Redis Cluster集群

Posted by Chenyawei on 2020-01-23
Words 2k and Reading Time 7 Minutes
Viewed Times

1、Redis Cluster简介

Redis cluster是Redis的分布式解决方案。分布式环境下,不会还使用单点的redis,做到高可用和容灾,起码也是redis主从。redis的单线程工作,一台物理机只运行一个redis实例太过浪费,redis单机显然是存在单点故障的隐患。内存资源往往受限,纵向不停扩展内存并不是很实际,因此横向可伸缩扩展,需要多台主机协同提供服务,即分布式下多个Redis实例协同运行。

Redis Cluster目标

  1. 高性能
  2. 线性扩容
  3. 高可用

引入集群

问题:

  • 容量不够,redis 如何进行扩容?

  • 并发写操作, redis 如何分摊?

  • 什么是集群:

    Redis 集群实现了对 Redis 的水平扩容,即启动 N 个 redis 节点,将整个数据库分布存储在这 N 个节点中,每个节点存储总数据的 1/N。

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

2、创建集群

2.1 安装Ruby环境

本身 redis 集群的安装是很麻烦了,通过 ruby 工具,可以非常方便的将一系列命令打包为一个脚本!

(1)无网环境(CentOS6)

依次执行在安装光盘下的 Package 目录(/media/CentOS_6.8_Final/Packages)下的 rpm 包:

1
2
3
4
5
6
rpm -ivh compat-readline5-5.2-17.1.el6.x86_64.rpm 
rpm -ivh ruby-libs-1.8.7.374-4.el6_6.x86_64.rpm
rpm -ivh ruby-1.8.7.374-4.el6_6.x86_64.rpm
rpm -ivh ruby-irb-1.8.7.374-4.el6_6.x86_64.rpm
rpm -ivh ruby-rdoc-1.8.7.374-4.el6_6.x86_64.rpm
rpm -ivh rubygems-1.3.7-5.el6.noarch.rpm

(2)无网环境(CentOS7)

进入 Package 目录(/run/media/root/CentOS 7 x86_64/Packages),拷贝如下安装包到独立目录 rpmruby

image-20200123101101076

进入此目录运行如下命令,按照依赖安装

rpm -Uvh *.rpm —nodeps —force

(3)联网环境

在联网状态下,执行 yum 安装,执行 yum -y install ruby;

之后安装 rubygem,rubygem 是 ruby 的包管理框架。yum -y install rubygems

2.2 安装 redis gem

redis-3.2.0.gem 是一个通过 ruby 操作 redis 的插件!

拷贝 redis-3.2.0.gem 到/opt 目录下,在 opt 目录下执行 gem install —local redis-3.2.0.gem;

2.3 制作6个redis 配置文件

端口号分别是:6379,6380,6381,6389,6390,6391

注意:每个配置文件中需要指定

1
2
3
4
5
6
7
8
9
daemonize yes: 服务在后台运行 
port:端口号
pidfile:pid 保存文件
logfile:日志文件(如果没有指定的话,就不需要)
dump.rdb: RDB 备份文件的名称
appendonly 关掉,或者是更改 appendonly 文件的名称。
cluster-enabled yes 打开集群模式
cluster-config-file nodes-6379.conf 设定节点配置文件名
cluster-node-timeout 15000 设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换。

样例:

1
2
3
4
5
6
7
include /usr/local/myredis/rediscluster/redis_base.conf 
pidfile "/var/run/redis_6379.pid"
port 6379
dbfilename "dump_6379.rdb"
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000

注意在创建集群的时候,初始化的时候,把所有节点的 dump 文件全部删掉。

2.4 开启集群

  • 首先依次启动 6 个节点,启动后,会在当前文件夹生成 nodes-xxxx.conf 文件

