Redis集群详解

Redis集群详解
一、Redis简介
  Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
  Redis 是一个高性能的key-value数据库,和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。Redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
二、Redis集群
  Redis支持三种集群方式,Redis复制(主从)、Redis哨兵(sentinel)、Redis集群(Cluster),下面就三种集群做从原理、优缺点做简单介绍,以备在项目中可以根据不同场景进行选择。
2.1 主从复制
  通过执行slaveof命令或者设置slaveof选项,让一个服务器去复制另一个服务器的数据,被复制的服务器我们称为master主服务器,对主服务器进行复制的服务器我们称为slave从服务器。主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。从数据库一般为只读操作,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能属于一个主数据库。
2.1.1 实现原理
  1.从服务器向主服务器发送SYNC(数据同步)命令。
  2.主服务器接收到SYNC命令后,执行BGSAVE(数据保存),在后台生成RDB文件,使用缓冲区记录,从现在开始执行的所有写命令。
  3.当主服务器的BGSAVE命令执行完毕后,主服务器将BGSAVE生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
  4.主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
2.1.2 通信过程图
Redis集群详解
2.1.3 优点
  1.主服务器自动将数据同步到从服务器,可以进行读写分离。
  2.为了分担master的读操作压力,slave服务器可以为客户端提供只读操作的服务,写操作仍然必须由master完成。
  3.slave同样可以接受其他slave的连接和同步请求,这样可以有效的分担master同步压力。
  4.master是以非阻塞方式为slave提供服务,所以在master和slave同步期间,客户端仍然可以提交查询和修改请求。
  5.slave同样以非阻塞的方式完成数据同步,在同步期间,如果客户端提交查询请求,redis则返回同步之前的数据。
2.1.4 缺点
  1.主从模式不支持自动容错和恢复功能,主服务器和从服务器的宕机都会导致前端部分读写请求失败,需要等待服务器重启或者手动切换前端的IP才能恢复。
  2.主服务器宕机,宕机前有部分数据未能及时同步到从从服务器,切换IP后还会引入数据不一致的问题,降低了系统可用性。
  3.Redis本身较难支持在线扩容,在集群容量到达上限时在线扩容变得复杂。
2.2 哨兵模式
  为了解决Redis的主从复制不支持高可用性,Redis实现了哨兵(sentinel)模式,由一个sentinel去监听任意多个主服务器及从服务器,并在被监听的主服务器宕机时,自动将主服务器下的从服务器升级为新的主服务器,由新的主服务器代替已经下线的主服务器。
哨兵(sentinel)之间也可以相互监听,当有多个哨兵时,在进行监听和转移主从服务器时,sentinel之间会自己首先进行选举,选出sentinel的leader来进行执行任务。
2.2.1 实现原理
  1.每个哨兵节点维护了3个定时任务。定时任务的功能分别如下:通过向主从节点发送info命令获取最新的主从结构;通过发布订阅功能获取其他哨兵节点的信息;通过向其他节点发送ping命令进行心跳检测,判断是否下线。
  2.在心跳检测的定时任务中,如果其他节点超过一定时间没有回复,哨兵节点就会将其进行主观下线。顾名思义,主观下线的意思是一个哨兵节点“主观的”判断下线;与主观下线相对应的是客观下线。
  3.哨兵节点在对主节点进行主观下线后,会通过sentinel is-master-down-by-addr命令询问其他哨兵节点该主节点的状态;如果判断主节点下线的哨兵数量达到一定数值,则对该主节点进行客观下线。
  需要特别注意的是,客观下线是主节点才有的概念;如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作
  4.当主节点被判断客观下线以后,各个哨兵节点会进行协商,选举出一个领导者哨兵节点,并由该领导者节点对其进行故障转移操作
2.2.2 集群架构图
1.单哨兵模式
Redis集群详解
2.多哨兵模式
Redis集群详解
2.2.3 优点
  1.哨兵模式是基于主从模式建立的,所有主从的优点,哨兵模式都具有。
  2.主从可以自动切换,系统更加的健壮,可用性更高。
2.2.4 缺点
  1.Redis本身较难支持在线扩容,在集群容量到达上限时在线扩容变得复杂。
2.3 Cluster模式
  Redis的哨兵模式基本上已经可以实现了高可用、读写分离,但是这种模式下每台服务器都存储相同的数据,很浪费内存。所以在Redis3.0以上的版本加入了cluster模式,实现Redis的分布存储,也就是说每台服务器上存储不同的内容。
  Cluster通过分片来进行数据共享,并提供复制和故障转移功能。一个Redis Cluster通常由多个节点组成,最初每个节点都是独立的,需要将独立的节点连接起来才能形成可工作的集群。
  Redis中的集群分为主节点和从节点,其中主节点用于处理槽,而从节点用于复制,某个主节点,并在被复制的主节点下线时,代替下线的主节点继续处理命令请求。
  Cluster采用无中心结构,有如下特点:
  1.所有的redis服务器彼此互联(ping-pong机制),内部使用二进制协议优化传输速度和带宽。
  2.节点的fail是通过集群中超过半数的节点检测失效时才生效。
  3.客户端与redis节点直连,不需要中间代理层,客户端连接集群所有节点,连接集群中任何一个可用节点即可。
2.3.1实现原理
  1.所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
  2.节点的fail是通过集群中超过半数的节点检测失效时才生效。
  3.客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
  4.redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
  Redis集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
2.3.2集群架构图
Redis集群详解
2.3.3 优点
  1.无中心架构
  2.数据按照slot存储分布在多个节点,节点间数据共享,可动态调整数据分布。
  3.动态扩展,可线性扩展到100+以上节点,节点可动态添加或删除。
  4.高可用性,部分节点不可用时,集群仍可用。通过slave做备用数据副本,能够实现故障自动故障转移,节点之间通过gossip协议交换状态。
  5.降低运维成本,提高系统的扩展性、可用性。
2.3.4 缺点
  1.client实现复杂,驱动要求实现Smart Client,缓存slots mapping信息并及时更新,提高了开发难度,客户端的不成熟影响业务的稳定性。目前仅Jedis Cluster相对成熟,异常处理部分还不完善,比如常见的“max redirect exception”。
  2.节点会因为某些原因发生阻塞(阻塞时间大于clutser-node-timeout),被判断下线,这种failover是没有必要的。
  3.数据通过异步复制,不保证数据的强一致性。
  4.多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容易出现相互影响的情况。
  5.slave在集群中充当“冷备”,不能缓解读压力,当然可以通过SDK的合理设计来提高slave资源的利用率。
  6.Key批量操作限制,如使用mset、mget目前只支持具有相同slot值的Key执行批量操作。对于映射为不同slot值的Key 由于Keys不支持跨slot查询,所以执行mset、mget、sunion等操作支持不友好。
  7.Key事务操作支持有限,只支持多key在同一节点上的事务操作,当多个Key分布于不同的节点上时无法使用事务功能。
  8.Key作为数据分区的最小粒度,不能将一个很大的键值对象如hash、list等映射到不同的节点。
  9.不支持多数据库空间,单机下的redis可以支持到16个数据库,集群模式下只能使用1个数据库空间,即db 0。
  10.复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
  11.避免产生hot-key,导致主库节点成为系统的短板。
  12.避免产生big-key,导致网卡撑爆、慢查询等。
  13.重试时间应该大于cluster-node-time时间。
  14.cluster不建议使用pipeline和multi-keys操作,减少max redirect 产生的场景。