Redis相关文章
Redis主从模式
主从模式原理
顾名思义,将集群区分成一个主节点多个从节点,读写分离架构,主节点负责写入数据也可以读数据,从节点同步主节点的数据写入做备份,同时支持读操作。
从节点如何处理key的过期
- 根本原因
- 从节点不会让 key 过期,而是等待主节点让 key 过期。当主节点让一个key到期时,会下发del命令并传输到所有的从节点。
- Redis的两种删除策略
- 惰性删除:当数据过期后,并不会马上删除。而是等到有请求访问时,对数据检查,如果数据过期,则删除数据。
- 定期删除:每隔一段时间,默认100ms,Redis会随机挑选一定数量的Key,检查是否过期,并将过期的数据删除
- 当读数据请求打到主节点访问删除数据时,主节点会触发惰性删除。但当请求达到从节点则可能读到旧数据,一般有两种原因。
- Redis3.2之前版本,读从库并不会判断数据是否过期。
- 解决方案:可以将版本升级到3.2版本后。
- 跟过期时间的设置方式有关系,我们一般采用 EXPIRE key ttl命令,表示从执行命令那个时刻开始,往后延长ttl 时间。主从复制是异步行为,必然会出现延迟情况,所以ttl时间的开始时间会出现不一致情况。
- 解决方案:采用Redis的另外两个命令,EXPIREAT key timestam 和 PEXPIREAT key timestamp避免由主从同步命令导致的开始时间延迟问题。
Redis replication
Redis复制过程
- 重要概念:
- 服务器的唯一id:每个 Redis 服务器在运行期间都有自己的run ID,run ID在服务器启动的时候自动生成。
- 复制偏移量 offset:主服务器和从服务器都会维护一个复制偏移量
- Redis从2.8以后使用PSYNC命令代替SYNC命令来执行复制时的同步操作
- slave刚上线的复制过程
- 设置主服务器的ip+端口
- 建立套接字链接
- 发送ping命令
- 验证身份
- 向主服务器发送Slave的端口
- 同步
- PSYNC命令具有完整同步和增量同步
- 全量同步
- 用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点
- Slave向Master发送PSYNC请求
- 主服务器开启后台保护进程创建RDB快照并发送给从服务器,同时将产生快照阶段产生的新的操作命令存储到缓存区
- Master向Slave同步存储缓存区的操作命令
- 增量同步
- 用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。需要注意的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制。
- Redis 主库接收到写操作的命令,首先会写入replication buffer(主要用于主从数据传输的数据缓冲),同时也会把这些操作命令也写入repl_backlog_buffer这个缓冲区。
- 如何主从断开了,当然对应的replication buffer也就没有了。这时候就依赖repl_backlog_buffer进行数据的增量同步了。repl_backlog_buffer是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置。
- 使用PSYNC {offset} {replication id}实现
- Master每执行一个写命令就会向Slave发送相同的写命令。然后Slave接收并执行
新增从库的过程
- 从库使用PSYNC请求同步,首次链接不会指定replcationid和offset
- master节点收到命令判断为全量同步后就会将自己的replcationid和offset告知slave,回复命令full resync {runId} {offset}。同时,master会执行bgsave命令来生成rdb文件,期间的所有写命令将被写入缓冲区。
- master bgsave执行完毕,向slave发送rdb文件。rdb文件发送完毕后,开始向slave发送缓冲区中的写命令。
- slave收到rdb文件,丢弃所有旧数据,开始载入rdb文件。
- rdb文件同步结束之后,slave执行从master缓冲区发送过来的所有写命令。
- 此后 master 每执行一个写命令,就向slave发送相同的写命令。
主从模式数据丢失问题
- 无法严格避免数据丢失问题,只能尽可能减轻
- redis配置文件中有两个配置
min-slaves-to-write 1min-slaves-max-lag 10
- 其中,min-slaves-to-write默认情况下是0,min-slaves-max-lag默认情况下是10。
- 上述参数表示至少有1个salve的与master的同步复制延迟不能超过10s,一旦所有的slave复制和同步的延迟达到了10s,那么此时master就不会接受任何请求,系统故障。
- 通过降低min-slaves-max-lag参数的值,可以避免在发生故障时大量的数据丢失,一旦发现延迟超过了该值就不会往master中写入数据发生故障。
- 应对方案:
- 一定场景下用主写主读策略
- 保证主从网络相同机房顺畅,监控从节点如果与主节点差距过大将该剔出集群,不在接受读请求。
Redis哨兵模式
哨兵模式原理
- Redis 哨兵模式(Sentinel)就是一个自动地监控处理 redis 间故障节点转移工作的一个程序,准确来说,Sentinel 其实是一个 redis 服务端程序,只不过运行在特殊的模式下,不提供数据存储服务,只进行普通 redis 节点监控管理。
- 通过不断发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
- 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。配置也会修改
- 一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式
- 故障切换:假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行故障转移过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行故障切换操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。
- 在哨兵sentinel机制中,可以解决redis高可用问题,即当master故障后可以自动将slave提升为master,从而可以保证redis服务的正常使用,但是无法解决redis单机写入的瓶颈问题,即单机redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素。
哨兵工作模式
- 每个Sentinel以每秒钟一次的频率向mster、slave、其他sentinel发送ping命令
- 如果一个实例(instance)距离最后一次有效回复PING命令的时间超过 own-after-milliseconds 选项所指定的值,则这个实例会被Sentinel标记为主观下线。
- 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
- 当有足够数量的Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态,则Master会被标记为客观下线。
- 在一般情况下,每个Sentinel 会以每10秒一次的频率向它已知的所有Master,Slave发送 INFO 命令。
- 当Master被Sentinel标记为客观下线时,Sentinel 向下线的 Master 的所有Slave发送 INFO命令的频率会从10秒一次改为每秒一次。
- 若没有足够数量的Sentinel同意Master已经下线,Master的客观下线状态就会被移除。 若 Master重新向Sentinel 的PING命令返回有效回复,Master的主观下线状态就会被移除。
主备切换过程
- 假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。
- 当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行故障切换操作。
- 切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。
Redis集群模式
Redis cluster集群原理
- 哨兵模式只解决了redis高可用问题,及时将挂掉了master换掉,但无法解决redis单机写入的瓶颈问题
- 由多个Redis服务器组成的分布式网络服务集群;至少6台redis服务器3主3从
- 集群之中有多个Master主节点,每一个主节点都可读可写;
- 节点之间会互相通信,两两相连;
- Redis集群无中心节点。可以理解成多个哨兵模式,基于Raft算法管理集群
数据分片机制
- Redis的分布式解决方案,分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集
- 采用hash槽分区
- 所有的键根据hash函数映射到0-16384整数槽内,根据公式:slot = CRC16(ey) & 16384,每个节点负责维护一部分槽一级槽所映射的键值数据
- Redis虚拟槽分区的特点
- 解耦数据和节点之间的关系,简化了节点扩容和收缩难度。
- 节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据
- 支持节点、槽和键之间的映射查询,用于数据路由,在线集群伸缩等场景。
- 如果集群中新增节点需要从已有节点删除一些hash slot给新节点,同理删除节点也应该将删除节点上的hash slot移动到现有的节点