Redis Cluster与Codis的选择
一、Codis
1.1 Codis是什么
Codis 是 Wandoujia Infrastructure Team 开发的一个分布式 Redis 服务, 用户可以看成是一个无限内存的 Redis 服务, 有动态扩/缩容的能力. 对偏存储型的业务更实用, 如果你需要 SUBPUB 之类的指令, Codis 是不支持的. 时刻记住 Codis 是一个分布式存储的项目. 对于海量的 key, value不太大( <= 1M ), 随着业务扩展缓存也要随之扩展的业务场景有特效。
1.2 Codis的优势
Redis获得动态扩容/缩容的能力,增减redis实例对client完全透明、不需要重启服务,不需要业务方担心 Redis 内存爆掉的问题. 也不用担心申请太大, 造成浪费. 业务方也不需要自己维护 Redis.
Codis支持水平扩容/缩容,扩容可以直接界面的 “Auto Rebalance” 按钮,缩容只需要将要下线的实例拥有的slot迁移到其它实例,然后在界面上删除下线的group即可。
1.3 Codis的组件
Codis 3.x 由以下组件组成:
- Codis Server:基于 redis-3.2.8 分支开发。增加了额外的数据结构,以支持 slot 有关的操作以及数据迁移指令。
- Codis Proxy:客户端连接的 Redis 代理服务, 实现了 Redis 协议。 除部分命令不支持以外,表现的和原生的 Redis 没有区别(就像 Twemproxy)。
- 对于同一个业务集群而言,可以同时部署多个 codis-proxy 实例;
- 不同 codis-proxy 之间由 codis-dashboard 保证状态同步。
- Codis Dashboard:集群管理工具,支持 codis-proxy、codis-server 的添加、删除,以及据迁移等操作。在集群状态发生改变时,codis-dashboard 维护集群下所有 codis-proxy 的状态的一致性。
- 对于同一个业务集群而言,同一个时刻 codis-dashboard 只能有 0个或者1个;
- 所有对集群的修改都必须通过 codis-dashboard 完成。
- Codis Admin:集群管理的命令行工具。
- 可用于控制 codis-proxy、codis-dashboard 状态以及访问外部存储。
- Codis FE:集群管理界面。
- 多个集群实例共享可以共享同一个前端展示页面;
- 通过配置文件管理后端 codis-dashboard 列表,配置文件可自动更新。
- Storage:为集群状态提供外部存储。
- 提供 Namespace 概念,不同集群的会按照不同 product name 进行组织;
- 目前仅提供了 Zookeeper、Etcd、Fs 三种实现,但是提供了抽象的 interface 可自行扩展。
1.4 Codis是如何分片的?
Codis 采用 Pre-sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个key来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024。
每一个 slot 都会有一个且必须有一个特定的 server group id 来表示这个 slot 的数据由哪个 server group 来提供。数据的迁移也是以slot为单位的。
二、Redis Cluster
redis cluster 是redis官方提供的分布式解决方案,在3.0版本后推出的,有效地解决了redis分布式的需求,当一个redis节点挂了可以快速的切换到另一个节点。当遇到单机内存、并发等瓶颈时,可以采用分布式方案要解决问题。
2.1 redis集群数据分片
以下内容翻译自redis官网文档:
Cluster不使用一致的哈希,而是使用一种不同形式的分片,其中每个键从概念上讲都是我们称为哈希槽的一部分。
Redis集群中有16384个哈希槽,要计算给定密钥的哈希槽,我们只需对密钥的CRC16取模16384。
Redis群集中的每个节点都负责哈希槽的子集,因此,例如,您可能有一个包含3个节点的群集,其中:
- 节点A包含从0到5500的哈希槽。
- 节点B包含从5501到11000的哈希槽。
- 节点C包含从11001到16383的哈希槽。
这样可以轻松添加和删除集群中的节点。例如,如果我想添加一个新节点D,则需要将一些哈希槽从节点A,B,C移到D。类似地,如果我想从群集中删除节点A,则只需移动A所服务的哈希槽到B和C。当节点A为空时,我可以将其从群集中完全删除。
因为将哈希槽从一个节点移动到另一个节点不需要停止操作,所以添加和删除节点或更改节点持有的哈希槽的百分比不需要任何停机时间。
2.2 redis集群的主从模型(高可用)
- 一个集群里面有M1、M2、M3三个节点,其中节点 M1包含 0 到 5500号哈希槽,节点M2包含5501 到 11000 号哈希槽,节点M3包含11001 到 16384号哈希槽。如果M2宕掉了,就会导致5501 到 11000 号哈希槽不可用,从而使整个集群不可用。
- 一个集群里面有M1-S1、M2-S2、M3-S3六个主从节点,其中节点 M1包含 0 到 5500号哈希槽,节点M2包含5501 到 11000 号哈希槽,节点M3包含11001 到 16384号哈希槽。如果是M2宕掉,集群便会选举S2为新节点继续服务,整个集群还会正常运行。当M2、S2都宕掉了,这时候集群就不可用了。
redis集群至少需要一个备份节点,才能更好的保证集群的高可用。
2.3 集群的一致性保证
Redis Cluster无法保证强一致性。实际上,这意味着在某些情况下,Redis Cluster可能会丢失系统认可给客户端的写入。Redis Cluster可能丢失写入的第一个原因是因为它使用异步复制。
可能的异常情况:
- 您的客户写信给主B。
- 主B向您的客户答复“确定”。
- 主机B将写操作传播到其从机B1,B2和B3。
B在回复客户端之前不会等待B1,B2,B3的确认,因为这会对Redis造成延迟性的延迟,因此,如果您的客户端写了一些东西,B会确认写,但是在崩溃之前崩溃由于能够将写操作发送到其从属服务器,因此一个从属服务器(未接收到写操作)可以升级为主服务器,从而永远丢失该写操作。
2.4 关于集群的一些配置
- cluster-enabled:如果yes,则在特定的Redis实例中启用Redis Cluster支持。否则,该实例将像往常一样作为独立实例启动。
- cluster-config-file:请注意,尽管有此选项的名称,但它不是用户可编辑的配置文件,而是Redis Cluster节点每次发生更改时都会自动持久保存集群配置的文件(状态,基本上是状态),为了能够在启动时重新阅读它。该文件列出了诸如群集中其他节点之类的内容,它们的状态,持久变量等等。通常,由于收到某些消息,此文件将被重写并刷新到磁盘上。
- cluster-node-timeout:Redis群集节点不可用的最长时间(不将其视为失败)。如果主节点无法访问的时间超过指定的时间长度,则它的从节点将对其进行故障转移。此参数控制Redis Cluster中的其他重要事项。值得注意的是,在指定的时间内无法到达大多数主节点的每个节点都将停止接受查询。
- cluster-slave-validity-factor:如果设置为零,则从服务器将始终尝试对主服务器进行故障转移,而不管主服务器和从服务器之间的链接保持断开状态的时间长短。如果该值为正,则将最大断开时间计算为节点超时值乘以此选项提供的系数,如果节点是从节点,则如果断开主链接的时间超过指定的时间,它将不会尝试启动故障转移。例如,如果节点超时设置为5秒,而有效性因子设置为10,则从服务器与主服务器断开连接超过50秒将不会尝试对其主服务器进行故障转移。请注意,如果没有从属能够对其进行故障转移,则任何非零的值都可能导致Redis群集在主服务器发生故障后不可用。在这种情况下,只有当原始主服务器重新加入集群后,集群才会返回可用状态。
- cluster-migration-barrier:一个主机将保持连接的最小数量的从机,以便另一个从机迁移到不再被任何从机覆盖的主机。有关更多信息,请参见本教程中有关副本迁移的相应部分。
- cluster-require-full-coverage:如果设置为yes,默认情况下,如果某个节点未覆盖一定比例的密钥空间,集群将停止接受写入。如果该选项设置为no,即使仅可以处理有关密钥子集的请求,群集仍将提供查询。
三、关于Codis与Redis Cluster的比较
|
Codis |
Redis Cluster |
数据库数量 |
16 |
1 |
Redis版本 |
3.2.8分支开发 |
5.0.6 |
不支持的命令 |
KEYS等 |
跨节点multi-key命令 |
可视化客户端 |
无 |
有 |
集群结构 |
代理 类中心化结构 集群管理层与存储层 解耦 |
P2P模型 Gossip协议 去中心化 |
哈希槽 |
1024 |
16384 |
主从复制 |
不负责 |
负责 |
升级 |
后续升级无法保证 |
Redis官方推出,后续升级可保证 |
事务支持 |
不支持 |
支持 |
选择Redis Cluster的场景:
- 需要redis的新特性,例如:Stream
- 需要更丰富的命令支持
- 资源紧张
选择Codis的场景:
- Codis支持的命令可满足需求
- 资源充裕
- 强调可靠性
考虑到我们公司的需求,采用Redis cluster集群搭建,采用redis Stream来提升性能。