Redis是非常常用的KV数据库, 使用内存以及HashMap进行存储的特点带来了高效的查询. 本文将围绕Redis的常见开发使用场景, 阐述在Redis集群中各个节点是如何进行数据同步, 每个节点如何进行持久化以及在长期使用中如何对数据进行更新和淘汰.
如果对Redis有更多的兴趣, 可以查看我的技术博客: https://dingyuqi.com
Redis对于集群的部署支持三种模式: 主从, 哨兵和分片. 在正式的生产环境中一般会采用一主一从+哨兵的模式来解决高可用和高并发读的问题, 但是这种模式无法解决高并发写的问题. 高并发写可以借助于分片集群.
由于单个服务器的并发数量存在上限, 我们可以使用主从模式实现读写分离, 以此提高读写的效率. 通常主节点进行写操作, 从节点进行读操作.
在主从模式中主节点和从节点之间存在数据同步的问题, 目前Redis支持两种不同的同步方式: 全量同步和增量同步.
在了解全量同步的流程之前, 我们先熟悉几个Redis内部的定义:
下面是全量同步的流程时序图:
::: tip
步骤9实际上记录了步骤6到步骤10之间master收到的所有命令.
:::
在了解过全量同步后, 再来对比看一下增量同步的流程. 增量同步主要用于slave节点重启后或者后期出现数据变化的场景.
哨兵模式主要用来实现主从集群的自动恢复. 主要的功能有三个:
用心跳机制, 每隔15s发一次ping
确保节点的状态保持活跃. 节点下线分为两种情况:
quorum
.当Redis中的master节点宕机后, 会使用类似Raft的投票机制来进行选主. 选主的标准大致基于以下几个:
分片集群主要用于应对海量的数据, 有以下几个特点:
ping
检测健康那么如果不同的master存储的是不同的数据, Redis又是如何决定每一个数据应当存储到哪个节点上呢? Redis使用的是插槽, 一共有16384个插槽. 大致过程为: 首先根据key的有效部分计算Hash值, 再与16384取余决定其插槽位置, 再去取数据.
至于为什么插槽的数量定为16384, 其作者有做过正式答复:
why redis-cluster use 16384 slots?
- Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to
update an old config. This means they contain the slots configuration
for a node, in raw form, that uses 2k of space with16k slots, but
would use a prohibitive 8k of space using 65k slots.- At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs. So 16k
was in the right range to ensure enough slots per master with a max of
1000 maters, but a small enough number to propagate the slot
configuration as a raw bitmap easily. Note that in small clusters the
bitmap would be hard to compress because when N is small the bitmap
would have slots/N bits set that is a large percentage of bits set.
Redis一共提供两种持久化的策略: RDB和AOF, 现在我们分别来看一下这两种策略的优缺点.
RDB是基于快照的全量备份, 周期性地把全量的数据写入快照文件.
优点
缺点
AOF策略是对内存修改进行指令记录.
优点
缺点
随着Redis集群的使用时间不断增加, 里面保存的KV越来越多, 此时就会面临内存不够用的问题. Redis为此提供了过期和淘汰策略来管理海量的数据.
顾名思义就是每一个数据在Redis当中都有一个"寿命", 当过了设定的有效时间该数据就会变为无效的数据, 不再支持读写. Redis提供两种过期策略:
h2
.还有一些额外的场景下Redis会对过期的key进行统一的处理:
序号 | 名称 | 定义 |
---|---|---|
1 | volatile_LRU | 设置了过期时间的key中执行LRU算法 |
2 | allkeys-LRU | 在所有key中执行LRU算法 |
3 | volatile_LFU | 设置了过期时间的key中执行LFU算法 |
4 | allkeys-LFU | 在所有key中执行LFU算法(删除最不常用的key) |
5 | volatile_random | 设置了过期时间的key中执行随机删除 |
6 | allkeys-random | 在所有key中执行随机删除 |
7 | volatile_TTL | 删除过期时间最早的key |
8 | noeviction | 不进行key的删除(默认配置, 但是正常开发中不会使用该模式) |