1、引言
Redis = Remote Dictionary Server,即远程字典服务。是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。本文主要透彻讲解redis集群、redis事务、redis分布式锁、redis缓存问题、持久化机制等几个核心技术点。
2、Redis集群
在生产环境中,使用 Redis 通常采用集群模式,因为单机版 Redis 稳定性可靠性较低,而且存储空间有限。
Redis 支持三种集群模式:
- 主从复制
- 哨兵模式
- Cluster 模式
2.1 主从复制
主从复制模式,有一个主节点(master)、多个从节点(slave),从而实现读写分离,主机负责写请求,从机负责读请求,以减轻主机压力。
1)主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器;前者称为主节点(master),后者称为从节点(slave);
2)数据的复制是单向的,只能由主节点到从节点;
3)默认情况下,每台Redis服务器都是主节点,且每一个主节点可以有多个从节点(或者没有),但一个从节点只有一个主;
主从复制的作用主要包括:
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式;
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余;
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在读多写少的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量;
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
2.1.1 工作原理
- 从数据库启动成功后,连接主数据库,发送 SYNC 命令;
- 主数据库接收到 SYNC 命令后,开始执行 BGSAVE 命令生成 RDB 文件并使用缓冲区记录此后执行的所有写命令;
- 主数据库 BGSAVE 执行完后,向所有从数据库发送快照文件,并在发送期间继续记录被执行的写命令;
- 从数据库收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主数据库快照发送完毕后开始向从数据库发送缓冲区中的写命令;
- 从数据库完成对快照的载入,开始接收命令请求,并执行来自主数据库缓冲区的写命令;(从数据库初始化完成)
- 主数据库每执行一个写命令就会向从数据库发送相同的写命令,从数据库接收并执行收到的写命令(从数据库初始化完成后的操作)
- 出现断开重连后,2.8之后的版本会将断线期间的命令传给重数据库,增量复制。
- 主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。Redis 的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
2.1.2 优缺点
优点:
- 支持主从复制,Master会自动将数据同步到Slave,可以进行读写分离;
- Slave 同样可以接受其它 Slaves 的连接和同步请求,这样可以有效的分载 Master 的同步压力;
- Master Server 是以非阻塞的方式为 Slaves 提供服务,所以在 Master-Slave 同步期间,客户端仍然可以提交查询或修改请求;
缺点:
- 主从不具备容错和恢复能力,一旦主机挂了,那么整个集群处理可读状态,无法处理写请求,会丢失数据;
- 主机宕机后无法自动恢复,只能人工手动恢复;
- 集群存储容量有限,容量上线就是主库的内存的大小,无法存储更多内容;
2.2 哨兵模式(Sentinel)
哨兵的核心功能是主节点的自动故障转移,哨兵起到监控的作用,一旦Redis集群出现问题了,哨兵会立即做出相应动作,应对异常情况。
2.2.1 哨兵功能
监控(Monitoring):每个哨兵节点会不断地检查主节点和从节点是否运作正常。
自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
通知(Notification):哨兵可以将故障转移的结果发送给客户端。
2.2.2 下线判断
Redis 下线分为主观下线和客观下线两种:
- 主观下线:单台哨兵认为主库处于不可用状态;每个Sentinel节点,每隔1秒会对数据节点发送ping命令做心跳检测,当这些数据节点超过down-after-milliseconds没有进行有效回复时,Sentinel节点会对该节点做失败判定,这个行为叫做主观下线。
- 客观下线:整个哨兵集群半数以上的哨兵都认为主库处于不可用状态,那这个判定就是客观的,叫做客观下线。
哨兵集群中任意一台服务器判断主库不可用时,此时会发送命令给哨兵集群中的其他服务器确认,其他服务器收到命令后会确认主库的状态,如果不可用,返回 YES,可用则返回 NO,当有半数的服务器都返回 YES,说明主库真的不可用,此时需要重新选举。
2.2.3 主库选举
当哨兵集群判定主库下线了,此时需要重新选举出一个新的主库对外提供服务。那么该由哪个哨兵来完成这个新库选举和切换的动作呢?
注意:这里不能让每个哨兵都去选举,可能会出现每个哨兵选举出的新主库都不同,这样就没法判定,所以需要派出一个代表;
哨兵代表选择
哨兵的选举机制其实很简单,就是一个Raft选举算法:选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举。大致思路如下:
1)每个Sentinel节点都有资格成为领导者,当它主观认为某个数据节点宕机后,会向其他Sentinel节点发送sentinel is-master-down-by-addr命令,要求自己成为领导者;
2)收到命令的Sentinel节点,如果没有同意过其他Sentinel节点的sentinelis-master-down-by-addr命令,将同意该请求,否则拒绝(每个Sentinel节点只有1票);
3)如果该Sentinel节点发现自己的票数已经大于等于MAX(quorum, num(sentinels)/2+1),那么它将成为领导者;
4)如果此过程没有选举出领导者,将进入下一次选举。
任何一个想成为 Leader 的哨兵,要满足两个条件:
-
第一,拿到半数以上的赞成票;
-
第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。
以 3 个哨兵为例,假设此时的 quorum 设置为 2,那么,任何一个想成为 Leader 的哨兵只要拿到 2 张赞成票,就可以了。
新库选择<