Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis是一款优秀的NoSQLDB,它在2.x版本不支持集群,集群必须通过外部手段集成;但由于集成方法过于复杂,研发测试和运维要求较高。新版本Redis3.x发布后,自带集群功能,降低了分布式缓存的使用门槛。
Redis2.x单实例支持的业务能力并不小,Redis3.x内部集群后,集群负担工作有一定系统开销,如果使用选型需要结合业务具体分析。一般来说,必须使用分布式场景的或业务数据过亿的可以考虑Redis3.x。
Redis模式实现,主要分为以下三种:
- Redis主从(复制,redis2.8版本之前的模式)
- Redis哨兵(Sentinel,redis2.8及之后的模式)
- Redis集群(redis3.0版本之后)
1. Redis主从模式
1.1. 主从模式原理
同Mysql主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制分为全量同步和增量同步两种。下图为级联结构。
1.2. 增量、全量同步
- 增量同步:增量同步较好理解,主服务器想从服务器发送缓冲区写命令,完成增量数据的同步;
- 全量同步:Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
- 从服务器连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载人收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
1.3. 主从模式优缺点
- 优点:
- 解决数据备份问题
- 做到读写分离,提高服务器性能
- 缺点:
- 每个客户端连接redis实例的时候都是指定了ip和端口号的,如果所连接的redis实例因为故障下线了,而主从模式也没有提供一定的手段通知客户端另外可连接的客户端地址,因而需要手动更改客户端配置重新连接
- 主从模式下,如果主节点由于故障下线了,那么从节点因为没有主节点而同步中断,因而需要人工进行故障转移工作
- 无法实现动态扩容
2. Redis哨兵模式
Sentinel(哨兵)是Redis的高可用性解决方案:由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。
2.1. 哨兵模式原理
2.2. 哨兵模式优缺点
- 优点
- Master 状态监测
- 如果Master 异常,则会进行Master-slave 转换,将其中一个Slave作为Master,将之前的Master作为Slave
- Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换
- 缺点:
- 如果是从节点下线了,sentinel是不会对其进行故障转移的,连接从节点的客户端也无法获取到新的可用从节点
- 无法实现动态扩容
3. Redis集群模式
集群是Redis提供的分布式数据库方案,集群通过分片来进行数据共享,并提供复制和故障转移功能。一个Redis集群通常由多个节点组成;最初,每个节点都是独立的,需要将独立的节点连接起来才能形成可工作的集群。可以通过Cluster Nodes命令和Cluster Meet命令,添加和连接节点形成集群。
在这个图中,每一个蓝色的圈都代表着一个redis的服务器节点。它们任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点。对其进行存取和其他操作。一般集群建议搭建三主三从架构,三主提供服务,三从提供备份功能。
3.1. 集群模式原理
在redis的每一个节点上,都有这么两个东西,一个是插槽(slot)可以理解为是一个可以存储两个数值的一个变量这个变量的取值范围是:0-16383。还有一个就是cluster. 这个cluster理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
还有就是因为如果集群的话,是有好多个redis一起工作的,那么,就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务。这个备用的redis称为从节点(slave)。那么这个集群是如何判断是否有某个节点挂掉了呢?
首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。
它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。如果某个节点和所有从节点全部挂掉,我们集群就进入fail状态。还有就是如果有一半以上的主节点宕机,那么我们集群同样进入发力了状态。这就是我们的redis的投票机制,具体原理如下图所示:
Redis中的集群分为主节点和从节点。其中主节点用于处理槽;而从节点用于复制某个主节点,并在被复制的主节点下线时,代替下线的主节点继续处理命令请求。
3.2. 集群模式优缺点
- 优点:
- 有效的解决了redis在分布式方面的需求
- 遇到单机内存,并发和流量瓶颈等问题时,可采用Cluster方案达到负载均衡的目的
- 可实现动态扩容
- P2P模式,无中心化
- 通过Gossip协议同步节点信息
- 自动故障转移、Slot迁移中数据可用
- 缺点:
- 架构比较新,最佳实践较少
- 为了性能提升,客户端需要缓存路由表信息
- 节点发现、reshard操作不够自动化
3.3. Redis集群数据分片
Redis Sharding可以说是在Redis cluster出来之前业界普遍的采用方式,其主要思想是采用hash算法将存储数据的key进行hash散列,这样特定的key会被定为到特定的节点上。进而实现高并发场景的一个高性能分布式锁;
高性能分布式锁具体可参考链接:每秒上千订单场景下的分布式锁高并发优化实践!
3.3.1. Jedis sharding集群
庆幸的是,Java Redis客户端驱动Jedis已支持Redis Sharding功能,即ShardedJedis以及结合缓存池的ShardedJedisPool
Jedis的Redis Sharding实现具有如下特点:
- 采用一致性哈希算法,将key和节点name同时hashing,然后进行映射匹配,采用的算法是MURMUR_HASH。采用一致性哈希而不是采用简单类似哈希求模映射的主要原因是当增加或减少节点时,不会产生由于重新匹配造成的rehashing。一致性哈希只影响相邻节点key分配,影响量小。
- 为了避免一致性哈希只影响相邻节点造成节点分配压力,ShardedJedis会对每个Redis节点根据名字(没有,Jedis会赋予缺省名字)会虚拟化出160个虚拟节点进行散列。根据权重weight,也可虚拟化出160倍数的虚拟节点。用虚拟节点做映射匹配,可以在增加或减少Redis节点时,key在各Redis节点移动再分配更均匀,而不是只有相邻节点受影响。
- ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag做sharding,这样通过合理命名key,可以将一组相关联的key放入同一个Redis节点,这在避免跨节点访问相关数据时很重要。
当然,Redis Sharding这种轻量灵活方式必然在集群其它能力方面做出妥协。比如扩容,当想要增加Redis节点时,尽管采用一致性哈希,毕竟还是会有key匹配不到而丢失,这时需要键值迁移。
作为轻量级客户端sharding,处理Redis键值迁移是不现实的,这就要求应用层面允许Redis中数据丢失或从后端数据库重新加载数据。但有些时候,击穿缓存层,直接访问数据库层,会对系统访问造成很大压力。
3.3.2. 利用中间件代理
中间件的作用是将我们需要存入redis中的数据的key通过一套算法计算得出一个值。然后根据这个值找到对应的redis节点,将这些数据存在这个redis的节点中。常用的中间件有这几种
- Twemproxy
- Codis
- nginx
3.3.3. 总结
客户端分片(sharding)需要客户端维护分片算法,这是一种静态的分片方案,需要增加或者减少Redis实例的数量,需要手工调整分片的程序。
利用中间件的情况则会影响到redis的性能,具体看中间件而定,毕竟所有请求都要经过中间件一层过滤.
3.4. 集群模式搭建
Redis3引入了一个hash槽的概念,集群将整个系统分为16384个hash槽,这16384个槽位要全部分布在集群中的主节点上。主节点是Redis的读写节点,每个主节点可以配置一个或多个从节点,从节点自动同步主节点数据;当主节点下线时,从节点自动代替主节点工作。
Redis3.x的最小集群需要3主3从6个实例;在生产环境最小配置3台服务器。测试验证工作可以部署在一台物理机上,用端口来区分实例。可以使用六个端口代表六个实例,搭建“三主三从”的集群环境,例如六个端口分别为6381 6382 6383 6384 6385 6386。
//TODO