集群和限流
# Redis有下面四种部署方式
模式 | 优点 | 缺点 |
---|---|---|
单机版 | 架构简单,部署方便 | 机器故障、容量瓶颈、QPS瓶颈 |
主从复制 | 高可靠性,读写分离 | 故障恢复复杂,主库的写跟存受单机限制 |
Sentinel 哨兵 | 集群部署简单,HA | 原理繁琐,slave存在资源浪费,不能解决读写分离问题 |
Redis Cluster | 数据动态存储solt,可扩展,高可用 | 客户端动态感知后端变更,批量操作支持查 |
下面一个一个的进行介绍
# redis主从复制
该模式下 具有高可用性且读写分离, 会采用 增量同步
跟 全量同步
两种机制。
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份
1、slave连接master,发送
psync
命令。2、master接收到
psync
命名后,开始执行bgsave命令生成RDB文件并使用缓冲区记录此后执行的所有写命令。3、master发送快照文件到slave,并在发送期间继续记录被执行的写命令。4、slave收到快照文件后丢弃所有旧数据,载入收到的快照。
5、master快照发送完毕后开始向slave发送缓冲区中的写命令。
6、slave完成对快照的载入,开始接收命令请求,并执行来自master缓冲区的写命令。
增量同步也叫指令同步,。Redis会把指令存放在一个环形队列当中,因为内存容量有限,如果备机一直起不来,不可能把所有的内存都去存指令,也就是说,如果备机一直未同步,指令可能会被覆盖掉。
Redis增量复制是指Slave初始化后开始正常工作时master发生的写操作同步到slave的过程。增量复制的过程主要是master每执行一个写命令就会向slave发送相同的写命令。
1、主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步
。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。2、slave在同步master数据时候如果slave丢失连接不用怕,slave在重新连接之后丢失重补
。
3、一般通过主从来实现读写分离,但是如果master挂掉后如何保证Redis的 HA呢?引入Sentinel
进行master的选择。
# 哨兵模式
Redis-sentinel 本身是一个独立运行的进程,一般sentinel集群 节点数至少三个且奇数个,它能监控多个master-slave集群,sentinel节点发现master宕机后能进行自动切换。Sentinel可以监视任意多个主服务器以及主服务器属下的从服务器,并在被监视的主服务器下线时,自动执行故障转移操作。这里需注意sentinel
也有single-point-of-failure
问题。大致罗列下哨兵用途:
集群监控:循环监控master跟slave节点。
消息通知:当它发现有redis实例有故障的话,就会发送消息给管理员
故障转移:这里分为主观下线(单独一个哨兵发现master故障了)。客观下线(多个哨兵进行抉择发现达到quorum数时候开始进行切换)。
配置中心:如果发生了故障转移,它会通知将master的新地址写在配置中心告诉客户端。
# Redis Cluster
RedisCluster是Redis的分布式解决方案,在3.0版本后推出的方案,有效地解决了Redis分布式的需求。说白了就是把数据分布在不同的节点上,采用去中心化的思想
分区规则如下
有下面这几个分区规则
节点取余
:hash(key) % N一致性哈希
:一致性哈希环虚拟槽哈希
:CRC16[key] & 16383
总结
- RedisCluster采用了
虚拟槽分区
方式 - 采用去中心化的思想,它使用虚拟槽solt分区覆盖到所有节点上,取数据一样的流程,节点之间使用轻量协议通信Gossip来减少带宽占用所以性能很高
- 自动实现负载均衡与高可用,自动实现failover并且支持动态扩展,官方已经玩到可以1000个节点 实现的复杂度低。
- 每个Master也需要配置主从,并且内部也是采用哨兵模式,如果有半数节点发现某个异常节点会共同决定更改异常节点的状态。
- 如果集群中的master没有slave节点,则master挂掉后整个集群就会进入fail状态,因为集群的slot映射不完整。如果集群超过半数以上的master挂掉,集群都会进入fail状态。
- 官方推荐 集群部署至少要3台以上的master节点。
# Redis限流
在开发高并发系统时,有三把利器用来保护系统:缓存
、降级
和限流
。目前主要有下面这几种限流的算法
# 基于Redis的setnx、zset
setnx
比如我们需要在10秒内限定20个请求,那么我们在setnx的时候可以设置过期时间10,当请求的setnx数量达到20时候即达到了限流效果。
缺点:比如当统计1-10秒的时候,无法统计2-11秒之内,如果需要统计N秒内的M个请求,那么我们的Redis中需要保持N个key等等问题。
zset
其实限流涉及的最主要的就是滑动窗口,上面也提到1-10怎么变成2-11。其实也就是起始值和末端值都各+1即可。我们可以将请求打造成一个zset数组,当每一次请求进来的时候,value保持唯一,可以用UUID生成,而score可以用当前时间戳表示,因为score我们可以用来计算当前时间戳之内有多少的请求数量。而zset数据结构也提供了range方法让我们可以很轻易的获取到2个时间戳内有多少请求,
缺点:就是zset的数据结构会越来越大。
# 漏桶算法
把水比作是请求,漏桶比作是系统处理能力极限,水先进入到漏桶里,漏桶里的水按一定速率流出,当流出的速率小于流入的速率时,由于漏桶容量有限,后续进入的水直接溢出(拒绝请求),以此实现限流。
# 令牌桶算法
令牌桶算法的原理:可以理解成医院的挂号看病,只有拿到号以后才可以进行诊病。
一些细节
- 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理。
- 根据限流大小,设置按照一定的速率往桶里添加令牌。
- 设置桶最大可容纳值,当桶满时新添加的令牌就被丢弃或者拒绝。
- 请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除。
- 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流。