Redis 持久化和管道
未雨绸缪一一持久化
Redis 的持久化机制为了保证 Redis 的数据不会因为故障而丢失,分别有两种机制:第一种是快照,第二种是 AOF 日志。快照是一次全量备份, AOF 日志是连续的增量备份。快照是内存数据的二进制序列化形式,在存储上非常紧凑,而 AOF 日志记录的是内存数据修改的指令记录文本。
快照原理
为了不阻塞线上的业务, Redis 就需要一边持久化,一边响应客户端的请求。Redis 使用操作系统的多进程 COW (Copy On Write )机制来实现快照持久化。
fork (多进程)
Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这是 Linux 操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的增长几乎没有明显变化。
子进程做数据持久化,不会修改现有的内存数据结构,只是对数据结构进行遍历读取,然后序列化写到碰盘中。但父进程必须持续服务客户端请求, 然后对内存数据结构进行不间断的修改。会使用操作系统的 cow 机制来进行数据段页面的分离。数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。内存持续增长不会超过原有数据内存的2倍大小。
AOF 原理
AOF 曰志存储的是 Redis 服务器的顺序指令序列, AOF 日志只记录对内存进行修改的指令记录。
Redis 会在收到客户端修改指令后,进行参数校验、逻辑处理,如果没问题,就立即将该指令文本存储到 AOF 曰志中,也就是说,先执行指令才将曰志存盘 这点 不同于 leveldb 、hbase 等存储引擎,它们都是先存储曰志再做逻辑处理。
AOF 重写
Redis 提供了 bgrewriteaof 指令用于对 AOF 曰志进行瘦身,其原理就是开辟一个子进程对内存进行遍历,转换成一系列 Redis 的操作指令,序列化到一个新的 AOF 曰志文件中。序列化完毕后再将操作期间发生的增量 AOF 日志追加到这个新的 AOF 日志文件中,追加完毕后就立即替代旧的 AOF 曰志文件。
fsync
Linux 的 glibc 提供了 fsync(int fd)函数可以将指定文件的内容强制从内核缓存 刷到磁盘。只要 Redis 进程实时调用 fsync 函数就可以保证 AOF 日志不丢失。在生产环境的服务器中, Redis 通常是每隔 1s 左右执行一次 fsync 操作,这个 1s 的周期是可以配置的。这是在数据安全性和性能之间做的一个折中,在保持高性能的同时,尽可能使数据少丢失。
运维
快照是通过开启子进程的方式进行的,它是一个比较耗资源的操作。 1. 遍历整个内存,大块写磁盘会加重系统负载。 2 . AOF 的 fsync 是一个耗时的 IO 操作,它会降低 Redis 性能,同时也会增加系统 IO 负担。
如果出现网络分区,从节点长期连不上主节点,就会出现数据不一致的问题,主节点一旦不小心宕机了,那么数据就会丢失,在生产环境下要实时监控工作,保证网络畅通或者能快速修复。还应该再增加一个从节点以降低网络分区的概率,只要有一个从节点数据同步正常, 数据不会轻易丢失。
Redis 4.0 混合持久化
为了解决:使用 rdb 来恢复内存状态,因为会丢失大量数据,重放 AOF 日志相对于使用 rdb 来说要慢很多,可以使用混合持久化。在 Redis 重启的时候,可以先加载 rdb 的内容, 然后再重放增量 AOF 日志, 就可以完全替代之前的 AOF 全量文件重放,重启效率变得很高。
雷厉风行一一管道
Redis 的消息交互
管道操作的本质:服务器根本没有任何区别对待,收到一条消息、 执行一条消息、回复 一条消息的正常流程。客户端通过对管道中的指令列表改变读写顺序就可以大幅节省 IO 时间。管道中指令越多,效果越好。
管道压力测试
redis -benchmark
redis-benchmark -t set -P 3 -q
P表示并行的请求数量
RedisQPS最高可达到约10w/s
深入理解管道本质
1 客户端进程调用 write 将消息写到操作系统内核为套接字分配的发送缓冲 send buffer中。
2 客户端操作系统内核将发送缓冲的内窑发送到网卡,网卡硬件将数据通过 “网际路由”送到服务器的网卡。
3 服务器操作系统内核将网卡的数据放到内核为套接字分配的接收缓冲 recv buffer中
4 服务器进程调用 read 从接收缓冲中取出消息进行处理。
5服务器进程调用 write 将响应消息写到内核为套接字分配的发送缓冲 send buffer中
6 服务器操作系统内核将发送缓冲的内容发送到网卡,网卡硬件将数据通过 “网际路由”送到客户端的网卡。
7 客户端操作系统内核将网卡的数据放到内核为套接字分配的接收缓冲 recv buffer中
8 客户端进程调用 read 从接收缓冲中取出消息返回给上层业务逻辑进行处理。
9 结束。
对于管道来说,连续的 write 操作不会耗时,之后第一个 read 操作会等待一个网络的来回开销,然后所有的响应消息就都已经送回到内核的读缓冲了,后续的 read 操作直接从缓冲中拿到结果,瞬间就返回了。