1 主从复制

redis.conf 配置 slaveof 启动成为 slave,只读。并且 slave 本身也可以接受别的 slave 的 PSYNC,减轻 master 负担。

  1. slave 尝试增量同步失败,发送 PSYNC 到 master
  2. master 收到 PSYNC,执行 BGSAVE,后台生成rdb文件
  3. master 收到新的写命令,记录到缓存
  4. master 发送 rdb文件 到 slave
  5. master 发送缓存中的写命令到 slave,并一直保持增量同步

1.1 主从延迟

  1. 从库设置 lave-serve-stale-data=yes 为 no,当从库同主机失去连接,或者复制正在进行时,会拒绝请求
  2. 外部监控复制偏移量,将流量引导到偏移量较小的从库

2 哨兵

配置 sentinel.conf 启动为哨兵,可以监控集群,并且自动故障转移。
如果 master 挂了,执行主从切换:

  1. sentinel 每秒向 instance 发送 PING 命令做心跳检测
  2. sentinel 将超时未响应的 master 标记为 sdown
  3. sentinel 每2秒向一个 channel 发布、接收拓扑结构
  4. 当 quorum 个 sentinel 确认 master 进入 sdown,该 master 标记为 odown,其中一个 sentinel 会通过 Raft 算法投票给自己成为本次故障转移的 leader
  5. leader sentinel 将 offset大的 slave 选为 master,执行主从切换,并广播 channel

3 集群模式

数据分片可以提高并发量,实现横向扩展。

3.1 客户端分片

随手记的 redis 集群于2012年搭建,当时 redis-cluster 还未推出,所以选择了 ShardJedis 实现客户端分片。
集群有4个节点用作JMS,14个节点用作缓存,这些都是 master,位于铜牛机房。
每一个 master 都有对应的一个 slave 在马驹桥机房,3个哨兵分别在铜牛、马驹桥、太和桥。
缺点:集群扩容后,会引起小范围的缓存击穿。

3.2 代理分片

Codis

3.3 服务端分片

配置 redis.conf 的 cluster-enabled yes 开启集群模式。

  1. 命令 cluster addslots 将 16384 个 slot 分配给各节点,分配结果记录在 bitmap
  2. Redis 收到请求,计算 slot = CRC16(key) mod 16384,根据 bitmap 找出 slot 对应节点,并告知 client
  3. 扩容、缩容,会引发数据迁移,过程对 client 透明

    3.3.1 为什么是 16384 个哈希槽

    为了表示 16384 个哈希槽,bitmap 大小为 16384/8 = 2048B = 2KB。
    集群内节点之间的心跳包需要携带完整的 bitmap,那么 2KB 刚刚好,再大就会打满宽带了。

4 慢日志

  1. 命令执行超过5毫秒记录慢日志
  2. CONFIG SET slowlog-log-slower-than 5000
  3. 只保留最近1000条慢日志
  4. CONFIG SET slowlog-max-len 1000
  5. 查询最近5条慢日志
  6. SLOWLOG get 5
  1. 执行时间复杂度高的命令。监控CPU使用率很高,但请求量不大。
  2. 存储大key。慢查询日志发现低复杂度的命令,比如 SET、DELETE。
  3. 集中过期
  4. 实例内存达到上限
  5. fork耗时严重
  6. 绑定CPU
  7. 开启AOF
  8. 开启Swap
  9. 网卡负载过高

4.1 常见的 O(n) // TODO

参考文献