redis集群

为什么要用redis集群?

  • 1.容量内存不够,redis如何进行扩容?
  • 2.并发写操作,redis如何分摊?

什么是集群?

  • 1.redis集群实现了对redis的水平扩容
    即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数的1/N。(降低内存压力,避免一台服务器写入爆掉内存)

  • 2.redis集群通过分区(partition)来提供一定程度的可用性
    即集群中有一部分节点失效或者无法通讯集群也可以继续处理命令请求。

集群通信原理

redis 集群采用 Gossip(流言)协议,Gossip 协议工作原理就是节点彼此不断交换信息,
一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播。

  • 通信过程:
    • 1.集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信,防火墙放行(端口号+10000).
    • 2.每个节点在固定周期内通过特定规则选择结构节点发送 ping 消息
    • 3.接收到 ping 消息的节点用 pong 消息作为响应。集群中每个节点通过一定规则挑选要通信的节点,
      每个节点可能知道全部节点也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会达成
      一致的状态,当节点出现故障,新节点加入,主从角色变化等,它能够给不断的ping/pong消息,从而达
      到同步目的。

redis官方集群安装配置

手动安装

文件架构

1
2
3
4
5
6
7
8
9
10
11
cluster-test/
├── conf
│ ├── redis6379.conf
│ ├── redis6380.conf
│ ├── redis6381.conf
│ ├── redis6382.conf
│ ├── redis6383.conf
│ └── redis6384.conf
├── data
├── logs
└── scripts

编辑conf文件

1
2
3
4
5
6
7
8
9
10
port 6379
daemonize yes
dir "/opt/software/redis/cluster-test/data"
logfile "/opt/software/redis/cluster-test/logs/6379.log"
#dbfilename不能配置为路径
dbfilename "dump-6379.rdb"
cluster-enabled yes
cluster-config-file nodes-6379.conf
#是否需要每个节点都可用,集群才算可用,关闭
cluster-require-full-coverage no

使用命令复制修改文件

1
sed "s/7000/7001/g" redis-7000.conf >redis-7001.conf

启动和槽分配

启动集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
redis-server redis63...conf

# 查看槽信息
redis-cli -p 6379 cluster slots
# 查看节点信息
redis-cli -p 6379 cluster nodes
# 查看集群点信息
redis-cli -p 6379 cluster info

# 节点会晤(把节点联系到一起)
redis-cli -p 6379 cluster meet 127.0.0.1 6380

# 设置副本
redis-cli -p 6379 cluster nodes # 查看id
# 把3个分配为从节点
redis-cli -p 6379 cluster replicate id

分配槽

  • 编写shell脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    1 start=$1
    2 end=$2
    3 port=$3
    4
    5 for slot in `seq ${start} ${end}`
    6 do
    7 echo "slot:${slot}"
    8 redis-cli -p ${port} cluster addslots ${slot}
    9 done
  • 调用脚本分配节点

    1
    2
    3
    4
    chmod 777 addslots.sh
    ./addslots.sh 0 5461 6379
    ./addslots.sh 5461 10922 6380
    ./addslots.sh 10922 16383 6381
  • 查看是否集群成功

    1
    2
    3
    4
    5
    6
    7
    8
    redis-cli -p 6379 cluster info

    # 进入集群节点进行测试
    redis-cli -c -p 6379
    127.0.0.1:6379> set k1 21
    -> Redirected to slot [12706] located at 127.0.0.1:6380
    OK

    关闭之后下次启动还可以是集群状态,因为信息已经持久化到dump文件里面,也就是data目录下存放的dump

使用 redis-trib.rb工具安装

注意:redis5.0.5以上不需要ruby环境,创建集群已经不用redis-trib.rb这个脚本,
而是使用自带的redis-cli创建,大致可以看下链接这个大概要淘汰掉了。

工具安装

  • 安装ruby
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    yum install zlib-devel
    wget https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.1.tar.gz
    解压到特定目录:tar -zxvf ruby-3.0.1.tar.gz -C /opt/software
    进入目录:cd /opt/software/ruby-3.0.1
    配置:./configure --prefix=/usr/local/ruby(把解压的源文件放在/usr/local/ruby)
    编译:make
    安装:make install
    进入目录:cd /usr/local/ruby
    让ruby添加到用户的访问变量中:cp bin/ruby /usr/local/bin
    让gem添加到用户的访问变量中 : cp /usr/local/ruby/bin/gem /usr/local/bin
    输入ruby -v

集群扩容和缩容

扩容

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
# 配置新节点
cp conf/redis6384.conf conf/redis6385.conf
cp conf/redis6384.conf conf/redis6386.conf
sed -i 's#6384#6385#g' conf/redis6385.conf
sed -i 's#6384#6386#g' conf/redis6386.conf

# 启动节点
redis-server redis6385
redis-server redis6386

# 集群确认节点
redis-cli -c -p 6379 cluster meet 127.0.0.1 6385
redis-cli -c -p 6379 cluster meet 127.0.0.1 6386
或者
redis-cli --cluster add-node 127.0.0.1 6385 127.0.0.1 6379
redis-cli --cluster add-node 127.0.0.1 6386 127.0.0.1 6379


# 查看id
redis-cli -c -p 6379 cluster nodes
# 分配主从
redis-cli -c -p 6386 cluster replicate 6385的id号

