1、redis集群形式
1)、数据分区方案
①、客户端分区
客户端分区方案的代表为 Redis Sharding,Redis Sharding是Redis Cluster出来之前,业界普遍使用的Redis多实例集群方法。Java的Redis客户端驱动库Jedis,支持Redis Sharding功能,即ShardingJedis 以及结合缓存池的ShardingJedisPool.
优点:
不使用第三方中间件,分区逻辑可控,配置简单,节点之间无关联,容易线性扩展,灵活性强。
缺点:
客户端无法动态增删服务节点,客户端需要自行维护分发逻辑,客户端之间无连接共享,会造成连接浪费。
②、代理分区
代理分区常用方案有Twemproxy 和 Codis.
③、redis-cluster
2)、高可用方式
①、Sentinel(哨兵机制) 支持高可用
前面介绍了主从机制,但是从运维角度来看,主节点出现了问题我们还需要通过人工干预的方式把从节点设为主节点,还要通知应用程序更新主节点地址,这种方式非常繁琐笨重,而且主节点的读写能力都十分有限,有没有较好的办法解决这两个问题,哨兵机制就是针对第一个问题的有效解决方案;第二个问题则有赖于集群!哨兵的作用就是监控Redis系统的运行情况,其功能主要是包含以下三个;
哨兵的原理
Redis哨兵的三个定时任务,Redis哨兵判定一个Redis节点故障不可达主要就是通过三个定时监控任务来完成的;
如果在定时Job3检测不到节点的心跳,会判断为“主观下线”。如果该节点还是主节点那么还会通知到其他的哨兵对该主节点进行心跳检测,这时主观下线的票数超过了
故障转移和Leader选举
如果主节点被判定为客观下线之后,就要选取一个哨兵节点来完成后面的故障转移工作,选举出一个leader,这里面采用的选举算法为Raft。选举出来的哨兵leader就要来完成故障转移工作,也就是在从节点选出一个节点来当新的主节点,这部分的具体流程可参考引用《深入理解Redis哨兵搭建及原理》
②、redis-cluster
详见下章
2、Redis-Cluster
https://redis.io/topics/cluster-tutorial
Redis的官方多机部署方案,Redis Cluster。一组Redis Cluster是由多个Redis实例组成,官方推荐我们使用6个实例,其中3个为主节点,3个为从节点。一旦有主节点发生故障的时候,Redis Cluster可以选举出对应的从节点成为新的主节点,继续对外服务,从而保证服务的高可用性。那么对于客户端来说,知道对应的key是要路由到哪一个节点呢?Redis Cluster 把所有的数据划分为16384个不同的槽位,可以根据机器的性能把不同的槽位分配给不同的Redis实例,对于Redis实例来说,他们只会存储部分的Redis数据,当然,槽的数据是可以迁移的,不同的实例之间,可以通过一定的协议,进行数据迁移。
1)、槽
Redis集群的功能限制;Redis集群相对单机在功能上存在一些限制,需要 开发人员提前了解,在使用时做好规避。Java CRC16 校验算法 https://www.jianshu.com/p/88a32b64273c
类似mset、mget操作,目前只支持对具有相同slot值的key执行批量操作。对于映射为不同slot值的key由于执行mget、mset等操作可能存在于多个节点上,因此不被支持。
只支持多key在同一节点上的事务操作,当多个key分布在不同的节点上时无法使用事务功能
单机下的Redis可以支持16个数据库(db0~db1),集群模式下只能使用一个数据空间,即db0
从节点只能复制主节点,不支持嵌套树状复制结构。
2)、一致性hash
一致性哈希可以很好的解决稳定性问题,可以将所有的存储节点排列在首位相接的Hash环上,每个key在计算后会顺时针找到临接的存储节点存放。而当有节点加入或退出时,仅影响该节点在Hash环上顺时针相邻的后续节点。
Hash倾斜
如果节点很少,容易出现倾斜、负载不均衡问题。一致性哈希算法,引入了虚拟节点、在整个环上,均衡增加若干个节点。比如a1,a2,b1,b2,c1,c2; a1和a2都是属于A节点的。解决Hash倾斜问题
3、部署Cluster
1)、创建6个Redis节点
3主3从方式,从为了同步备份,主进行slot分片
for port in $(seq 7001 7006); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.54.130
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}
appendonly yes
EOF
docker run -p ${port}:${port} -p 1${port}:1${port} --name redis-${port} --restart always \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d redis:5.0.7 redis-server /etc/redis/redis.conf; \
done
port ${port} ##节点端口
cluster-enabled yes ##cluster集群模式
cluster-config-file nodes.conf ##集群配置名
cluster-node-timeout 5000 ##超时时间
cluster-announce-ip 192.168.54.130 ##实际为各节点网卡分配ip 先用上网关ip代替
cluster-announce-port ${port} ##节点映射端口
cluster-announce-bus-port 1${port} ##节点总线端口
appendonly yes ##持久化模式
#停止所有redis容器
docker stop $(docker ps -a|grep redis-700 | awk '{print $1}')
#删除所有redis容器
docker rm $(docker ps -a|grep redis-700 | awk '{print $1}')
2)、使用redis建立集群
docker exec -it redis-7001 /bin/bash
redis-cli --cluster create 192.168.54.130:7001 192.168.54.130:7002 192.168.54.130:7003 192.168.54.130:7004 192.168.54.130:7005 192.168.54.130:7006 --cluster-replicas 1
--cluster-replicas 1 设置一个副本
输出
#指定某个节点连接 -c指定集群操作方式
root@d54e449c82ac:/data# redis-cli -c -h 192.168.54.130 -p 7001
192.168.54.130:7001> set hello 1
OK
192.168.54.130:7001> set a aaa #key a的槽在7003
-> Redirected to slot [15495] located at 192.168.54.130:7003
OK
192.168.54.130:7003> get a
"aaa"
192.168.54.130:7003> get hello #在7003获取key hello 的值会重定向到7001
-> Redirected to slot [866] located at 192.168.54.130:7001
"1"
192.168.54.130:7001> set bb aa #key bb的槽在7002
-> Redirected to slot [8620] located at 192.168.54.130:7002
OK
192.168.54.130:7002>
查询集群状态
192.168.54.130:7001> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1962
cluster_stats_messages_pong_sent:2024
cluster_stats_messages_sent:3986
cluster_stats_messages_ping_received:2019
cluster_stats_messages_pong_received:1962
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:3986
查询集群节点信息
192.168.54.130:7001> cluster nodes
1ea5481619b5fb2f58cf2be62019ed822b957b4b 192.168.54.130:7003@17003 master - 0 1629899872589 3 connected 10923-16383
b3e9e0218c9814cd7ef09ca5116a7998c8a9378b 192.168.54.130:7004@17004 slave 1ea5481619b5fb2f58cf2be62019ed822b957b4b 0 1629899873598 4 connected
3501d50aa5cc704c0e6401ba0685fe4e9541cdb2 192.168.54.130:7001@17001 myself,master - 0 1629899873000 1 connected 0-5460
65b0adb4eff27a10da294617191c9671c92ecda2 192.168.54.130:7006@17006 slave adaa7037a4e4af584b802e97b9bccc9c4036a3a4 0 1629899872084 6 connected
8f7cd22e6f24dbb0740eee4a77ef0943187bfc2b 192.168.54.130:7005@17005 slave 3501d50aa5cc704c0e6401ba0685fe4e9541cdb2 0 1629899872000 5 connected
adaa7037a4e4af584b802e97b9bccc9c4036a3a4 192.168.54.130:7002@17002 master - 0 1629899873598 2 connected 5461-10922
模拟对 redis-7001 宕机后查看状态
#在7005 获取 key hello不会再重定向到7001
[root@elasticsearch ~]# docker exec -it redis-7005 /bin/bash
root@4b21487f9358:/data# redis-cli -c -h 192.168.54.130 -p 7005
192.168.54.130:7005> get hello
"1"
重新启动 redis-7001 节点
密码设置
前提:无论是在redis-server 5.x版本,还是老的ruby创建集群的方式, 在create cluster的环节是不能配置redis密码的,
如果设置了密码,redis-cli --cluster create会报用户认证失败的错误
解决方法:
在搭建集群时去除所有redis节点的密码,也就是redis-cli --cluster create 的时候是没有密码参数配置的,所有在这里我们不要配置密码
① 非docker容器创建的redis容器集群可以采用以下方式
当集群配置完成后,通过config set的方式动态的为每一个节点设置密码(不需要重启redis,且重启后仍然有效)
例如:
$ redis-cli -h 127.0.0.1 -p 6379 -c
127.0.0.1:6379> config set requirepass 'password' // 设置密码
127.0.0.1:6379> config set masterauth 'password' // 设置连接密码
127.0.0.1:6379> config rewrite // 把config set 操作写入配置文件中
设置密码后连接集群
redis-cli -h 127.0.0.1 -p 6379 -c -a password
由docker容器创建的redis集群,config rewrite会报 (error) ERR Rewriting config file: Permission denied
② docker容器创建的redis集群,可以修改挂载在外面的配置文件 redis.conf 修改后重启容器
masterauth zan123456
requirepass zan123456
注意:所有节点的密码都必须一致,masterauth也要加的。
再次验证key value 的设置无异常
其他集群操作相关知识 https://www.cnblogs.com/zhoujinyi/p/11606935.html (未验证)