主从复制针对读操作进行并发量和可用性的提高。一个节点作为主节点另外的节点作为从节点。主节点对数据有任何修改都会将修改同步到从节点上主节点和从节点上的数据是一致的。读取从节点就相当于读取主节点。所以可以将客户端的读请求路由到不同的节点以增加redis服务的并发量。配置建立复制可以通过修改配置文件来实现在结尾添加以下字段然后修改从节点的配置目录/dir重启后生效slaveof {masterHost} {masterPort}从节点后面也可以接从节点查看配置相关信息在客户端内执行info replication断开复制在从节点的客户端内执行slaveof no one断开与主节点的复制关系并且成为主节点并不会抛弃原有数据。还可以执行slaveof {newMasterIp} {newMasterPort}实现从节点更换主节点更换主节点的流程断开与旧主节点的复制关系然后与新主节点建立连接删除从节点当前所有数据从新主节点进行复制操作只读默认情况下从节点使用slave-read-onlyyes配置为只读模式由于主节点无法同步从节点的数据所以不建议将其关闭防止出现数据不一致的情况传输延迟主从节点一般部署到不同的机器上不可避免的会存在网络延迟可通过 repl-disable-tcp-nodelay配置项来选择是否开启tcp-nodelay 功能关闭降延迟增带宽主节点产生的命令数据无论大小都会即时发送给从节点。适用于要求强一致性或者同机房部署开启(默认)增延迟降带宽主节点会合并比较小的数据包从而节省带宽发送消息的时间间隔取决于Linux系统内核。适用于弱一致性或者跨机房部署拓扑结构一主一从最简单的主从复制结构从节点提供分散请求以及故障转移支持。当服务器写命令并发量较高且需要持久化时可以只在从节点上开启AOF这样既可以持久化数据又可以降低主节点的压力。当主节点重启时要主动拉取从节点的AOF文件以同步数据一主多从可以实现读写分离主节点专门处理写命令从节点负责处理读命令。当从节点过多时主节点每次修改都需要同步到很多的从节点增加了主节点的压力树形主从结构降低了主节点同步数据的压力但是增加了数据同步的延迟执行流程保存主节点的IP和端口号与主节点建立TCP连接发送ping命令验证是否能从主节点读写数据权限验证如果主节点设置了 requirepass 参数则需要密码验证从节点通过配置 masterauth 参数来设置密码两者相同则验证通过同步数据集首次建立连接时主节点将全部数据发送给从节点命令持续复制当从节点复制了主节点所有的数据之后针对修改命令主节点会持续将命令发送给从节点数据同步psync当主节点和从节点建立连接后从节点自动执行 PSYNC replicationid offset以从主节点拉取数据replicationid/replid (复制id)主节点生成的复制id从节点晋升称为主节点也会生成统一节点重启前后的replid不一致这里有两个参数一般情况下master-replid保存的是主节点的replid。当主从节点通信出现网络抖动从节点判断主节点挂了。此时从节点变为主节点并为自己生成一个replid保存到master-replid将原来主节点的replid保存到master-replid2。当后续网络恢复从节点可以根据master-replid2再次找到主节点主从节点只是网络通信异常主节点没有重启所以replid不改变offset (偏移量)主节点的offset处理完写命令后将写命令的字节长度累加到offset保存到master_repl_offset从节点的offset表示从节点的数据同步到哪了从节点接收到主节点的命令后就会将字长累加到offset保存到slave_repl_offset中。从节点每秒钟会给主节点上报自身的偏移量当主从偏移量一致表示主从数据同步全量复制当从节点首次与主节点进行数据同步或者主节点不方便进行部分复制时进行全量复制从节点发送psync命令给主节点进行数据同步由于是第一次进行复制从节点没有主节点的运行id和 偏移量所以发送psync ? -1主节点根据命令解析出要进行全量复制回复FULLRESYNC响应从节点对主节点的信息进行保存主节点执行bgsave进行RDB文件持久化主节点发送RDB文件给从节点从节点保存RDB数据到本地硬盘从节点清空自身原有的旧数据从节点加载RDB文件主节点将生成RDB生成阶段执行的写命令写入缓冲区从节点加载完RDB文件之后主节点将缓冲区内的命令发送给从节点。从节点直接在内存中执行这些命令执行bgrewrite操作 得到最近的AOF文件无磁盘复制默认情况下是主节点将RDB文件保存到磁盘中然后再把磁盘上的RDB文件通过网络发送给从节点。无磁盘复制下主节点不会生成RDB文件到磁盘中而是直接把生成的RDB数据通过网络发送给从节点。这样就节省了一系列IO操作的开销部分复制从节点之前连接过主节点并且从节点已经保存了绝大部分数据主从节点之间出现网络中断时如果超过repl-timeout主节点会认为从节点故障并终止连接主从连接断开的期间主节点正常接收数据并将这些数据暂存到复制积压缓冲区中主从节点网络恢复从节点将之前保存的replicationId和offset作为psync的参数发送给主节点请求进行部分复制replicationId与主节点相同则进行部分复制否则进行全量复制根据offset判断从节点未同步数据的进度是否在复制积压缓冲区内如果在则进行部分复制否则进行全量复制根据offset去积压缓冲区内查找合适的数据并响应CONTINUE给从节点主节点将需要进行同步的数据发送给从节点复制积压缓冲区复制积压缓冲区是保存在主节点上一个固定长度的队列当主节点连接从节点时创建主节点不仅会将命令发送给从节点还会写入复制积压缓冲区实时复制主从节点通过TCP长连接的方式源源不断的将指令同步给从节点从节点会根据这些请求来同时修改自身的数据从而保持主从节点的数据一致性。这样的长连接通过心跳包维持连接状态主节点每隔10s对从节点发送ping命令判断从节点的存活性和连接状态从节点每隔1s向主节点上报自身当前的复制偏移量如果主节点发现从节点通信延迟超过repl-timeout则判定从节点下线。此时断开复制客户端连接从节点恢复连接之后心跳机制继续进行哨兵哨兵节点单独的redis-sentinel进程不负责存储数据只是对其他redis-server进程起到监控的效果。当主节点故障时哨兵节点能够自动完成故障发现和故障转移并通知应用方以实现高可用原理执行流程运行多个redis-sentinel进程这若干个哨兵进程会与主从节点建立TCP长连接定期发送心跳包来判断节点是否正常运行哨兵节点发现主节点故障(主观下线)并与其他哨兵节点达成共识(客观下线)。主要为了防止网络抖动导致的心跳包丢失主观下线单个哨兵节点判断主节点宕机客观下线哨兵集群中半数以上节点认为主节点下线哨兵节点之间通过Raft算法选出一个节点负责故障转移工作故障转移从从节点中选择一个作为主节点(执行slaveof no one)其他节点同步到新的主节点最后通知客户端告知新的主节点是谁后续更新操作会针对新的主节点进行操作核心功能监控哨兵节点定期检测主从节点是否可用故障转移实现从节点晋升为主节点并更新主从关系通知哨兵节点将故障转移结果通知给应用方新主节点选取原则优先级每个redis数据节点都会在配置文件中设置一个优先级优先级最高的从节点成为主节点offset从主节点上同步数据最多的从节点runidrunid是为每个redis节点生成随机生成的一串数字小的成为主节点配置修改sentinel.conf文件bind 0.0.0.0 port 26379 sentinel monitor 主节点名 主节点ip 主节点端口 法定票数 sentinel down-after-milliseconds 主节点名 毫秒数sentinel monitor 主节点名 主节点ip 主节点端口 法定票数主节点名哨兵内部自己起的名字法定票数为防止哨兵节点自己出现网络问题导致误判主节点宕机使用投票的方式来确定主节点是否宕机当多个哨兵都认为主节点宕机票数 法定票数才正式判定主节点挂了集群引入多台redis服务器每台服务器存储一部分数据以此增加整体内存容量数据分片算法解决数据路由到哪个数据分片的问题哈希求余将集群中的分片从0开始编号针对给定的key先计算哈希值MD5算法然后对集群中master节点的个数进行求余根据余数来判断路由到哪个数据分片优点简单高效数据分配均匀问题当集群需要扩容或者缩容时原有求余方式改变大量的key需要重新映射涉及到大量的数据搬运一致性哈希算法将0-2^32-1个数据空间映射到一个圆环上圆环顺时针增长每个分片管理一段数字并规定管理区域为某个分片起点顺时针到下一个分片的起点。假定有一个key计算出的哈希值为H根据H在圆环中对应的位置计算出映射到的数据分片假设现在要扩容为四台机器原有分片的位置不动只需要新安排一个分片即可这里将二号分片的一部分分给的新的分片搬运数据时只需要搬运二号分片的一部分数据优缺点解决了哈希求余算法造成的扩容时大量数据搬运的问题但是有引入了数据无法均匀映射的新问题哈希槽分区算法redis采用的分区算法解决了搬运成本高和数据分配不均匀的问题。将整个哈希值映射到16384个槽位上将这些槽位均匀分配给每个分片每个分片记录自己所持有的分片。每个key先对16384取余然后根据余数判断路由到哪个分片。每个分片都持有一个16384bit的位图上面标记了对应分片所持有哪些槽位hash_slot crc16(key) % 16384分片规则可以灵活指定每个数据分片所持有的槽数可以是连续的也可以是离散的。当进行扩容时可以把每个分片所持有的槽位各拿出一点分给新的槽位实际使用时只需要设置每个分片应持有多少槽位Redis会自动完成槽位分配以及对应key的搬运工作配置集群redis-cli --cluster create 各个节点的地址 --cluster-replicas 每个主节点的从节点个数故障转移当集群中某个分片的主节点宕机集群能够自动对问题进行处理故障判定集群中的所有节点都会周期性的使用心跳包进行通信心跳包中包含了集群的一些配置信息每个节点每秒钟都会给一些随机的节点发送ping包。当节点A给节点B发送ping包B不能如期回应时A首先会尝试重置和B的TCP连接。如果还连接失败A就会把B设置为PFAIL(主观下线)状态当A判定B为PFAIL之后会通过redis内置的Gossip协议和其他节点确认B的状态每个节点都会维护一张自己的下线列表此时如果超过一半的主节点都认为B下线那么A就将B标记为FAIL(客观下线)当某个分片的所有主从节点全部宕机或者某个分片的主节点宕机但是没有从节点那么整个集群都会宕机故障转移主节点宕机时将从节点提升为主节点继续给整个redis集群提供支持只有从节点和主节点之间通信间隔在一定阈值内的从节点才能参与竞选主节点主要是防止主从节点的数据差异过大参与竞选的节点会先休眠一段时间休眠时间 500ms 基础时间 [0, 500ms] 随机 时间 排名 * 1000msoffset越大排名越小先苏醒的节点会通知其他节点对其进行投票只有主节点才能投票当收到的票数超过主节点数的一半时这个节点就会晋升为主节点执行slaveof no one。数据分片内的其他节点更改主节点新的主节点向集群同步信息以便其他节点更新自己保存的集群结构信息集群扩容将新的主节点加入集群加入后自动成为主节点redis-cli --cluster add-node 新节点的地址 集群中的任意节点地址重新分配 slots搬运key时大部分key不需要搬运。这些不需要搬运的key可以正常访问需要搬运的key无法访问redis-cli --cluster reshard 集群中的任意节点地址给新的主节点添加从节点redis-cli --cluster add-node 新节点的地址 集群中的任意节点地址 --cluster-slave --cluster-master-id 主节点id访问集群JedisClusterSetHostAndPortnodesnewHashSet();nodes.add(newHostAndPort(ip,port));try(JedisClusterjedisClusternewJedisCluster(nodes)){...}Spring更改配置文件spring:redis:cluster:nodes:-ip:port...lettuce:cluster:refresh:adaptive:period:lettuce配置, 目的是自动刷新集群的拓扑结构. 当集群中有节点宕机/加入新节点之后, 代码能够自动感知到集群的变化