当访问量比较大,使用到redis集群的时候,就需要面临一个问题,读写分离。这就意味要么客户端知道主节点是哪个节点,从节点是哪些节点?要么就是,中间加一个代理,来实现主从复制的要求。Redis集群的方案有很多,此处介绍redis官方给出的方案,推荐使用。
基于分片。一个 Redis cluster集群包含 16384 个哈希槽, 任意一个key都可以通过 CRC16(key) % 16384 这个公式计算出应当属于哪个槽。每个槽应当落在哪个节点上,也是事先定好。这样,进行任一操作时,首先会根据key计算出对应的节点,然后操作相应的节点就可以了。所以说,其实cluster跟单点相比,只是多了一个给key计算sharding值的过程,并没有增加多少复杂度,个人认为完全可以放心使用。像增删节点、重启这些对redis本身的操作,和client端对数据的操作,是两套流程,可以做到互不干扰。关于节点故障,一是有slave,二是即便这一个节点完全挂掉,也只是落在这个节点上的数据不可用,不会有类似"雪崩"这样的问题影响整个集群。数据的恢复之类的逻辑,也与单点完全一致,是独立于集群其他部分的。redis cluster的整个设计是比较简单的,并没有引入太多新问题,大部分操作都可以按照单点的操作流程进行操作。至于cluster最终的易用性,其实很大程度上取决client端的代码可靠性,而jedis现在的代码也已经很完善了,用起来也比较方便。
优点:无中心的P2P Gossip分散式模式,更少的来回次数并降低延迟,自动在多个节点进行分片,不需要第三方软件支持协调机制;缺点:依赖于redis 3,0或更高的版本,没有后台界面,需要智能客户端,Redis客户端必须支持Redis Cluster架构,教Codis有更多的维护升级成本;
集群文件配置:
cluster-enabled:是否启用集群环境,默认注释掉的;
cluster-config-file:cluster集群配置文件,该文件不需要有东西,集群会自己写,但是必须要有该文件,默认注释掉了。该文件,默认放置在etc目录下;
cluster-node-timeout:判断节点是否故障的超时时长,默认被注释;
cluster-slave-validity-factor 进行故障转移时,salve会申请成为master。有时slave会和master失联很久导致数据较旧,这样的slave不应该成为master。这个配置用来判断slave是否和master失联时间过长。
实验:实现redis集群
三台主机,node1,node2,node3;实现redis-cluster;
在三个节点上执行:
vim /etc/redis.conf
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
cluster-slave-validity-factor 10
systemctl start redis
node1节点:
systemctl start redis
ss -ntl
redis-cli
127.0.0.1:6379> config get cluster-enabled
(empty list or set)
127.0.0.1:6379> cluster info
cluster_state:fail # 集群的状态;
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0
127.0.0.1:6379> exit
for i in {0..5461};do redis-cli cluster addslots $i;done # 添加哈希槽;
node2节点:
systemctl restart redis
ss -ntl
for i in {5462..10922};do redis-cli cluster addslots$i;done # 添加哈希槽;
node3节点:
systemctl restart redis
ss -ntl
for i in {10923..16384};do redis-cli cluster addslots $i;done # 添加哈希槽
node2节点:
for i in {1..20};do redis-cli set key$i value$i;done # 添加数据,测试效果;
OK
(error) MOVED 4998 192.168.109.7:6379
(error) MOVED 935 192.168.109.7:6379
(error) MOVED 13120 192.168.109.6:6379
OK
(error) MOVED 4866 192.168.109.7:6379
……
node1节点:
redis-cli
127.0.0.1:6379> cluster meet 192.168.109.6
(error) ERR Wrong CLUSTER subcommand or number of arguments
127.0.0.1:6379> cluster meet 192.168.109.6 6379 # 添加集群;
OK
127.0.0.1:6379> cluster meet 192.168.109.8 6379 # 添加集群;
OK
127.0.0.1:6379> cluster info # 查看集群的状态;
cluster_state:ok # 集群配置成功
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:3
cluster_current_epoch:2
cluster_my_epoch:2
cluster_stats_messages_sent:29
cluster_stats_messages_received:29
127.0.0.1:6379> cluster nodes # 查看集群的节点;
b22df3f9965c33375956887de1bf17483fc1d58f 192.168.109.8:6379 master - 0 1513168145410 0 connected 5462-10922
11e6acb0b53841b276c1ffed1913f6e3d16ee15c 192.168.109.6:6379 master - 0 1513168144401 1 connected 10923-16383
94b161eea14d5eb7ed99e1f71c79cea980330ae2 192.168.109.7:6379 myself,master - 0 0 2 connected 0-5461
127.0.0.1:6379> get key1
(error) MOVED 9189 192.168.109.8:6379 # 在节点1上,查看key1的值,因为该值不在此处存放,所以,node1反馈给客户端,数据的地址。在生产环境中,使用的是智能设备,它会自己去访问,此处没办法模拟。
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> get key3
(nil)
node2节点:
redis-cli
127.0.0.1:6379> get key1
"value1"
127.0.0.1:6379> get key2
(error) MOVED 4998 192.168.109.7:6379
注意:在工作环境中,还需要使用主从备份。此处由于没有多余的机器,没有设置从属节点;可以使用多实例技术。