共计 3732 个字符,预计需要花费 10 分钟才能阅读完成。
数据分片
Q:redis 集群是怎么做数据分片的?
A:Redis 集群是通过数据分片(sharding)来实现数据在不同节点间的调配。Redis 集群中有 16384 个 hash slot(槽位),每个节点能够解决其中的一部分槽位,不同节点之间能够独特解决这 16384 个槽位。当一个键值对须要被放到 Redis 集群中时,Redis 会先计算该键值对的 key 对应的 hash 值,而后将其放到对应的槽位中。Redis 集群的每个节点都晓得本人负责解决哪些槽位,所以可能疾速定位数据在哪个节点上。
具体来说,Redis 集群应用哈希槽分片(hash slot sharding)来将所有数据分成 16384 个哈希槽。当客户端连贯 Redis 集群时,会失去集群中任意一个节点的 IP 和端口信息,而后将客户端的申请路由到正确的节点上。每个节点都负责解决一部分哈希槽,这些哈希槽的范畴通过分布式哈希算法(比方 CRC16)来计算,而后调配到不同的节点上。当一个客户端申请须要操作某个 key 时,Redis 会先依据 key 计算出该 key 对应的哈希槽,而后将申请路由到负责该哈希槽的节点上。这样就实现了数据的分片存储和拜访。
Q:一个槽位,能够被多个 redis 主节点独特持有吗?
A:在 Redis 集群中,一个槽位只能被一个 Redis 节点持有,即每个槽位只能被调配给 Redis 集群中的一个主节点。在 Redis 集群中,槽位会被平均地调配给各个主节点,确保每个主节点都调配了肯定数量的槽位,从而实现数据的分布式存储。如果一个槽位被多个主节点持有,那么可能会导致数据抵触和数据一致性问题。因而,Redis 集群的设计保障了一个槽位只被一个主节点持有。
Q:一个 redis 主节点,怎么晓得本人持有哪些槽位?持有的槽位是离散的,还是间断的?
A:在 Redis 集群中,一个 Redis 主节点会持有一部分槽位,具体是哪些槽位是由集群的节点管理器指定的。一个槽位只会被调配给一个 Redis 主节点,而不会被多个主节点独特持有。每个 Redis 主节点都会记录本人持有的槽位信息,能够通过命令 CLUSTER SLOTS 来获取以后节点所持有的槽位信息,例如:
127.0.0.1:6379> CLUSTER SLOTS | |
1) 1) (integer) 0 | |
2) (integer) 5460 | |
3) 1) "127.0.0.1" | |
2) (integer) 6379 | |
3) "f2b5a96e2e79d08ce5d5a5b1d64b5a31f07a734f" | |
4) 1) "127.0.0.1" | |
2) (integer) 6380 | |
3) "92d24c0209384f4c4c9abef7adff0f129b73e7b6" | |
2) 1) (integer) 5461 | |
2) (integer) 10922 | |
3) 1) "127.0.0.1" | |
2) (integer) 6380 | |
3) "92d24c0209384f4c4c9abef7adff0f129b73e7b6" | |
4) 1) "127.0.0.1" | |
2) (integer) 6379 | |
3) "f2b5a96e2e79d08ce5d5a5b1d64b5a31f07a734f" | |
... |
上述命令返回了以后节点所持有的所有槽位信息。其中,每个槽位由一个起始槽号和一个完结槽号组成,例如 (integer) 0 到 (integer) 5460 示意第一个槽位的起始编号为 0,完结编号为 5460。对于间断的槽位,它们的起始和完结编号是间断的,而对于离散的槽位,它们的编号是不间断的。
Q:客户端怎么晓得应该把数据写到 redis 集群的哪个节点?
A:在 Redis 集群中,客户端能够应用哈希槽位算法来确定应该将申请发送到哪个节点。哈希槽位算法将每个 key 映射到 16384 个槽位中的一个,并将每个槽位调配给集群中的一个节点。当客户端须要与集群通信时,它会将 key 映射到一个槽位,并向负责该槽位的节点发送申请。如果申请须要拜访多个 key,则应用所有 key 的槽位来确定应该将申请发送到哪个节点。
在 Redis 集群中,每个节点都晓得哪些槽位被调配给它。当一个节点收到一个申请,如果它不是负责该槽位的节点,则它会返回一个 MOVED 谬误,通知客户端应该将申请发送到负责该槽位的节点。
因而,客户端通过哈希槽位算法将 key 映射到节点,并应用 MOVED 谬误来确定应该将申请发送到哪个节点。
Q:redis 集群的客户端,怎么晓得哪个 redis server 节点负责哪个槽位?
A:Redis 集群的客户端通过集群中的元数据(metadata)来获取槽和节点之间的映射关系,这个元数据保留在所有的 Redis 节点上。当一个客户端须要晓得某个槽位的信息时,它会向 Redis 集群的其中一个节点发送 CLUSTER SLOTS 命令,该节点会返回一个蕴含以后集群中节点和槽位信息的列表,客户端通过解析这个列表就能够理解槽位和节点之间的映射关系。客户端在获取了这个映射关系后,就能够将申请发送到正确的节点上。
Q:redis 集群的元数据个别会很大吗?会占用很多网络通讯资源吗?
A:Redis 集群的元数据个别不会很大,因为它只蕴含了对于槽位与节点的映射信息。在默认的状况下,Redis 集群有 16384 个槽位,因而元数据的大小与节点数目和槽位的数量成正比。当集群中有成千盈百个节点时,元数据会变得比拟大,然而它通常不会成为瓶颈。
对于网络通讯资源的占用,元数据的大小绝对较小,因而它对网络通讯资源的占用也较小。在 Redis 集群中,每个节点都须要与其余节点替换元数据信息以放弃整个集群的状态一致性,这可能会占用肯定的网络带宽。然而,Redis 采纳了一些优化措施,如增量同步和只同步变动的信息等,以升高网络通讯资源的占用。
Q:redis 集群的客户端,怎么晓得哪个 redis server 节点上线了或者下线了?怎么更新元信息?
A:Redis 集群的客户端能够通过监听 cluster:slots、cluster:meet、cluster:forget 等事件来感知 Redis 节点的上线、下线、增加、删除等操作,并相应地更新集群元数据。
具体来说,客户端能够应用 Redis 提供的 SUBSCRIBE 命令来订阅 cluster:slots、cluster:meet、cluster:forget 等事件的告诉,当 Redis 节点的状态发生变化时,Redis 会公布相应的事件告诉给所有客户端。客户端接管到告诉后,能够更新本人本地的集群元数据,以确保后续的操作能够正确地路由到相应的节点。
例如,Python 客户端 redis-py-cluster 提供了 RedisCluster 类来操作 Redis 集群,能够应用该类的 pubsub 属性来订阅相应的事件告诉,如下所示:
from rediscluster import RedisCluster | |
startup_nodes = [{"host": "127.0.0.1", "port": "7000"}] | |
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True) | |
# 订阅 cluster:slots 事件 | |
pubsub = rc.pubsub(ignore_subscribe_messages=True) | |
pubsub.subscribe("__keyspace@0__:*") | |
# 监听事件告诉 | |
for item in pubsub.listen(): | |
print(item) |
下面的代码订阅了 __keyspace@0__:*
频道,即监听所有 key 空间的事件告诉。当有节点上线、下线、增加、删除等操作时,Redis 会公布相应的事件告诉到该频道,客户端通过监听该频道,就能够更新本人本地的集群元数据。
Q:对于一个 redis 集群,如果有一个 redis 主节点宕机下线了,这个时候,客户端往这个节点写入数据怎么办?
A:如果一个 Redis 主节点宕机下线了,客户端往这个节点写入数据的申请会失败。为了防止这种状况,Redis 集群提供了主动故障迁徙(automatic failover)机制,使得当主节点宕机下线后,集群可能主动将从节点降级为新的主节点,以保障集群的高可用性。
当主节点宕机下线后,集群会检测到该节点下线,而后从其它从节点中选出一个新的主节点。选举新主节点的过程是通过集群内的投票机制来实现的。首先,集群会在所有从节点中选举一个新主节点,而后将新主节点的信息播送给集群中的所有节点。当客户端向集群发送写入申请时,集群会主动将申请路由到新的主节点上,从而保障集群的失常运行。
数据正本
Q:redis 集群的正本是怎么调配的?
A:在 Redis 集群中,每个主节点会被调配若干个从节点,每个从节点都会在运行时通过复制主节点的数据来放弃与主节点的数据统一。在默认状况下,每个主节点会被调配一个从节点,能够通过减少主节点的数量来减少集群的可用性和容错性。Redis 集群应用的是无核心架构,所以每个节点都会调配一个固定的槽位,对于任何给定的槽位,只会有一个主节点和一个或多个从节点负责解决。
当一个主节点下线时,其对应的从节点会被晋升为新的主节点,从而确保集群的高可用性和可靠性。Redis 集群还反对对数据进行分片,从而将数据分布在多个主节点之间,进步并发解决能力和可扩展性。