redis io模型

ps,读redi小册

redis的几个特性

  单线程:没错redis是单线程的。
  快:因为所有数据都在内存里面。
  单线程如何高效处理大并发请求:多路复用。非阻塞io。其实现和java nio,netty都是基于多路复用实现的,通过select函数不断轮训请求,然后判断请求类型,就行不同操作,比如连接请求,读请求,写请求等(具体实现请看我的博客关于java nio的一章)
  Redis 会将每个客户端套接字都关联一个指令队列。客户端的指令通过队列来排队进行顺序处理,先到先服务。
  Redis 同样也会为每个客户端套接字关联一个响应队列。Redis 服务器通过响应队列来将指令的返回结果回复给客户端.
  Redis 的定时任务会记录在一个称为最小堆的数据结构中。这个堆中,最快要执行的任务排在堆的最上方。在每个循环周期,Redis 都会将最小堆里面已经到点的任务立即进行处理。处理完毕后,将最快要执行的任务还需要的时间记录下来,这个时间就是select系统调用的timeout参数。因为 Redis 知道未来timeout时间内,没有其它定时任务需要处理,所以可以安心睡眠timeout的时间。

Redis 通信协议

  Redis通信协议是一个文本协议RESP。优势是实现简单,解析性能好。
Redis协议将所传输的数据分为5个最小类型。单元结束统一加\r\n:

单行字符串 以 + 符号开头。
多行字符串 以 $ 符号开头,后跟字符串长度。
整数值 以 : 符号开头,后跟整数的字符串形式。
错误消息 以 - 符号开头。
数组 以 * 号开头,后跟数组的长度。
空串 用多行字符串表示,长度填 0。

  set author codehole会被序列化成下面的字符串。

*3
$3
set
$6
author
$8
codehole

redis持久化

  redis持久化有2个机制。一个是RDB(快照:全量备份,内存数据的2进制序列化形式),一个是AOF(增量备份,记录内存数据的修改指令文本)。
  快照原理:内存快照要求redis必须进行文件io操作,而这个操作是无法阻塞的。如果单线程在服务线上请求还要进行文件io操作,那么性能会变得很差,如果不阻塞线上的业务,便持久化边相应请求,持久化同时,内存数据结构还在变化,这怎么玩呢?redis采用多进程来进行处理。redis在持久化时fork一个子进程,快照持久化交给子进程来处理,父进程继续处理客户端请求。子进程刚产生时和父进程共享内存里面的代码段和数据段。所以不会导致内存突然变大。子进程做持久化,不会修改这个内存数据,只会对其结构不断遍历读取,然后序列化之后写到磁盘,但是父进程则是不断相应客户端请求,然后对内存数据不断修改。然后使用操作系统的写时复制机制,在内存里面,数据是一页一页的,当父进程修改内存数据时会把这个数据所在的那一页辅助一份出来,进行修改,等子进程顺利遍历完了,在替换合并。
  AOF原理:就是一个日志存储着redis创建后的所有修改指令。redis是先执行指令在存日志的。同时redis长期运行会导致日志庞大,重启时间长,导致redis长期无法对外提供服务。所以需要瘦身,redis提供了bgrewriteaof 指令对aof日志瘦身,其原理是开辟一个子进程对内存进行遍历转换生成一系列的redis操作指令,序列化到一个新的aof日志文件里面,序列化后,再讲操作期间发生的增量aof日志加到新的aof日志文件里面,追加完毕即可代替旧的aof日志。aof日志以文件方式存在的,当程序对aof日志文件进行写操作时,实际上是将内容写到了内核为文件描述符分配的内存缓存,但是如果系统宕机了aof日志没来得及刷到磁盘,该如何。linux提供了fsync函数可以将日志文件强刷到磁盘。所以redis一般每隔一秒执行一次fsunc操作,使得尽可能减少数据丢失。
  快照是通过开启子进程的方式进行的,它是一个比较耗资源的操作。

  遍历整个内存,大块写磁盘会加重系统负载
  AOF 的 fsync 是一个耗时的 IO 操作,它会降低 Redis 性能,同时也会增加系统 IO 负担
  所以通常 Redis 的主节点是不会进行持久化操作,持久化操作主要在从节点进行。从节点是备份节点,没有来自客户端请求的压力,它的操作系统资源往往比较充沛。

  但是如果出现网络分区,从节点长期连不上主节点,就会出现数据不一致的问题,特别是在网络分区出现的情况下又不小心主节点宕机了,那么数据就会丢失,所以在生产环境要做好实时监控工作,保证网络畅通或者能快速修复。另外还应该再增加一个从节点以降低网络分区的概率,只要有一个从节点数据同步正常,数据也就不会轻易丢失。

混合持久化

  redis4.0之后将rdb文件的内容和增量aof文件存在一起,这里的aof日志则是自持久化到持久化结束的增量aof文件.这样redis重启的时候则是先加载rdb文件,在加载aof日志文件。