Docker环境下安装部署Redis Cluster

Posted by Lucky Xue on 2020-04-21

为了应对更高的QPS、更大的数据存储和更多的网络流量的需求,Redis官方提供了原生的集群模式Redis Cluster的解决方案。Redis Cluster作为分布式数据库的典型代表,对理解分布式的理论理解有很大帮助。
为了实现实现分布式存储,需要对数据分布在不同节点上。数据分布就是通过一定的分区规则,将大数据集分别存储在不同的分区。哈希分布存在数据分散度高、键值分布与业务无关、无法顺序访问、无法批量操作等特点,典型的产品如一致性哈希Memcache和Redis Cluster等;顺序分布存在数据分散度易倾斜、键值业务相关、可顺序访问和支持批量操作等特点,典型的产品如HBase等。

原生命令安装-理解架构

第一步:创建redis容器服务
第二步:各个redis容器握手
第三步:各个redis容器分配Hash槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 端口
port 7001
# 是否是守护进程
daemonize no
# 存放的目录
dir ./
# 日志名称
logfile "7001.log"
# RDB文件名称
dbfilename "dump-7001.rdb"
# 开启集群模式
cluster-enabled yes
# 集群配置文件
cluster-config-file nodes-7001.conf
# 集群中所有节点都可用则系统可用
cluster-require-full-coverage no

# 快速复制生成其他节点的配置文件
sed 's/7001/7002/g' redis-7001.conf > redis-7002.conf

# 7001节点与7002节点握手meet
redis-cli -p 7001 cluster meet 127.0.0.1 7002

# 7001节点分配0号槽
redis-cli -p 7001 cluster addslot 0

创建Redis Cluster容器服务

编写Dockerfile文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#基础镜像
FROM redis
#修复时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
#环境变量
ENV REDIS_PORT 7000
#ENV REDIS_PORT_NODE 17000
#暴露变量
EXPOSE $REDIS_PORT
#EXPOSE $REDIS_PORT_NODE
#复制
COPY entrypoint.sh /usr/local/bin/
COPY redis.conf /usr/local/etc/
#for config rewrite
RUN chmod 777 /usr/local/etc/redis.conf
RUN chmod +x /usr/local/bin/entrypoint.sh
#入口
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
#命令
CMD ["redis-server", "/usr/local/etc/redis.conf"]

编写entrypoint.sh文件

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
#只作用于当前进程,不作用于其创建的子进程
set -e
#$0--Shell本身的文件名 $1--第一个参数 $@--所有参数列表
# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
sed -i 's/REDIS_PORT/'$REDIS_PORT'/g' /usr/local/etc/redis.conf
chown -R redis . #改变当前文件所有者
exec gosu redis "$0" "$@" #gosu是sudo轻量级”替代品”
fi

exec "$@"

编写Redis通用配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
#端口
port REDIS_PORT
#开启集群
cluster-enabled yes
#配置文件
cluster-config-file nodes.conf
cluster-node-timeout 5000
#更新操作后进行日志记录
appendonly yes
#设置主服务的连接密码
# masterauth
#设置从服务的连接密码
# requirepass

注意:
requirepass和masterauth不能启用,否则redis-trib创建集群失败。
protected-mode 保护模式是禁止公网访问,但是不能设置密码和bind ip。
以上编写了3个文件,其实可以创建镜像了,不过也可以在docker-compose中自动创建。

编写docker-compose.yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
version: '3'

services:
redis1:
build: ./
volumes:
- ./redis/7001/data:/data
environment:
- REDIS_PORT=7001
ports:
- '7001:7001' #服务端口
- '17001:17001' #集群端口

redis2:
build: ./
volumes:
- ./redis/7002/data:/data
environment:
- REDIS_PORT=7002
ports:
- '7002:7002'
- '17002:17002'

redis3:
build: ./
volumes:
- ./redis/7003/data:/data
environment:
- REDIS_PORT=7003
ports:
- '7003:7003'
- '17003:17003'

redis4:
build: ./
volumes:
- ./redis/7004/data:/data
environment:
- REDIS_PORT=7004
ports:
- '7004:7004'
- '17004:17004'

redis5:
build: ./
volumes:
- ./redis/7005/data:/data
environment:
- REDIS_PORT=7005
ports:
- '7005:7005'
- '17005:17005'

redis6:
build: ./
volumes:
- ./redis/7006/data:/data
environment:
- REDIS_PORT=7006
ports:
- '7006:7006'
- '17006:17006'

Mac上宿主机访问Docker容器的服务

根据上一篇文章,我们知道在Mac上由于没有docker0端口,宿主机是没法直接ping容器的ip地址的,但是我们现在需要引用第三方封装好的服务对我们上面建立的6个redis容器进行hash槽分片,并且建立好3主3从的依赖关系,所以我们还是需要通过代理方式来实现网络互通。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 查看docker容器现有的网络列表
docker network ls

NETWORK ID NAME DRIVER SCOPE
1709e94caf34 bridge bridge local
35b8c1f86000 docker-mac-network_default bridge local
6b0d41370c4e host host local
1a8b3bce27bc none null local
a0516e13c024 redis_cluster_default bridge local
c062d641ba3b redis_sentinel_bridge_default bridge local

# 查看新建的redis_cluster网络情况,由于输出太长这里就不完整展示,只展示网关情况
docker inspect redis_cluster_default

"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]

# 修改上一篇中我们创建的docker-mac-network文件夹中VPN配置文件docker-for-mac.ovpn
# 在配置文件的底部新增一行

route 172.20.0.0 255.240.0.0

# 然后在ping一下redis_cluster集群中的任意一节点的ip地址

ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: icmp_seq=0 ttl=63 time=2.072 ms

引用封装好的容器进行Hash槽分片

设置了3个Master,3个Slave

1
docker run --rm -it inem0o/redis-trib create --replicas 1 172.20.0.1:7001 172.20.0.1:7002 172.20.0.1:7003 172.20.0.1:7004 172.20.0.1:7005 172.20.0.1:7006
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
172.20.0.1:7001
172.20.0.1:7002
172.20.0.1:7003
Adding replica 172.20.0.1:7004 to 172.20.0.1:7001
Adding replica 172.20.0.1:7005 to 172.20.0.1:7002
Adding replica 172.20.0.1:7006 to 172.20.0.1:7003
M: f8ffc3ab409a4e4a106afbb3014f1fdf7926f005 172.20.0.1:7001
slots:0-5460 (5461 slots) master
M: 2b26fc43942aec8bfe4e40065ff95883ba65460b 172.20.0.1:7002
slots:5461-10922 (5462 slots) master
M: 82bb8588cf9eb97d1523dca6bc3e9a5177cd8893 172.20.0.1:7003
slots:10923-16383 (5461 slots) master
S: 04456ac87241aee205f1be464604c4e5ca797c3e 172.20.0.1:7004
replicates f8ffc3ab409a4e4a106afbb3014f1fdf7926f005
S: 76e9e147726b431fd99a61b4c08c4d804280f7f0 172.20.0.1:7005
replicates 2b26fc43942aec8bfe4e40065ff95883ba65460b
S: 614b17ef2a2f66bc1423743c43efb77f6b8d9417 172.20.0.1:7006
replicates 82bb8588cf9eb97d1523dca6bc3e9a5177cd8893
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
>>> Performing Cluster Check (using node 172.20.0.1:7001)
M: f8ffc3ab409a4e4a106afbb3014f1fdf7926f005 172.20.0.1:7001
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: 614b17ef2a2f66bc1423743c43efb77f6b8d9417 172.20.0.1:7006@17006
slots: (0 slots) slave
replicates 82bb8588cf9eb97d1523dca6bc3e9a5177cd8893
M: 82bb8588cf9eb97d1523dca6bc3e9a5177cd8893 172.20.0.1:7003@17003
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: 04456ac87241aee205f1be464604c4e5ca797c3e 172.20.0.1:7004@17004
slots: (0 slots) slave
replicates f8ffc3ab409a4e4a106afbb3014f1fdf7926f005
S: 76e9e147726b431fd99a61b4c08c4d804280f7f0 172.20.0.1:7005@17005
slots: (0 slots) slave
replicates 2b26fc43942aec8bfe4e40065ff95883ba65460b
M: 2b26fc43942aec8bfe4e40065ff95883ba65460b 172.20.0.1:7002@17002
slots:5461-10922 (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...

验证Redis Cluster集群创建成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 登录到其中一条cluster节点上
docker exec -it redis_cluster_redis1_1 redis-cli -c -h 127.0.0.1 -p 7001
# 查看cluster集群的基本信息
cluster info
# 可以看到cluster集群运行状态OK,3个主节点,3个从节点,16384个槽位全部分配

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

# 查看节点的握手情况

127.0.0.1:7001> cluster nodes
614b17ef2a2f66bc1423743c43efb77f6b8d9417 172.20.0.1:7006@17006 slave 82bb8588cf9eb97d1523dca6bc3e9a5177cd8893 0 1587880284000 6 connected
82bb8588cf9eb97d1523dca6bc3e9a5177cd8893 172.20.0.1:7003@17003 master - 0 1587880285284 3 connected 10923-16383
f8ffc3ab409a4e4a106afbb3014f1fdf7926f005 172.20.0.2:7001@17001 myself,master - 0 1587880283000 1 connected 0-5460
04456ac87241aee205f1be464604c4e5ca797c3e 172.20.0.1:7004@17004 slave f8ffc3ab409a4e4a106afbb3014f1fdf7926f005 0 1587880285590 4 connected
76e9e147726b431fd99a61b4c08c4d804280f7f0 172.20.0.1:7005@17005 slave 2b26fc43942aec8bfe4e40065ff95883ba65460b 0 1587880284258 5 connected
2b26fc43942aec8bfe4e40065ff95883ba65460b 172.20.0.1:7002@17002 master - 0 1587880284257 2 connected 5461-10922

# 查看槽的分布情况

127.0.0.1:7001> cluster nodes

# 向集群中的7001节点存储数据,cluster集群对数据进行hash分片自动存放到7002节点的槽位区间中
# 集群自动重定向,然后就可以获取存储的数据了

127.0.0.1:7001> keys *
(empty list or set)
127.0.0.1:7001> set name hancaihaoyun
-> Redirected to slot [5798] located at 172.20.0.1:7002
OK
172.20.0.1:7002> get name
"hancaihaoyun"

Redis官方提供工具安装

JedisCluster使用

1
2
3
4
5
6
7
8
Set<HostAndPort> nodeList = new HashSet<HostAndPort>();
nodeList.add(new HostAndPort(host1, port1));
nodeList.add(new HostAndPort(host2, port2));
nodeList.add(new HostAndPort(host3, port3));
nodeList.add(new HostAndPort(host4, port4));
nodeList.add(new HostAndPort(host5, port5));
nodeList.add(new HostAndPort(host6, port6));
JedisCluster redisCluster = new JedisCluster(nodeList, timeout, poolConfig);

使用技巧

单例:内置了所有节点的连接池
无需手动借还连接池
合理设置commons-pool

参考链接

Redis-Cluster集群
Docker方式部署redis-cluster
Docker-compose redis cluster

关注【憨才好运】微信公众号,了解更多精彩内容⬇️⬇️⬇️

continuous_deployment