切片集群
参考:
# 1. 切片集群:数据增多了,是该加内存还是加实例?
有这么一个需求:要用 Redis 保存 5000 万个键值对,每个键值对大约是 512B,为了能快速部署并对外提供服务,我们采用云主机来运行 Redis 实例,那么,该如何选择云主机的内存容量呢?
粗略计算一下,这些 KV 所占的内存空间大约为 25GB,所以第一反应是选择一台 32G 内存的云主机来部署 Redis。但在使用过程中会发现,Redis 响应有时会非常慢,这时使用 INFO 命令查看 Redis 的 latest_fork_usec 指标值(表示最近一次 fork 的耗时),结果显示这个指标值特别高,快到秒级别了。
这跟 Redis 的持久化机制有关系。在使用 RDB 进行持久化时,Redis 会 fork 子进程来完成,fork 操作的用时和 Redis 的数据量是正相关的,而 fork 在执行时会阻塞主线程。数据量越大,fork 操作造成的主线程阻塞的时间越长。所以,在使用 RDB 对 25GB 的数据进行持久化时,数据量较大,后台运行的子进程在 fork 创建时阻塞了主线程,于是就导致 Redis 响应变慢了。
看来,第一个方案显然是不可行的,我们必须要寻找其他的方案。这个时候,我们注意到了 Redis 的切片集群。虽然组建切片集群比较麻烦,但是它可以保存大量数据,而且对 Redis 主线程的阻塞影响较小。
切片集群,也叫分片集群,就是指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。回到我们刚刚的场景中,如果把 25GB 的数据平均分成 5 份(当然,也可以不做均分),使用 5 个实例来保存,每个实例只需要保存 5GB 数据。如下图所示:
那么,在切片集群中,实例在为 5GB 数据生成 RDB 时,数据量就小了很多,fork 子进程一般不会给主线程带来较长时间的阻塞。采用多个实例保存数据切片后,我们既能保存 25GB 数据,又避免了 fork 子进程阻塞主线程而导致的响应突然变慢。
在实际应用 Redis 时,随着用户或业务规模的扩展,保存大量数据的情况通常是无法避免的。而切片集群,就是一个非常好的解决方案。这节课,我们就来学习一下。
# 1.1 如何保存更多数据?
在刚刚的案例里,为了保存大量数据,我们使用了大内存云主机和切片集群两种方法。实际上,这两种方法分别对应着 Redis 应对数据量增多的两种方案:纵向扩展和横向扩展:
- 纵向扩展(scale up):升级单个 Redis 实例的资源配置,包括增加内存容量、增加磁盘容量、使用更高配置的 CPU。
- 横向扩展(scale out):横向增加当前 Redis 实例的个数。
两种方式各有优缺点:
- 纵向扩展实施简单,但持久化 RDB 文件会显著降低性能,而且会受到硬件与成本的限制。
- 横向扩展不需要担心硬件和成本的限制,但涉及到多实例的分布式管理的问题。
要想把切片集群用起来,我们就需要解决两大问题:
- 数据切片后,在多个实例之间如何分布?
- 客户端怎么确定想要访问的数据在哪个实例上?
接下来,我们就一个个地解决。
# 1.2 数据切片和实例的对应分布关系
在切片集群中,数据需要分布在不同实例上,那么,数据和实例之间如何对应呢?这就和接下来我要讲的 Redis Cluster 方案有关了。不过,我们要先弄明白切片集群和 Redis Cluster 的联系与区别。
实际上,切片集群是一种保存大量数据的通用机制,这个机制可以有不同的实现方案。在 Redis 3.0 之前,官方并没有针对切片集群提供具体的方案。从 3.0 开始,官方提供了一个名为 Redis Cluster 的方案,用于实现切片集群。Redis Cluster 方案中就规定了数据和实例的对应规则。
具体来说,Redis Cluster 方案采用哈希槽(Hash Slot,后面称为 Slot),来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个 slot 中。具体的映射过程分为两大步:
- 首先根据键值对的 key,按照 CRC16 算法 (opens new window)计算一个 16bit 的值;
- 然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的 slot。
那么,这些 slot 又是如何被映射到具体的 Redis 实例上的呢?我们在部署 Redis Cluster 方案时,可以使用 cluster create 命令创建集群,此时,Redis 会自动把这些 slot 平均分布在集群实例上。例如,如果集群中有 N 个实例,那么,每个实例上的槽个数为 16384/N 个。这也是 DDIA 中讲的数据分区方法中的固定逻辑分区的方法。
当然, 我们也可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,根据不同实例的资源情况指定每个实例上的 slot 个数。下图展示了数据、哈希槽和实例这三者的映射分布情况:
示意图中的切片集群一共有 3 个实例,同时假设有 5 个 slot,我们首先可以通过下面的命令手动分配 slot:实例 1 保存 slot 0 和 1,实例 2 保存 slot 2 和 3,实例 3 保存 slot 4。配置命令如下:
redis-cli -h 172.16.19.3 –p 6379 cluster addslots 0,1
redis-cli -h 172.16.19.4 –p 6379 cluster addslots 2,3
redis-cli -h 172.16.19.5 –p 6379 cluster addslots 4
2
3
注意:在手动分配 slot 时,需要把 16384 个 slot 都分配完,否则 Redis 集群无法正常工作。
综上,通过哈希槽,切片集群就实现了数据到哈希槽、哈希槽再到实例的分配。但是,即使实例有了哈希槽的映射信息,客户端又是怎么知道要访问的数据在哪个实例上呢?
# 1.3 客户端如何定位数据?
在定位键值对数据时,它所处的哈希槽是可以通过计算得到的,这个计算可以在客户端发送请求时来执行。但是,要进一步定位到 Redis 实例,还需要知道 slot 分布在哪个实例上。
一般来说,客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。但是,在集群刚刚创建的时候,每个实例只知道自己被分配了哪些哈希槽,是不知道其他实例拥有的哈希槽信息的。那么,客户端为什么可以在访问任何一个实例时,都能获得所有的哈希槽信息呢?这是因为,Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。
客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。但是,在集群中,实例和哈希槽的对应关系并不是一成不变的,最常见的变化有两个:
- 在集群中,实例有新增或删除,Redis 需要重新分配哈希槽;
- 为了负载均衡,Redis 需要把哈希槽在所有实例上重新分布一遍。
此时,实例之间还可以通过相互传递消息,获得最新的哈希槽分配信息,但是,客户端是无法主动感知这些变化的。这就会导致,它缓存的分配信息和最新的分配信息就不一致了,那该怎么办呢?
Redis Cluster 方案提供了一种重定向机制,所谓的“重定向”,就是指,客户端给一个实例发送数据读写操作时,如果这个实例上并没有相应的数据,实例就会想客户端返回一个如下所示的 MOVED 命令响应结果,客户端这时就要再给一个新实例发送操作命令。
GET hello:key
(error) MOVED 13320 172.16.19.5:6379
2
其中,MOVED 命令表示,客户端请求的键值对所在的哈希槽 13320,实际是在 172.16.19.5 这个实例上。通过返回的 MOVED 命令,就相当于把哈希槽所在的新实例的信息告诉给客户端了。这样一来,客户端就可以直接和 172.16.19.5 连接,并发送操作请求了。
下面用一张图来说明一下 MOVED 命令的重定向的使用方法。可以看到,由于负载均衡,Slot 2中的数据已经从实例2迁移到了实例3,但是,客户端缓存仍然记录着“Slot 2在实例2”的信息,所以会给实例2发送命令。实例2给客户端返回一条MOVED命令,把Slot 2的最新位置(也就是在实例3上),返回给客户端,客户端就会再次向实例3发送请求,同时还会更新本地缓存,把Slot 2与实例的对应关系更新过来。
需要注意的是,在上图中,当客户端给实例2发送命令时,Slot 2中的数据已经全部迁移到了实例3。在实际应用时,如果Slot 2中的数据比较多,就可能会出现一种情况:客户端向实例2发送请求,但此时,Slot 2中的数据只有一部分迁移到了实例3,还有部分数据没有迁移。在这种迁移部分完成的情况下,客户端就会收到一条 ASK 报错信息,如下所示:
GET hello:key
(error) ASK 13320 172.16.19.5:6379
2
这个结果中的 ASK 命令就表示,客户端请求的键值对所在的哈希槽 13320,在 172.16.19.5 这个实例上,但是这个哈希槽正在迁移。此时,客户端需要先给 172.16.19.5 这个实例发送一个 ASKING 命令。这个命令的意思是,让这个实例允许执行客户端接下来发送的命令。然后,客户端再向这个实例发送 GET 命令,以读取数据。
看起来好像有点复杂,我再借助图片来解释一下。在下图中,Slot 2正在从实例2往实例3迁移,key1和key2已经迁移过去,key3和key4还在实例2。客户端向实例2请求key2后,就会收到实例2返回的ASK命令。
ASK 命令表示两层含义:
- 第一,表明 slot 数据还在迁移中;
- 第二,ASK 命令把客户端所请求数据的最新实例地址返回给客户端,此时,客户端需要给实例 3 发送 ASKING 命令,然后再发送操作命令。
和 MOVED 命令不同,ASK命令并不会更新客户端缓存的哈希槽分配信息。所以,在上图中,如果客户端再次请求 slot 2 中的数据,它还是会给 实例 2 发送请求。这也就是说,ASK 命令的作用只是让客户端能给新实例发送一次请求,而不像 MOVED 命令那样,会更改本地缓存,让后续所有命令都发往新实例。
# 1.4 小结
这节课,我们学习了切片集群在保存大量数据方面的优势,以及基于哈希槽的数据分布机制和客户端定位键值对的方法。
在应对数据量扩容时,虽然增加内存这种纵向扩展的方法简单直接,但是会造成数据库的内存过大,导致性能变慢。Redis 切片集群提供了横向扩展的模式,也就是使用多个实例,并给每个实例配置一定数量的哈希槽,数据可以通过键的哈希值映射到哈希槽,再通过哈希槽分散保存到不同的实例上。这样做的好处是扩展性好,不管有多少数据,切片集群都能应对。
另外,集群的实例增减,或者是为了实现负载均衡而进行的数据重新分布,会导致哈希槽和实例的映射关系发生变化,客户端发送请求时,会收到命令执行报错信息。了解了 MOVED 和 ASK 命令,你就不会为这类报错而头疼了。
我刚刚说过,在 Redis 3.0 之前,Redis 官方并没有提供切片集群方案,但是,其实当时业界已经有了一些切片集群的方案,例如基于客户端分区的 ShardedJedis,基于代理的 Codis、Twemproxy 等。这些方案的应用早于 Redis Cluster 方案,在支撑的集群实例规模、集群稳定性、客户端友好性方面也都有着各自的优势,我会在后面的课程中,专门和你聊聊这些方案的实现机制,以及实践经验。这样一来,当你再碰到业务发展带来的数据量巨大的难题时,就可以根据这些方案的特点,选择合适的方案实现切片集群,以应对业务需求了。
本节问题:为什么Redis不直接用一个表,把键值对和实例的对应关系记录下来?
如果使用表记录键值对和实例的对应关系,一旦键值对和实例的对应关系发生了变化(例如实例有增减或者数据重新分布),就要修改表。如果是单线程操作表,那么所有操作都要串行执行,性能慢;如果是多线程操作表,就涉及到加锁开销。此外,如果数据量非常大,使用表记录键值对和实例的对应关系,需要的额外存储空间也会增加。
基于哈希槽计算时,虽然也要记录哈希槽和实例的对应关系,但是哈希槽的个数要比键值对的个数少很多,无论是修改哈希槽和实例的对应关系,还是使用额外空间存储哈希槽和实例的对应关系,都比直接记录键值对和实例的关系的开销小得多。
# 2. Codis VS Redis Cluster:我该选择哪一个集群方案?
前面学习了 Redis 官方提供的切片集群方案 Redis Cluster,但在该方案发布之前,业界已经广泛使用 Codis。这一节将讲解 Codis 的实现原理,并将两者进行对比,从而选出最佳的集群方案。
# 2.1 Codis 的整体架构和基本流程
Codis 集群中包含了 4 类关键组件:
- codis server:这是进行了二次开发的Redis实例,其中增加了额外的数据结构,支持数据迁移操作,主要负责处理具体的数据读写请求。
- codis proxy:接收客户端请求,并把请求转发给codis server。
- Zookeeper 集群:保存集群元数据,例如数据位置信息和codis proxy信息。
- codis dashboard 和 codis fe:共同组成了集群管理工具。其中,codis dashboard负责执行集群管理工作,包括增删codis server、codis proxy和进行数据迁移。而codis fe负责提供dashboard的Web操作界面,便于我们直接在Web界面上进行集群管理。
我用一张图来展示下 Codis 集群的架构和关键组件:
下面具体解释一下 Codis 是如何处理请求的:
- 首先,为了让集群能接收并处理请求,我们要先使用 codis dashboard 设置 codis server 和 codis proxy 的访问地址,完成设置后,codis server 和 codis proxy 才会开始接收连接。
- 然后,当客户端要读写数据时,客户端直接和codis proxy建立连接。codis proxy 本身支持 Redis 的 RESP 交互协议,所以客户端访问codis proxy时,和访问原生的Redis实例没有什么区别,这样一来,原本连接单实例的客户端就可以轻松地和Codis集群建立起连接了。
- 最后,codis proxy接收到请求,就会查询请求数据和codis server的映射关系,并把请求转发给相应的codis server进行处理。当codis server处理完请求后,会把结果返回给codis proxy,proxy再把数据返回给客户端。
用一张图来展示这个处理流程:
# 2.2 Codis 的关键技术原理
这里将围绕切片集群使用效果的 4 方面技术因素:数据分布、集群扩容和数据迁移、客户端兼容性、可靠性保证,来讨论它们的具体设计选择和原理。
# 2.2.1 数据如何在集群里分布?
在 Codis 集群中,一个数据应该保存在哪个codis server上,这是通过逻辑槽(Slot)映射来完成的,具体来说,总共分成两步:
- 第一步,Codis集群一共有1024个Slot,编号依次是0到1023。我们可以把这些Slot手动分配给codis server,每个server上包含一部分Slot。当然,我们也可以让codis dashboard进行自动分配,例如,dashboard把1024个Slot在所有server上均分。
- 第二步,当客户端要读写数据时,会使用CRC32算法计算数据key的哈希值,并把这个哈希值对1024取模。而取模后的值,则对应Slot的编号。此时,根据第一步分配的Slot和server对应关系,我们就可以知道数据保存在哪个server上了。
这个过程如下图所示:
数据key和Slot的映射关系是客户端在读写数据前直接通过CRC32计算得到的,而Slot和codis server的映射关系是通过分配完成的,所以就需要用一个存储系统保存下来,否则,如果集群有故障了,映射关系就会丢失。
我们把Slot和codis server的映射关系称为数据路由表(简称路由表)。我们在codis dashboard上分配好路由表后,dashboard会把路由表发送给codis proxy,同时,dashboard也会把路由表保存在Zookeeper中。codis-proxy会把路由表缓存在本地,当它接收到客户端请求后,直接查询本地的路由表,就可以完成正确的请求转发了。下图展示了路由表的分配和使用过程:
在数据分片的实现方法上,Codis 和 Redis Cluster 很相似,都采用了 key 映射到 Slot、Slot 再分配到实例上的机制。但是,这里有一个明显的区别:
- Codis中的路由表是我们通过codis dashboard分配和修改的,并被保存在Zookeeper集群中。一旦数据位置发生变化(例如有实例增减),路由表被修改了,codis dashbaord就会把修改后的路由表发送给codis proxy,proxy就可以根据最新的路由信息转发请求了。
- 在Redis Cluster中,数据路由表是通过每个实例相互间的通信传递的,最后会在每个实例上保存一份。当数据路由信息发生变化时,就需要在所有实例间通过网络消息进行传递。所以,如果实例数量较多的话,就会消耗较多的集群网络资源。
数据分布解决了新数据写入时该保存在哪个server的问题,但是,当业务数据增加后,如果集群中的现有实例不足以保存所有数据,我们就需要对集群进行扩容。接下来,我们再来学习下Codis针对集群扩容的关键技术设计。
# 2.2.2 集群扩容和数据迁移如何进行?
Codis 集群扩容包括了两方面:增加 codis server 和增加 codis proxy。
我们先来看增加 codis server,这个过程主要涉及到两步操作:
- 启动新的 codis server,将它加入集群中;
- 把部分数据迁移到新的 server。
需要注意的是,这里的数据迁移是一个重要的机制。Codis 集群按照 Slot 的粒度进行数据迁移,我们来看下迁移的基本流程:
- 在源server上,Codis从要迁移的Slot中随机选择一个数据,发送给目的server。
- 目的server确认收到数据后,会给源server返回确认消息。这时,源server会在本地将刚才迁移的数据删除。
- 第一步和第二步就是单个数据的迁移过程。Codis会不断重复这个迁移过程,直到要迁移的Slot中的数据全部迁移完成。
下图显示了数据迁移的流程:
针对刚才介绍的单个数据的迁移过程,Codis实现了两种迁移模式,分别是同步迁移和异步迁移:
- 同步迁移是指,在数据从源server发送给目的server的过程中,源server是阻塞的,无法处理新的请求操作。这种模式很容易实现,但是迁移过程中会涉及多个操作(包括数据在源server序列化、网络传输、在目的server反序列化,以及在源server删除),如果迁移的数据是一个bigkey,源server就会阻塞较长时间,无法及时处理用户请求。
- 为了避免数据迁移阻塞源server,Codis实现的第二种迁移模式就是异步迁移。异步迁移的关键特点有两个:
- 第一个特点是,当源server把数据发送给目的server后,就可以处理其他请求操作了,不用等到目的server的命令执行完。而目的server会在收到数据并反序列化保存到本地后,给源server发送一个ACK消息,表明迁移完成。此时,源server在本地把刚才迁移的数据删除。在这个过程中,迁移的数据会被设置为只读,所以,源server上的数据不会被修改,自然也就不会出现“和目的server上的数据不一致”的问题了。
- 第二个特点是,对于bigkey,异步迁移采用了拆分指令的方式进行迁移。具体来说就是,对bigkey中每个元素,用一条指令进行迁移,而不是把整个bigkey进行序列化后再整体传输。这种化整为零的方式,就避免了bigkey迁移时,因为要序列化大量数据而阻塞源server的问题。此外,当bigkey迁移了一部分数据后,如果Codis发生故障,就会导致bigkey的一部分元素在源server,而另一部分元素在目的server,这就破坏了迁移的原子性。所以,Codis会在目标server上,给bigkey的元素设置一个临时过期时间。如果迁移过程中发生故障,那么,目标server上的key会在过期后被删除,不会影响迁移的原子性。当正常完成迁移后,bigkey元素的临时过期时间会被删除。
这里,有个地方需要你注意下,为了提升迁移的效率,Codis在异步迁移Slot时,允许每次迁移多个key。你可以通过异步迁移命令SLOTSMGRTTAGSLOT-ASYNC的参数numkeys设置每次迁移的key数量。
刚刚讲的是 codis server 的扩容和数据迁移机制,除此之外,我们可能还需要增加 codis proxy。因为在 Codis 集群中,客户端是和 codis proxy 直接连接的,所以,当客户端增加时,一个proxy无法支撑大量的请求操作,此时,我们就需要增加proxy。
增加proxy比较容易,我们直接启动proxy,再通过codis dashboard把proxy加入集群就行。
此时,codis proxy的访问连接信息都会保存在Zookeeper上。所以,当新增了proxy后,Zookeeper上会有最新的访问列表,客户端也就可以从Zookeeper上读取proxy访问列表,把请求发送给新增的proxy。这样一来,客户端的访问压力就可以在多个proxy上分担处理了,如下图所示:
好了,到这里,我们就了解了Codis集群中的数据分布、集群扩容和数据迁移的方法,这都是切片集群中的关键机制。
# 2.2.3 客户端的兼容性
使用 Redis 单实例时,客户端只要符合 RESP 协议,就可以和实例进行交互和读写数据。但是,在使用切片集群时,有些功能是和单实例不一样的,比如集群中的数据迁移操作,在单实例上是没有的,而且迁移过程中,数据访问请求可能要被重定向(例如Redis Cluster中的MOVE命令)。所以,客户端需要增加和集群功能相关的命令操作的支持。如果原来使用单实例客户端,想要扩容使用集群,就需要使用新客户端,这对于业务应用的兼容性来说,并不是特别友好。
Codis 集群在设计时,就充分考虑了对现有单实例客户端的兼容性。Codis 使用 codis proxy 直接和客户端连接,codis proxy 是和单实例客户端兼容的。而和集群相关的管理工作(例如请求转发、数据迁移等),都由 codis proxy、codis dashboard 这些组件来完成,不需要客户端参与。
这样一来,业务应用使用 Codis 集群时,就不用修改客户端了,可以复用和单实例连接的客户端,既能利用集群读写大容量数据,又避免了修改客户端增加复杂的操作逻辑,保证了业务代码的稳定性和兼容性。
# 2.2.4 怎么保证集群可靠性?
我们来分别看下 Codis 不同组件的可靠性保证方法。
首先是 codis server。
codis server其实就是Redis实例,只不过增加了和集群操作相关的命令。Redis的主从复制机制和哨兵机制在codis server上都是可以使用的,所以,Codis就使用主从集群来保证codis server的可靠性。简单来说就是,Codis给每个server配置从库,并使用哨兵机制进行监控,当发生故障时,主从库可以进行切换,从而保证了server的可靠性。
在这种配置情况下,每个server就成为了一个server group,每个group中是一主多从的server。数据分布使用的Slot,也是按照group的粒度进行分配的。同时,codis proxy在转发请求时,也是按照数据所在的Slot和group的对应关系,把写请求发到相应group的主库,读请求发到group中的主库或从库上。
下图展示的是配置了server group的Codis集群架构。在Codis集群中,我们通过部署server group和哨兵集群,实现codis server的主从切换,提升集群可靠性:
再看一下 codis proxy 和 Zookeeper 的可靠性。
在Codis集群设计时,proxy上的信息源头都是来自Zookeeper(例如路由表)。而Zookeeper集群使用多个实例来保存数据,只要有超过半数的Zookeeper实例可以正常工作, Zookeeper集群就可以提供服务,也可以保证这些数据的可靠性。
所以,codis proxy使用Zookeeper集群保存路由表,可以充分利用Zookeeper的高可靠性保证来确保codis proxy的可靠性,不用再做额外的工作了。当codis proxy发生故障后,直接重启proxy就行。重启后的proxy,可以通过codis dashboard从Zookeeper集群上获取路由表,然后,就可以接收客户端请求进行转发了。这样的设计,也降低了Codis集群本身的开发复杂度。
对于codis dashboard和codis fe来说,它们主要提供配置管理和管理员手工操作,负载压力不大,所以,它们的可靠性可以不用额外进行保证了。
# 2.3 切片集群方案选择建议
下图总结了 Codis 和 Redis Cluster 两种切片集群方案,对比如下:
最后,在实际应用的时候,对于这两种方案的选择有如下建议:
从稳定性和成熟度来看,Codis应用得比较早,在业界已经有了成熟的生产部署。虽然Codis引入了proxy和Zookeeper,增加了集群复杂度,但是,proxy的无状态设计和Zookeeper自身的稳定性,也给Codis的稳定使用提供了保证。而Redis Cluster的推出时间晚于Codis,相对来说,成熟度要弱于Codis,如果你想选择一个成熟稳定的方案,Codis更加合适些。
从业务应用客户端兼容性来看,连接单实例的客户端可以直接连接codis proxy,而原本连接单实例的客户端要想连接Redis Cluster的话,就需要开发新功能。所以,如果你的业务应用中大量使用了单实例的客户端,而现在想应用切片集群的话,建议你选择Codis,这样可以避免修改业务应用中的客户端。
从使用Redis新命令和新特性来看,Codis server是基于开源的Redis 3.2.8开发的,所以,Codis并不支持Redis后续的开源版本中的新增命令和数据类型。另外,Codis并没有实现开源Redis版本的所有命令,比如BITOP、BLPOP、BRPOP,以及和与事务相关的MUTLI、EXEC等命令。 Codis官网 (opens new window) 上列出了不被支持的命令列表,你在使用时记得去核查一下。所以,如果你想使用开源Redis 版本的新特性,Redis Cluster是一个合适的选择。
从数据迁移性能维度来看,Codis能支持异步迁移,异步迁移对集群处理正常请求的性能影响要比使用同步迁移的小。所以,如果你在应用集群时,数据迁移比较频繁的话,Codis是个更合适的选择。
另外这里再提供一个 Codis 使用上的小建议:当你有多条业务线要使用 Codis 时,可以启动多个 codis dashboard,每个 dashboard 管理一部分 codis server,同时,再用一个 dashboard 对应负责一个业务线的集群管理,这样就可以做到用一个 Codis 集群实现多条业务线的隔离管理了。