之间我们抛出了单机Redis的几种问题:
- 单点故障
- 容量有限
- IO压力
其中我们使用sentinel解决了单点故障的问题实现了高可用,使用主从复制实现读写分离解决了IO压力的问题,但是如何解决Redis容量的问题呢? - Sharding分片实现扩容
Redis扩容的几种方案
1.数据可以分类,交集不多
在这种情况下,我们可以通过client做业务拆分,不同的业务使用不同的Redis

2.数据没办法划分拆解
-
根据hash取模进行划分
在客户端通过hash取模算法从不同的Redis中读取数据,其可以实现Redis的扩容,但是取模的数字必须是固定的,影响分布式下的扩展性
根据hash取模算法拆分 -
根据Random随机拆分
在客户端通过random随机从不同的Redis中读取数据,其弊端是完全随机,无法固定取得数据。但是在特定的场景下也是可以使用的,比如做类似消息队列的场景
随机拆分 -
根据一致性hash拆分
可以在客户端根据一致性hash算法(或者一系列映射算法)拆分数据,该算法讲node和data同时进行计算
一致性hash拆分
一致性hash算法
将0 - 2^32个点散列在hash环上,将node和data使用相同的hash[映射]算法确定在各自的点位,使得读取该key的数据时,都在顺时针最近的node上进行

当加入其node时,也使用同样的算法加入hash环,这样可以很方便的分担其他节点的压力,也不会使数据重新洗牌,但是新增节点会使一小部分数据无法命中,造成缓存击穿,使得请求访问mysql,此时我们可以开启内存管理,淘汰原有的数据,将这些数据加入新的节点,但此时,Redis更倾向作为缓存,而不是数据库
- 如果因hash算法导致数据倾斜如何处理?
Redis会加入虚拟节点,比如之前是对node的ip进行hash,现在我们可以使用ip+一些随机数进行hash,使得节点和虚拟节点分布在hash环上

使用Redis分片的架构设计
-
客户端直连Redis
Redis的连接成本很高,多个客户端集中访问redis会在服务端造成很大压力
客户端直连Redis -
通过代理连接Redis
此时需要关注代理性能
通过代理连接Redis - 当代理性能不够时 - LVS + proxy集群
LVS的相关知识可参阅之前的文章LVS负载均衡:https://www.jianshu.com/p/20b5dc39c564

关于代理的功能可以参阅twemproxy的功能文档(README):https://github.com/twitter/twemproxy
- 以上3种分区模式的弊端:Redis无法作为数据库使用
如何解决这个问题。我们可以使用预分区的方式:
redis代理实现预分区:如下图,我们开始只有2台Redis,划分10个hash槽道,0-4的读取在redis01,5-9的读取在redis02,当新加入redis03时,我们可以把对应槽道的数据迁移入redis03中

那么Redis是如何实现的呢?
Redis自身实现:首先做预分片,然后把对应的槽道数据转移到新的分片,每台redis中保存了所有redis的mapping信息,当用户执行读写操作时,如果数据不在当前节点,则因为有所有redis的mapping,则可以让用户去对应的redis分片读取数据(没有主的概念)