image-20200123101702935

  • 配置集群

    在/opt/redis-3.2.5/src 目录下,执行命令:

    1
    ./redis-trib.rb create --replicas 1 192.168.31.211:6379 192.168.31.211:6380 192.168.31.211:6381 192.168.31.211:6389 192.168.31.211:6390 192.168.31.211:6391

    注意,此处不要用 127.0.0.1,请用真实 IP 地址!

    image-20200123101837045

    image-20200123101845271

  • 之后登录到客户端,通过 cluster nodes 命令查看集群信息

    image-20200123101925666

  • 6 个节点,为什么是三主三从?

    配置机器,至少需要 6 个节点,否则会报错:

    image-20200123102009597

    命令 create,代表创建一个集群。参数—replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。一个集群至少要有三个主节点,分配原则尽量保证每个主数据库运行在不同的 IP 地址,每个从库和主库不在一个 IP 地 址上。

2.5 slot 插槽

进入集群后,如果我们,直接写入数据,可能会看到报错信息:

image-20200123102124264

这是因为,集群中多了 slot(插槽)的设计。一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个 键都属于这 16384 个插槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。

集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:

  • 节点 A 负责处理 0 号至 5500 号插槽。
  • 节点 B 负责处理 5501 号至 11000 号插槽。
  • 节点 C 负责处理 11001 号至 16383 号插槽。

2.6 集群中写入数据

2.6.1 客户端重定向

  • 在 redis-cli 每次录入、查询键值,redis 都会计算出该 key 应该送往的插槽,如果不是该客户端对应服务器插槽redis 会报错,并告知应前往的 redis 实例地址和端口。

  • redis-cli 客户端提供了 –c 参数实现自动重定向。如 redis-cli -c –p 6379 登入后,再录入、查询键值对可以自动重定向。

    image-20200123102522197

  • 每个 slot 可以存储一批键值对。

2.6.2 如何多键操作

采用哈希算法后,会自动地分配 slot,而不在一个 slot 下的键值,是不能使用 mget,mset 等多键操作。

image-20200123102613541

如果有需求,需要将一批业务数据一起插入呢?

解决:可以通过{}来定义组的概念,从而使 key 中{}内相同内容的键值对放到一个 slot 中去。

image-20200123102710350

2.7 集群中读取数据

  • CLUSTER KEYSLOT 计算键 key 应该被放置在哪个槽上

    image-20200123103031392

  • CLUSTER COUNTKEYSINSLOT 返回槽 slot 目前包含的键值对数量

    image-20200123103022753

  • CLUSTER KEYSLOT :计算 key 应该放在哪个槽

    image-20200123103015499

  • CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。

    image-20200123103007786

2.8 集群中故障恢复

问题 1:如果主节点下线?从节点能否自动升为主节点?

答:主节点下线,从节点自动升为主节点。

image-20200123103153385

image-20200123103203503

问题 2:主节点恢复后,主从关系会如何?

主节点恢复后,主节点变为从节点!

image-20200123103230091

问题 3:如果所有某一段插槽的主从节点都宕掉,redis 服务是否还能继续?

答:服务是否继续,可以通过 redis.conf 中的 cluster-require-full-coverage 参数进行控制。

​ 主从都宕掉,意味着有一片数据,会变成真空,没法再访问了!

​ 如果无法访问的数据,是连续的业务数据,我们需要停止集群,避免缺少此部分数据,造成整个业务的异常。此时可以通过配置 cluster-require-full-coverage 为 yes.

​ 如果无法访问的数据,是相对独立的,对于其他业务的访问,并不影响,那么可以继续开启集群体提供服务。此时,可以配置 cluster-require-full-coverage 为 no。

2.9 集群的Jedis开发

1
2
3
4
5
6
7
8
@Test
public void testCluster(){
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
//Jedis Cluster will attempt to discover cluster nodes automatically
jedisClusterNodes.add(new HostAndPort("192.168.4.128", 6379));
JedisCluster jc = new JedisCluster(jedisClusterNodes);
jc.set("foo", "bar"); String value = jc.get("foo");
}

2.10 集群的优缺点

优点:

  • 实现扩容
  • 分摊压力
  • 无中心配置相对简单

缺点:

  • 多键操作是不被支持的
  • 多键的 Redis 事务是不被支持的。lua 脚本不被支持。
  • 由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至 redis cluster,需要整体迁移而不是逐步过渡,复杂度较大。

notice

欢迎访问 chenyawei 的博客, 若有问题或者有好的建议欢迎留言,笔者看到之后会及时回复。 评论点赞需要github账号登录,如果没有账号的话请点击 github 注册, 谢谢 !

If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !