Redis 集群

1、redis集群形式

1)、数据分区方案

①、客户端分区

Redis 集群_第1张图片

客户端分区方案的代表为 Redis Sharding,Redis Sharding是Redis Cluster出来之前,业界普遍使用的Redis多实例集群方法。Java的Redis客户端驱动库Jedis,支持Redis Sharding功能,即ShardingJedis 以及结合缓存池的ShardingJedisPool.

优点:

不使用第三方中间件,分区逻辑可控,配置简单,节点之间无关联,容易线性扩展,灵活性强。

缺点:

客户端无法动态增删服务节点,客户端需要自行维护分发逻辑,客户端之间无连接共享,会造成连接浪费。

②、代理分区

Redis 集群_第2张图片

 

代理分区常用方案有Twemproxy 和 Codis.

③、redis-cluster

2)、高可用方式

①、Sentinel(哨兵机制) 支持高可用

前面介绍了主从机制,但是从运维角度来看,主节点出现了问题我们还需要通过人工干预的方式把从节点设为主节点,还要通知应用程序更新主节点地址,这种方式非常繁琐笨重,而且主节点的读写能力都十分有限,有没有较好的办法解决这两个问题,哨兵机制就是针对第一个问题的有效解决方案;第二个问题则有赖于集群!哨兵的作用就是监控Redis系统的运行情况,其功能主要是包含以下三个;

  • 监控(Monitoring);哨兵(sentinel)会不断地检查你的Master和Slave是否运作正常。
  • 提醒(Notification);当被监控的某个Redis出现问题时,哨兵(sentinel)可以通过API向管理员或者其他应用程序发送通知。
  • 自动故障迁移(Automatic failover);当主数据库出现故障时自动将从数据库转换为主数据库

Redis 集群_第3张图片

 

哨兵的原理

Redis哨兵的三个定时任务,Redis哨兵判定一个Redis节点故障不可达主要就是通过三个定时监控任务来完成的;

  • 每隔10秒每个哨兵节点会向主节点和主从节点发送"info replication"命令来获取最新的拓扑结构

Redis 集群_第4张图片

 

  • 每隔2秒每个哨兵节点会向Redis节点的_sentinel_:hello频道发送自己对主节点是否故障的判断以及自身的节点信息,并且其他的哨兵节点也会订阅这个频道来了解其他哨兵节点的信息以及对主节点的判断
  • 每隔1秒每个哨兵会向主节点、从节点、其他的哨兵节点发送一个"ping"命令来做心跳检测

Redis 集群_第5张图片

 

如果在定时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 集群_第6张图片

 

Redis集群的功能限制;Redis集群相对单机在功能上存在一些限制,需要 开发人员提前了解,在使用时做好规避。Java CRC16 校验算法 https://www.jianshu.com/p/88a32b64273c

  • key批量操作支持有限。

类似mset、mget操作,目前只支持对具有相同slot值的key执行批量操作。对于映射为不同slot值的key由于执行mget、mset等操作可能存在于多个节点上,因此不被支持。

  • key事务操作支持有限

只支持多key在同一节点上的事务操作,当多个key分布在不同的节点上时无法使用事务功能

  • key作为数据分区的最小粒度
  • 不能将一个大的键值对象如hash、list等映射到不同节点。
  • 不支持多数据库空间

单机下的Redis可以支持16个数据库(db0~db1),集群模式下只能使用一个数据空间,即db0

  • 复制结构只支持一层

从节点只能复制主节点,不支持嵌套树状复制结构。

  • 命令大多会重定向,耗时多

Redis 集群_第7张图片

 

2)、一致性hash

一致性哈希可以很好的解决稳定性问题,可以将所有的存储节点排列在首位相接的Hash环上,每个key在计算后会顺时针找到临接的存储节点存放。而当有节点加入或退出时,仅影响该节点在Hash环上顺时针相邻的后续节点。

Redis 集群_第8张图片

 

Hash倾斜

如果节点很少,容易出现倾斜、负载不均衡问题。一致性哈希算法,引入了虚拟节点、在整个环上,均衡增加若干个节点。比如a1,a2,b1,b2,c1,c2; a1和a2都是属于A节点的。解决Hash倾斜问题

3、部署Cluster

1)、创建6个Redis节点

3主3从方式,从为了同步备份,主进行slot分片

Redis 集群_第9张图片

 

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 设置一个副本

输出

Redis 集群_第10张图片

#指定某个节点连接 -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> 

 

Redis 集群_第11张图片

查询集群状态
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 宕机后查看状态

Redis 集群_第12张图片

#在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 (未验证)

你可能感兴趣的:(运维,redis,数据库)