一、集群原理
架构
Redis cluster使用去中心化的思想,整个集群是分布式的。所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
客户端与redis节点直连,不需要中间proxy层。客户端不需要连接集群所有节点,只要连接集群中任意一个可用节点即可。
Redis集群数据分片(Redis cluster data sharding)不使用一致性哈希算法,而是采用哈希槽(hash slot)的方式。集群中内置了 16384 个哈希槽(编号0-16383),每个master负责hashslots总数的一个子集,即[0-16384]个hashslot,且各个master负责的哈希槽没有交集。当所有master拥有的哈希槽的集合总数为16384时,该Redis cluster才能正常工作。
当要访问 Redis 集群中的一个 key 时,Redis 先对key使用CRC16 算法算出一个结果(0-32767),然后把结果对 16384 取模,这样就会对应到一个编号在 0-16383 之间的hash slot。如果算出来的hash slot落在当前节点本身,则直接处理返回数据。如果是在其他节点,则当前节点会返回负责这个hash slot的节点的IP和端口给客户端,以及-MOVED标识,由客户端向正确的节点再次发起请求。
当要存储一个 key-value 时,也是先计算 key 落在哪一个hash slot,过程与读key类似。
集群的这种模式很容易实现横向扩展。假设我想加个新的主节点,我只需要从原有的主节点分别移动一些hash slot到新节点上即可。同样的,假设我想从集群中移除一个主节点,只需要把该节点负责的hash slot移动到其他节点即可。当一个节点没有任何hash slot时,就可以完全删除该节点了。添加或删除节点时无需停止服务。
Redis集群支持多key操作,前提是这些key属于同一个hash slot。用户可以使用hash tags {}来强制使多个key落在同一个hash slot。例如user_id1和user_id2会落在同一个hash slot,因为Redis cluster遇到key中包含用{}包裹的字符串时,只会使用{}里面的内容进行计算CRC16值。
容错
Redis集群使用主从复制模型,每个master拥有0到N个的slave。slave是master的replica,slave本身不占hash slot。当某个master 挂掉时,集群将会提拔它的slave为新的主节点,集群将继续工作。节点的fail是通过集群中超过半数的主节点检测失效时才生效。
但是如果某个master没有slave,则挂掉之后,整个Redis集群就都挂掉了。
一致性
Redis集群不保证强一致性,因为集群主从采用的是异步复制。当客户端写数据到主节点,主节点回应客户端一切OK,然后主节点复制写的数据到从节点。此时如果刚完成第2步还没完成第3步,主节点就挂了,而从节点被提升为新的主节点,则刚刚写入的这部分数据就永久丢失了。
通信
Redis集群要求每个节点都开通两个TCP 连接。正常的Redis TCP端口作为服务端的端口,例如6379,服务端口加上10000作为数据端口(服务端端口和集群总线端口的偏移量是固定10000的),例如16379。
其中较大的端口被用于集群总线,即使用二进制协议的点对点的通信通道。集群总线作为节点间失败探测、配置更新、故障转移授权认可等等。客户端只要保持与,服务端端口连接即可,不要尝试连接集群总线端口。无论如何,要确保防火墙没有关闭这两个端口,否则Redis集群节点不能互相通信。
持久化
Redis的持久化方式有aof、rdb、以及aof&rdb三种。其中aof类似关系型数据库中的binlog,把每一次写操作以追加的形式记录在其中并以文件的形式刷到磁盘里。Redis默认采用每秒fsync策略(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求,因此Redis性能依然很好),因此一旦出现故障,最多丢失1秒的数据。但是缺点也随之而来,那就是aof文件的大小会随着时间线性增长 一段时间之后,就会变得很大。如果要在一端以aof的形式来恢复数据,那么由于aof文件的巨大体积,可能会让进程如同假死一样,十分的慢。
rdb则是一种快照机制,Redis工作在内存中,rdb就是每隔一段时间对内存中的数据做一次快照,保存在rdb文件中。Redis会fork出一个子线程来做快照,不影响父线程处理请求。Rdb的问题是如果数据量很大的话,它要保存一个完整的数据集是一个大的工作,如果时间间隔设置太短就会影响Redis的性能,如果按常规设置5分钟,则重启的话会丢失分钟级的数据。
在redis4.0的新特性中,采用了aof-rdb的混合方案来保障数据的持久性。
二、搭建步骤
单机实例
参照《Redis主从安装部署》安装单机实例。
实例复制
创建redis-cluster文件夹,并在目录下以端口号命名创建6个子文件,作为redis集群的实例:
从单机实例中复制配置文件redis.conf到7001目录下redis7001.conf,并修改配置:
复制redis7001.conf到其他5个文件夹下,并使用命令:%s/7001/700/g来进行端口替换,其中为对应的2、3、4、5、6。
复制redis-trib.rb脚本到目录下:cp /usr/local/redis-4.0.10/src/redis-trib.rb /usr/local/redis-cluster
编写启动脚本和停止脚本:
执行启动脚本sh start-all.sh
创建集群
./redis-trib.rb create --replicas 1 192.25.106.133:7001 192.25.106.133:7002 192.25.106.133:7003 192.25.106.133:7004 192.25.106.133:7005 192.25.106.133:7006
提示没有安装ruby。因为redis cluster的管理工具redis-trib.rb是用ruby写的,要使用它必须先安装ruby。
ruby环境
yum -y install ruby
yum -y install rubygems
gem install redis
首次安装可能出现如下错误,直接百度搜素错误信息查看解决方案:
出现如下信息表示安装成功:
继续执行创建集群命令
看到All 16384 slots covered.表示集群创建成功。
通过客户端连接其中一个端口进行测试,-c表示以集群方式连接:
获取key a,发现不在7001节点,会重定向到所在的节点。
通过命令cluster nodes查看集群节点信息,可以看到各个节点负责的slots以及slave信息: