为了应对更高的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节点握手meetredis-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 rewriteRUN 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 clusterWaiting 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:7002OK 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
关注【憨才好运】微信公众号,了解更多精彩内容⬇️⬇️⬇️