高性能:可线性伸缩到1000个节点,无代理通信,使用异步复制,不对值执行merge操作。
一致性:可接受程度内的写安全。对于连接到主节点中”大多数“的客户端,系统会最大程度保留他们的写入。
可用性:当主节点中”大多数“可达,且每个不可达的主节点至少有一个可达的副本,集群能够在分区中存活。
副本迁移:一个副本都没有的主节点,可以从其他拥有多个副本的主节点接收一个副本。
Reids 单机版支持的单键命令,Reids 集群也支持。
对于复杂的多键命令,如果这些键都被哈希到相同的槽,Reids 集群也支持。
Reids 集群支持"hash tag"的概念,用来强制某些键存储到同一个哈希槽。
Reids 集群不支持多个数据库,只有0号数据库。
集群节点之间使用异步复制,以最后被选中的主节点数据集为准,覆盖其他副本的数据(如果有差异)。发生分区的期间,会有一个时间窗口,期间的写入可能会丢失。
被分区中的大多数所接受、确认的写入,在故障期间,写入丢失的例子:
写入已经被主节点接受,客户端收到回复(确认),但写入异步复制到副本失败。等待足够久的时间后,其中一个副本被提升为主节点。
主节点因为分区而不可达,被其中一个副本代替,一段时候后恢复可达,然后旧的主节点被转换为副本。客户端因为缓存了路由表(键-节点),在旧的主节点被转换为副本之前,向它写入了数据。
当一个主节点不能被主节点中的大多数访问,持续时间达到 NODE_TIMEOUT,主节会被其副本替换。如果在 NODE_TIMEOUT 之前分区被解决,没有写入丢失,否则期间的写入会丢失。(因为分区)如果主节点中的少数在持续 NODE_TIMEOUT 时间之后,仍然无法连接上主节点中的大多数,主节点中的少数进入拒接写入的状态。
键空间被划分为16384个槽,集群中的每个主节点负责16384个槽中的一个子集。
HASH_SLOT = CRC16(key) mod 16384
hash tag 保证多个键被哈希到同一个槽。
def HASH_SLOT(key) s = key.index "{" if s e = key.index "}",s+1 if e && e != s+1 key = key[s+1..e-1] end end crc16(key) % 16384 end
redis 客户端可以向任意节点发送请求,包括副本节点。如果请求是可接受的(单键请求,或者是多键请求但键都在同一个槽),节点会去查找负责(键所属)哈希槽的节点。如果哈希槽正好由当前节点负责,直接处理请求,否则查找内部映射表(槽->节点),回复 MOVED 错误:
GET x -MOVED 3999 127.0.0.1:6381
3999为键所属槽,127.0.0.1:6381为能处理此请求的实例IP和端口。
客户端需要重新发送请求到对应的实例。
客户单应该记住3999号槽由127.0.0.1:6381实例负责。下次要发送请求时,计算键所在哈希槽,有更大几率直接选中正确的节点。
另一个方案是,当收到MOVED重定向时,使用 CLUSTER NODES 或者 CLUSTER SLOTS 命令查询集群内所有槽->节点的映射关系。
下列情况下,客户端通常需要完整地获取所有槽->节点的映射:
参考 CLUSTER SLOTS 命令。
当某个槽正处于重新分片的过程中,属于此槽的键是不可用的。
连接可以开启只读模式,暗示客户端可以接受“过时”的数据,对正在进行中的写入不感兴趣。
参考 READONLY 命令。