复习
单机有三个问题:
- 单点故障 (用主备/主从的方式,属于 AKF 的 X 轴)
- 容量
- 压力
关于容量问题解决的一些方案
1. 按业务分实例
客户端处理,将不同业务访问不同 Redis 实例。
但对于业务不可再拆分而单个业务容量需要很大时,就无法处理了。
2. 分片算法
2.1 客户端做 hash 区分访问那个实例
客户端做 hash 取模算法。
但影响扩展性。因为当扩展的时候,取模结果会发生变化,此时就需要将以往的所有数据进行取模运算再分配
2.2 Random 方式
存取方便,但查不方便。
那为什么还有这种方案呢?因为消息队列的场景可以用它,同一个 topic 下不同的 partition 可以是 random 选择的。
2.3 一致性哈希算法
哈希运算是一种映算法。通过算法将数据实现映射。参考
一致性哈希算法要求 key 和 设备 都需要进行哈希运算。

Redis 哈希槽
Redis-Cluster 自己实现了用哈希槽的概念,预先分为 16384 个哈希槽。然后分片的机器平均(默认)领取这些槽位。
Redis 集群式无主模型,即客户端可以连任意的 Redis,而 Redis 自己通过 Mapping 关系,将数据存在对于节点中。
分片的问题:整合
整合是常常用到的运算,比如 accountId:actionId:key1
和 accountId:actionId:key2
就可能常常需要在一起运算。
由于分片,所以数据分摊在不同的片上,那在整合的时候,还需要数据移动。这样是很影响效率的。
Redis 的解决策略是提供了 Hash Tag 的概念,让开发者自己去选择。如上方可以将 accountId
指定为 Hash Tag,Redis 只对 Hash Tag 进行运算,找到片的位置,这样就可以将有同样 Tag 的数据放在同一片中。
操作实例
- 操作下 twitter 的
twemproxy
代理。不支持事务 - 操作下
predixy
代理。只支持单 group 的事务。 - 操作下
redis-cluster
(用redis-cli --cluster
连接)。支持事务,但需要{hashTag}key
才能成功。reshard
解决数据倾斜。
文档旧的部分
AKF 拆分
由来,Redis DB 存全量的数据很耗内存,解决办法:
- 硬件括展内存,但不现实。
- 根据业务多实例划分。但会有数据倾斜的问题:某部分数据量太大。
- AKF 拆分原则(是 微服务设计的四个原则[参考] 之一)
AKF 的拆分最主要的是如何按 key 拆分到哪一个 redis 中:拆分算法。
AKF 拆分算法最主要的问题:
- 分片问题:增加物理节点如何去做。(如模 2 和模 3 结果不同)
- 负载问题:不需要代理层后怎么做。
对于分片,Redis 的做法是提供了个槽位的概念,当你未来增加物理节点,直接将槽位迁移过去。
对于负载,Redis 每个服务加个代理,
扩展:
- HBase 预分区实现,将数据存在分区上,当数据变大增加节点后,直接将某一部分区移动到新节点
- ElasticSearch 分片的实现,即便公司只有一点点数据量,但还是推荐你用高倍数的数据量压测它,多几个分片,日后增加节点便可以方便扩容。
- 无主模型(负载问题):就像 Redis 这种实现,ElasticSearch 也一样,在使用环节是无主的(不分主从,连哪一个都一样),服务自己做映射找到正确的节点。

分布式锁
场景:并发下想操作某一个资源,Redis 来创建一个 key 做为锁,谁拿到了这个锁,谁就能操作它。
问题:
- 在上锁状态中,若使用者挂了,不释放锁,若不释放锁,则造成死锁。可以用 Redis 过期时间来解决。
- 在上锁状态中,若Redis挂了而后又恢复了,中间可能锁丢失了,导致另一个服务拿到了这个锁,这里变成了两个锁。可以开启 Redis 的 AOF 持持久化来解决,要每操作级别的。(但这里 Redis 的性能已经退化到 MySQL 的性能了)。另外还可以开启 Redis 主从强一致,但这样会破坏可用性。
想法:用 RedLock 算法,这是一个算法,下面是实现逻辑。
- 多个 Redis 锁,谁抢到过半的锁,谁就有权限。问题:3 个服务器抢 3 个 Redis,造成都抢不到。
- 增加销毁功能,没抢到过半的锁时立即销毁自己的锁,重新抢。可以实现,但抢锁的逻辑是在客户端实现的算法。
所以问题的关键是在于并发,有并发就会有很恶心的事情发生。比如,RedLock 中,如果各服务抢到锁后设定的过期时间不同步,都设定 30 秒过期,但一个 20 秒就会过期,一个 10 秒就会过期。。。所有问题都想到了,逻辑也变得更庞大了。
解决方式:串行化。
zookeeper 在并发时是串行化的。它在分布式时,有一个 Leader,规定 增/删/改 操作一定要在 Leader 中按顺序处理。即集群模式下,串行化处理。
为保证读时也是最新的,可以要求同步,即达到强一致。
(zookeeper 也是内存型DB,它是做分布式协调的,在设计时就考虑到集群,在集群中它们是可以互相通信。另外它还有回调的功能,在抢锁过程中回复客户端可以抢了。而 Redis 是需要客户端主动做。)

(图片表述有误,客户端写可以连到 Follower,但会转移到 leader;leader 也可以读)
网友评论