文字内容
1. ⼤话Redis设计实现 “峰云就她了” - xiaorui.cc v 2016.6.5
2. redis协议 set name fengyun *3\r\n $3\r\n SET\r\n $4\r\n name\r\n $7\r\n fengyun\r\n 消息体数 get name *2\r\n $3\r\n GET\r\n $4\r\n name\r\n if OK:'>OK: +OK\r\n else:'>else: -1\r\n 字节数 if OK:'>OK: $7\r\n fengyun\r\n else:'>else: $-1\r\n
3. 数据结构 string (sds) list (deque) hash (hash table) set (intset + dict) zset (skip list + hash table)
4. String (sds) struct sdshdr { int len; int free; char buf[]; }; 获取字符串长度, 常数复杂度 增长时空间预分配 惰性回收 shshdr free 0 len 5 buf R E D I S \O
5. Hash table 通过渐进式rehash解决kv过多造成服务阻塞 流程: 给ht[1]分配⾄少2倍于ht[0]的空间 将ht[0]数据分批迁移到ht[1] 清空ht[0], 将ht[0]指针指向ht[1],ht[1]指针指向ht[0] 每次rehash 100个桶 渐进式rehash del \ find \ update in ht[0] and ht[1] insert in ht[1]
6. dict ht[O] type … ht rehashidx -1 dictht table size 4 sizemask 3 userd 2 null null dictEntry*[4] dictEntry 0 k2 1 2 dictEntry k3 v3 3 v2 null null ht[1] dictht table size 8 sizemask 7 userd 2 dictEntry*[8] … 4 5 … dictEntry kx vx dictEntry k6 v6 null null
7. RedisDB 内部结构 string object server “this is string” … db List object 0 1 2 3 … “t1” … redisDB dict “string” “list” watch “hash” … “set” … “null” Hash object dict expires “t2” name xiaorui age 18 Set object a b c d …
8. Redis event 事件类型 时间类型 (serverCron \ aof \ rdb \ expires) ⽂件类型 (client reuqest \ repl) 串⾏ epoll_create , epoll_ctl , epoll_wait 先⽂件类型, 再时间类型 (100ms cs)
9. event loop IO事件表 定时事件表 io事件 定时器 io事件 io事件 定时器 io事件 定时器
10. Redis Rdb RDB是Redis物化数据,保证宕机恢复的⼀个 ⼿段(会丢⼀部分最新数据) 每个Redis实例只会存⼀份rdb⽂件 可以通过Save以及BGSAVE 来调用 ⼆进制⽂件, lzf
11. RDB Format “redis rdb” “version” “Data” “Data” “Data” … EOF CHECKSUM “expireTime” “value type” “key” “value”
12. rdbSave 遍历每个db, 遍历每个db的dict, 获取每⼀个dictEntry 获取Key之后查询expire, 如过期, 就舍弃 将数据key, value, type, expiretime 等写⼊⽂件 计算checksum, 通过rename交换旧的RDB⽂件
13. rdbLoad 遍历RDB⽂件的每⼀条数据 读取key, value, expiretime等信息,插⼊dict字典以及expire字典 校验checksum
14. Redis Aof 类似于BINLOG机制, 可以做到不丢数据 how ? 每次数据操作都会调用flushAppendOnlyFile来刷新aof 每次操作都需要fsync, 前台线程阻塞 aof的内容就是redis标准协议 *3\r\n$5\r\nHMGET\r\n$5\r\nHENRY\r\n$10\r\nxiaorui.cc\r\n
15. Aof 意义 ? 将同⼀个key的反复操作,全部转为最后的值或multi集合 ( < 64) no-appendfsync-on-rewrite yes 正导出rdb快照的过程中,要不要停⽌同步fsync auto-aof-rewrite-min-size 3000mb aof⽂件,⾄少超过3000M时, 再执⾏aof重写 auto-aof-rewrite-percentage 80 aof⽂件⼤小比起上次重写时的⼤小,增长率80%时,执⾏aof重写
16. AOF ReWrite的实现: Fork⼀个⼦进程进⾏重写 打开⼀个tmp aof⽂件准备写⼊ 遍历每个DB 及DICT中的每对key value, 同时忽略过期键 以协议命令的⽅式写⼊tmp aof⽂件中 主进程中新的操作内容写到aof rewrite buffer中 ⼦进程重写完后, 向主进程发送信号, 主进程serverCron中将buffer的内容刷到新 的aof⽂件中 最后以rename的⽅式替换旧的aof⽂件
17. brpop/blpop client redisDB interpreter dict blocking_keys expires_keys brpop/blpop watch_keys … client fd blocking_keys xiaorui client fd hello … client fd
18. pubsub producer pubsub_channels channel_1 hello worker pub … “client_fd” “client_fd” “client_fd” redisServer pubsub_channels pubsub_patterns pubsub_patterns hello_* worker_* sub consumer
19. expire realize 懒惰清理 当发⽣读写的时候, 会检查是否过期 主动清理 定期轮询expire dict中的键是否过期 slave屏蔽懒惰和主动清理, 只等待psync .
20. expire realize Expires Dict 0 RedisDB expires_keys D 1 key value next 2 … blog time
21. watch multi watch 乐观锁 multi 原⼦性 流程 事务标记开始 命令⼊队 事务执⾏ ⽆rallback 、 ⽆Lock
22. command 客户端 事务状态? 是 exec,discard,watch, multi 否 push cmd queue return queued 否 是 if watch: do cas run command 返回执⾏结果
23. 主从同步 fork bgsave ? fork child block ? bgsave block ? psync vs fullsync 区别 ? run_id标识slave, 为⽑不适用fd ? offset replication backlog vs replication buffer 两个slave同时fullsync , 共用⼀个RDB及buffer
24. psync runid offset 连接主机 no backlog runid offset 返回 event + runid + offset 等待接收事件 bgsave Transfer RDB yes 返回 event 等待接收事件 传输backlog transfer repl buffer
25. 改进 transfer rdb, copy效率 断连 落地 sendfile 断点 内存 expires keyes, random check ⼆叉堆 ?
26. “Q & A” – 2016. 06. 05