# 重新分配槽
redis-cli --cluster reshard 127.0.0.1 6385
按照步骤输入即可

# 平衡槽数
redis-cli --cluster rebalance 127.0.0.1 6385

# 查看节点分配
redis-cli -c -p 6379 cluster nodes

缩容

  • 1.首先需要确定下线节点是否有负责的槽,
    如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性.
  • 2.当下线节点不再负责槽或者本身是从节点时,
    就可以通知集群内其他节点忘记下线节点,当所有的节点忘记该节点后可以正常关闭.
1
2
3
4
5
6
7
8
9
10
11
# 查看要下线的节点是否有槽
redis-cli -c -p 6379 cluster nodes
# 分配下线节点的槽(用rebalance爽一点)
redis-cli --cluster reshard 127.0.0.1:6386
分配节点数:节点数/剩余主节点数
分配节点id:xxxx
需要分几次平均分配给各个节点,也可以分配后用redis-cli --cluster rebalance

# 删除节点
redis-cli --cluster del-node 192.168.1.102:6391 ID号
redis-cli --cluster del-node 192.168.1.102:6390 ID号

redis slots简介

  • 什么是slots?
    一个redis集群包含16384个插槽(hash slot),数据库中的每个键都属于这16384个插槽其中一个,集群使用公式CRC16(key)%16384来计算键key属于哪个槽,其中CRC16(key)语句用于计算键key的CRC16校验和。
    集群中每个主节点负责处理一部分插槽。举个例子,如果一个集群有3主节点,其中:
    • 节点A负责处理0号至5500号插槽
    • 节点B负责处理5501号至11000号插槽
    • 节点C负责处理11000号至16383号插槽
  • 注意:
    • 1.如果登录redis-cli不使用-c(普通客户端)如果当前计算槽点不属于该节点会报错。
    • 2.不在一个slot下的键值不能使用mget,mset等多键操作。(无法选择重定向目标)
    • 3.可以通过{}来定义组的概念,从而让set的值在一个slot中(set a{user} v, set b{user} c)
    • 4.cluster keyslot 计算键key应该被放置在哪个槽上。 cluster keyslot k1
    • 5.cluster countkeysinslot 返回槽slot目前包含的键值对数量。cluster countkeysinslot 5474
    • 6.cluster getkeysinslot 返回count个slot槽中的键。cluster getkeysinslot 5474 2
1
2
3
4
5
6
7
8
9
10
11
主节点宕机:
redis-cli –p 6381 shutdown关掉6381
通过cluster nodes查看是否slave变成了主节点
重启原主节点,变成从节点了。。。。。

如果一段slot的主从都宕机
该集群都会宕机。
redis.conf中的参数 cluster-require-full-coverage
只有当16384个slot都正常时候才能对外提供服务。
vim redis.conf
把cluster-require-full-coverage 改为no

如何判断节点宕机

如果一个节点认为另外一个节点宕机,那么就是 pfail,主观宕机。
如果多个节点都认为另外一个节点宕机了,那么就是 fail,客观宕机,
跟哨兵的原理几乎一样,sdown,odown。在 cluster-node-timeout 内,
某个节点一直没有返回 pong,那么就被认为 pfail。如果一个节点认为某个
节点 pfail 了,那么会在 gossip ping 消息中,ping 给其他节点,如果
超过半数的节点都认为 pfail 了,那么就会变成 fail。

  • 从节点过滤
    对宕机的 master node,从其所有的 slave node 中,选择一个切换成 master node。
    检查每个 slave node 与 master node 断开连接的时间,
    如果超过了 cluster-node-timeout * cluster-slave-validity-factor,
    那么就没有资格切换成 master。

  • 从节点选举
    每个从节点,都根据自己对 master 复制数据的 offset,来设置一个选举时间,
    offset 越大(复制数据越多)的从节点,选举时间越靠前,优先进行选举。
    所有的 master node 开始 slave 选举投票,给要进行选举的 slave 进行投票,
    如果大部分 master node(N/2 + 1)都投票给了某个从节点,那么选举通过,
    那个从节点可以切换成 master。
    从节点执行主备切换,从节点切换为主节点。

一致性hash集群

redis集群除了官方CRC槽计算,还可以通过一致性hash进行手工配置redis集群,
一致性hash大概就是对各个redis实例ip:port进行hash计算,然后形成一个环,
来了一个 key,首先计算 hash 值,并确定此数据在环上的位置,从此位置沿环
顺时针“行走”,遇到的第一个 master 节点就是 key 所在位置。

容灾&扩容&缩容

  • 容灾
    一个节点挂掉后,仅仅该节点上的数据受到影响,新的数据可以存入下一个节点

  • 扩容
    需要把后一个节点的数据进行重新分配,这里如果加入虚拟节点分配逻辑更为复杂

  • 缩容
    需要把该节点的数据进行重新分配到后一个节点。

  • 缺点
    不使用虚拟节点会因为节点少导致数据分配不均,出现缓存热点问题。

虚拟节点

其实就是给ip:port再生成几个虚拟的节点,比如ip:port:1, 2, 3然后hash,这个时候
计算的key如果前面是虚拟节点就存入该虚拟节点对应的真实节点。

分享到