为自己打响Redis的进阶之战
Redis发布订阅模式
发布者将消息发布到对应的频道上,消息订阅者只要订阅了对应的频道,那么只要发布者发布了消息,订阅者就会收到该订阅。
简单使用参考:
- 消息订阅者订阅频道
- 消息发布者发布消息
- 消息订阅者接收到消息
pipelining
redis支持管道(pipelining)技术,简单的理解就是,将多次命令请求合并为一次请求发送,减少IO,减少访问次数。
简单的一个测试参考下图:我们利用pipelining将多条命令一次发送给redis。
nc 是一个工具,它可以用来测试TCP连接是否通畅
Redis的事务
Redis支持事务,可以将一系列命令放入一个事务中进行,这一系列命令是有序的会原子性的执行,但Redis不支持回滚(保持简单快速的设计理念),这也意味着在一次事务中的不同命令,可能存在失败
- 事务的一些命令及使用
- watch监控的key,被其他的人改动过后,Redis将放弃本次事务的执行。
- 每个事务都会有自己的一个队列,按入队顺序执行。
Redis支持集成module
Redis可以集成第三方的一些模块,具体可查看redis.io中的modules菜单下的具体可集成模块。一般的步骤为:
- 在redis.io的module中找到要集成的模块
- 在Redis中下载对应的模块
- make该模块
- 启动redis时loadmodule redis-server --loadmodule 具体的地址
- 然后就可以自Redis客户端使用集成进的模块内容
Redis做缓存
缓存的特点:缓存中的数据不是全量的数据,一般只存放热点数据,数据会随着业务的变化而变化
Redis要做缓存要面对两个问题:第一,数据的有限期;第二,分配的内存大小,分配的内存满了,应该使用什么策略来淘汰过期的数据。
- 对于有效期问题,Redis支持多种形式的设置key的有效期,可设置key的存活时间、到什么时间过期等。对于内存问题可以通过修改Redis的配置文件来修改内存的大小,同时也可设置具体的淘汰策略,常用的有LRU(最近最久未使用 时间层面)。
Redis做缓存的一些常见概念
击穿
当客户端请求数据时,它所需要的key过期了,没有命中redis缓存,那么它就需要到数据库里直接请求,我们称这种现象为击穿。
面对击穿这种情况,通常我们会这样处理:当客户端没有从redis中拿到数据时,它会进行第二次访问redis,使用setnx命令(该命令只有在key不存在时才能执行成功,这次操作相当于加锁),执行完后会去数据库查出所需的key然后将其写到redis中,这样当其他客户端在访问相同的key时,要么第一个客户端已经从数据库将值写入redis,它可以直接返回,要么拿不到锁,等待直到第一个客户端将值取回放入redis中,在高并发场景下,可以减少数据库的压力。当然这样还有问题,假如第一个客户出问题了,那么其他人还是会死锁等待,这时我们可以设置锁的过期时间,这样就可以保证其他人不会死锁,还有一种情况是第一个客户没有出问题,只是数据库压力太大,它还没有拿到数据而已,为了保证程序的健壮性,这时我们可以引入多线程,专门有一个线程监控访问数据库的客户,当客户挂掉,那么只需要等待过期时间其他人就可以解除死锁,如果是阻塞在数据库那,监控线程可以延长过期时间,这也是redis实现分布式锁的思想。
穿透
客户端请求的数据不是我们系统中存在的数据,即redis缓存和数据库都不存在,当请求到达时会先到redis,然后到数据库,这个过程它并不能得到数据,这种想象称为穿透。
Redis做缓存时可以集成布隆过滤器来防止缓存穿透。
雪崩
在某一个时刻,redis中的缓存数据大量失效,有大批的请求直接进入数据库,这种现象称为雪崩。
对于雪崩,可能出现的原因有两个,第一,我们设置的过期时间有问题,这是我们可以通过设置随机过期时间来解决;第二,在某一个时间点,系统要求缓存的数据都失效,需要重新从数据库加载数据 到缓存,这时我们可以完全依赖击穿的方法,或者我们已经明白在某一个时间点缓存会失效,我们可以在客户端那做判断,如果到了那个时间点,可以随机的让访问线程睡眠一会,减少redis的压力,让几个客户端连进来做数据跟新。
Redis做数据库
数据库的特点:数据要持久化,保证数据的完整性,Redis要做数据库的话就要保证数据的持久化,Redis的持久化方式有两种 RDB和AOF。
任何数据库在存储层都有两个东西:第一,快照或者说副本;第二,日志。
RDB
RDB是快照的实现方式,在某个时间节点的时候做一个现有数据的快照,然后将其持久化到磁盘中,关键点就是怎么做这个快照,而且还需要明白的是在做快照的时候我们的数据库还要向外提供服务,同时要提供服务,要做快照,那么怎么保证数据的时点性(这个概念这么理解:当我们在8点的时候要做快照(肯定需要一定的时间),同时我们还对外提供着服务,那么怎么保证快照就是我们在8点这个时刻的数据),Redis是这样做的:
采用fork()子进程的方式加copyonwrite机制保证数据的时点性和对外服务。在Linux里fork子进程的代价极低,花费的时间极短,占据的内存也很小,因为它只是做虚拟内存地址的复制,刚开始两进程的虚拟内存地址指向一块真正的内存地址,真正的内存数据不会改变,各自进程做数据改变时采用copyonwrite机制,谁做数据改变,那么会在内存中新增出一个数据,将其原来的指针指向该数据,另一个进程不动,操作只是造成指针的移动,代价极小,而且不是进程里的所有数据都会有改变。
当用Redis做数据库时,我们一般通过配置文件的方式设定具体的持久化计划,当到点时,Redis进程会fork出一个子进程,让子进程去做持久化的过程,而它自己继续为客户提供服务,这种方式其实是通过调用bgsave命令来完成,我们也可以在客户端显示的调用bgsave命令;在Redis里还有save命令,这种命令的调用是阻塞式的,做持久化的过程不能继续为客户端提供服务,一般很少用。
Redis的RDB方式的优缺点:优点::这种方式的持久化数据以二进制的形式存储,数据恢复的速度非常快。缺点::第一,持久化的文件只有一个dump.db,不支持拉链(按时间分类存储多个备份文件);第二,出现问题,丢失的数据比较多,可能丢失一整个 间隔的 备份时间点的数据。
- 配置文件参数
save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存
save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存
save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存
AOF
AOF是日志的实现方式,对Redis的操作命令都会以日志的形式持久化到文件中。这种追加日志形式的持久化使得Redis做数据恢复时丢失的数据变少,但它也存在着一些问题,我们一般会做出一些改进,下面我依次介绍存在的问题及改进。
-
问题:如果我们不做任何改进的追加日志,那么日志终有一天会变成一个庞然大物,当我们做恢复时内存可能溢出。
-
改进方法:重写策略,重写的实际做法分4.0之前和之后,二者的做法不同。4.0之前,利用CPU做命令的优化,删除抵消的命令、合并重复的命令来减小aof文件的大小,最终生成一个纯指令形式的文件,4.0之后的重写会将老数据以RDB的方式(占据空间小)持久化到aof文件中,新的增量数据以命令的方式继续追加到该aof文件中,该文件是一个快照和日志的混合体,结合了RDB的快速和AOF的数据丢失少的特点。
-
如果Redis中开启了AOF,当恢复数据时那么只会用AOF方式做恢复,因为其包含了RDB的全量和AOF日志的增量。
-
AOF方式的持久化也是通过配置文件的形式来完成。
- 配置文件参数 什么时候触发真正写磁盘 no:不调用,等待操作系统来清空缓冲区。很快。 always: 每次更新数据都写入仅增日志文件。慢,但是最安全。 everysec: 每秒调用一次。折中。 什么实用触发重写 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
本文地址:https://blog.csdn.net/IT_0008/article/details/106426741