Docker Compose部署Redis Cluster
in Docker with 0 comment

Docker Compose部署Redis Cluster

in Docker with 0 comment

1 Redis Cluster简介

1.1 节点间的内部通信机制

集群元数据的维护有两种方式:集中式、Gossip协议。redis cluster节点间采用gossip协议进行通信。

集群元数据(节点信息、故障等等)几种存储在某个节点上。集中式元数据集中存储的一个典型代表,就是大数据领域的 storm。它是分布式的大数据实时计算引擎,是集中式的元数据存储的结构,底层基于 zookeeper(分布式协调的中间件)对所有元数据进行存储维护

image.png

优缺点

  1. 优点:元数据的读取和更新,时效性非常好,一旦元数据出现了变更,就立即更新到集中式的存储中,其它节点读取的时候就可以感知到
  2. 缺点:所有的元数据的更新压力全部集中在一个地方,可能会导致元数据的存储有压力

所有节点都持有一份元数据,不同的节点如果出现了元数据的变更,就不断将元数据发送给其它的节点,让其它节点也进行元数据的变更

image.png

优缺点

  1. 优点:元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续打到所有节点上去更新,降低了压力
  2. 缺点:元数据的更新有延时,可能导致集群中的一些操作会有一些滞后

1.2 Gossip协议

Gossip协议包含多种消息,包含 ping,pong,meet,fail 等等。

redis-trib.rb add-node

其实内部就是发送了一个 gossip meet 消息给新加入的节点,通知那个节点去加入我们的集群。

1.3 分布式寻址算法

1.3.1 hash 算法

来了一个 key,首先计算 hash 值,然后对节点数取模。然后打在不同的 master 节点上。一旦某一个master节点宕机,所有请求过来,都会基于最新的剩余master节点数去取模,尝试去取数据

image.png

缺点
这会导致大部分的请求过来,全部无法拿到有效的缓存,导致大量的流量涌入数据库。

1.3.2 一致性 hash 算法

一致性 hash 算法将整个hash值空间组织成一个虚拟的圆环,整个空间按顺时针方向组织,下一步将各个 master 节点(使用服务器的 ip 或主机名)进行 hash。这样就能确定每个节点在其哈希环上的位置。

image.png

来了一个 key,首先计算 hash 值,并确定此数据在环上的位置,从此位置沿环顺时针行走,遇到的第一个 master 节点就是 key 所在位置。

在一致性哈希算法中,如果一个节点挂了,受影响的数据仅仅是此节点到环空间前一个节点(沿着逆时针方向行走遇到的第一个节点)之间的数据,其它不受影响。增加一个节点也同理。

然而,一致性哈希算法在节点太少时,容易因为节点分布不均匀而造成缓存热点的问题。为了解决这种热点问题,一致性 hash 算法引入了虚拟节点机制,即对每一个节点计算多个 hash,每个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。

1.3.3 redis cluster的hash slot算法

redis cluster 有固定的16384个hash slot,对每个key计算 CRC16 值,然后对 16384 取模,可以获取 key 对应的 hash slot。

redis cluster 中每个 master 都会持有部分slot,比如有3个 master,那么可能每个master持有5000多个hash slot。hash slot让node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去。移动hash slot的成本是非常低的。客户端的api可以对指定的数据,让他们走同一个hash slot,通过hash tag来实现。
image.png
任何一台机器宕机,另外两个节点不受影响。因为 key 找的是 hash slot,不是机器。

2 部署Redis Cluster

2.1 创建配置文件模版

cd /usr/local/docker/volumes
mkdir redis-cluster 
touch redis-cluster.tmpl
vim redis-cluster.tmpl

redis-cluster.tmpl模板

port ${PORT}
requirepass 123456
masterauth 123456
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 47.100.79.211
cluster-announce-port ${PORT}
cluster-announce-bus-port 1${PORT}

详解

命令描述
port节点端口
requirepass密码
masterauthmaster密码
cluster-enabled是否开启集群
cluster-config-file集群配置名
cluster-node-timeout集群节点超时时间
cluster-announce-ip实际为各节点网卡分配ip 先用上网关ip代替
cluster-announce-port节点映射端口
cluster-announce-bus-port节点总线端
appendonly持久化模式

2.2 创建redis配置文件

for port in `seq 6391 6396`; do \
mkdir -p ./${port}/conf \
&& PORT=${port} envsubst < ./redis-cluster.tmpl > ./${port}/conf/redis.conf \
&& mkdir -p ./${port}/data; \
done

2.3 创建docker-compose.yaml配置文件

touch docker-compose.yaml
vim docker-compose.yaml

docker-compose.yaml内容如下

version: '3'
services:
  redis-6391:
    image: redis:latest
    container_name: redis-6391
    command: redis-server /usr/local/etc/redis/redis.conf --appendonly yes
    privileged: true
    restart: always
    volumes:
      - /usr/local/docker/volumes/redis-cluster/6391/data:/data
      - /usr/local/docker/volumes/redis-cluster/6391/conf/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - 6391:6391
      - 16391:16391
  redis-6392:
    image: redis:latest
    container_name: redis-6392
    command: redis-server /usr/local/etc/redis/redis.conf --appendonly yes
    privileged: true
    restart: always
    volumes:
      - /usr/local/docker/volumes/redis-cluster/6392/data:/data
      - /usr/local/docker/volumes/redis-cluster/6392/conf/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - 6392:6392
      - 16392:16392
  redis-6393:
    image: redis:latest
    container_name: redis-6393
    command: redis-server /usr/local/etc/redis/redis.conf --appendonly yes
    privileged: true
    restart: always
    volumes:
      - /usr/local/docker/volumes/redis-cluster/6393/data:/data
      - /usr/local/docker/volumes/redis-cluster/6393/conf/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - 6393:6393
      - 16393:16393
  redis-6394:
    image: redis:latest
    container_name: redis-6394
    command: redis-server /usr/local/etc/redis/redis.conf --appendonly yes
    privileged: true
    restart: always
    volumes:
      - /usr/local/docker/volumes/redis-cluster/6394/data:/data
      - /usr/local/docker/volumes/redis-cluster/6394/conf/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - 6394:6394
      - 16394:16394
  redis-6395:
    image: redis:latest
    container_name: redis-6395
    command: redis-server /usr/local/etc/redis/redis.conf --appendonly yes
    privileged: true
    restart: always
    volumes:
      - /usr/local/docker/volumes/redis-cluster/6395/data:/data
      - /usr/local/docker/volumes/redis-cluster/6395/conf/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - 6395:6395
      - 16395:16395
  redis-6396:
    image: redis:latest
    container_name: redis-6396
    command: redis-server /usr/local/etc/redis/redis.conf --appendonly yes
    privileged: true
    restart: always
    volumes:
      - /usr/local/docker/volumes/redis-cluster/6396/data:/data
      - /usr/local/docker/volumes/redis-cluster/6396/conf/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - 6396:6396
      - 16396:16396

2.4 运行docker-compose启动redis容器

docker-compose -f docker-compose.yaml up -d

image.png

2.5 执行集群指令

docker exec -it redis-6391 bash

执行集群命令

redis-cli --cluster create 47.100.79.211:6391 47.100.79.211:6392 47.100.79.211:6393 47.100.79.211:6394 47.100.79.211:6395 47.100.79.211:6396 --cluster-replicas 1

中间需要输入yes指令,执行成功如下
image.png

2.6 验证集群

image.png

image.png