cassandra 如何处理新节点(令牌如何重新分配)?
How cassandra handles new node ( how tokens are redistributed)?
我最近开始为一个新项目探索 Cassandra。这是我目前对 Cassandra 的理解(基于大量在线博客)
- Cassandra (C*) 是 AP(CAP 定理),即它具有高可用性和分区容错性
- C*在逻辑上是环形拓扑。不是在真正的网络意义上(因为所有节点都可以相互通信),而是在数据复制意义上(数据被复制到相邻节点)
- C* 使用 Murmur3 分区算法将分区键映射到整数范围(大约 -2^63 到 2^63)
- 每个节点负责几个范围(启用Vnodes),即
node1: [-2^63 到 -2^61], [2^31 到 2^33] ....
node2: [-2^61 - 1 到 2^59], [2^33 + 1 到 2^35]...
现在我的问题是,假设我创建了一个有 3 个节点且 RF = 2 的集群,那么
- 在这种情况下,整个令牌范围(我相信我在这里使用了正确的术语)-2^63 到 2^63 将均匀分布在这 3 个节点中?
- 如果我在此 运行 集群中添加另一个节点会怎样?我的假设是,C* 将重新平衡环,因为它使用一致性哈希,因此范围 -2^63 到 2^63 将被重新分配,相应的数据将被复制到新节点。 (在修复发生之前,从现有节点复制的数据不会被删除?)
- 当一个节点宕机时会发生什么? C* 是否通过重新分配代币和移动数据来重新平衡环?
- 令牌是 Murmur3hash(分区键)的花哨词吗?分区范围究竟意味着什么?是不是像partition range1= -2^63 to -2^61, partition range2 = -2^61 + 1 到 -2^59 等等。
- 八卦中实际分享的信息是什么?
抱歉,如果这些问题看起来很基础,但我花了很多时间却找不到明确的答案。
我尽量通俗易懂
Cassandra 提供了一种简单的配置方式,所有配置都在cassandra.yaml中完成。您还可以通过 了解集群中的分区情况。
让我们从基础开始,我们暂时只使用一个节点,而不是使用三个节点。
使用 cassandra 的默认配置,我们在 cassandra.yaml 文件
中得到以下值
num_tokens: 1
initial_token: 0
这意味着只有一个节点,所有分区都将驻留在这个节点上。
现在,虚拟节点的概念,简单来说就是cassandra把token分成多个范围,虽然没有物理节点。现在,如何在配置文件 cassandra.yaml 中启用虚拟节点功能。答案是num_token值。
num_tokens: 128
#initial_token: 0
此配置生成 128 个令牌范围,例如 0-10、11-20、20-30 等。保留 initial_token 的值注释,这意味着我们希望 cassandra 决定初始令牌的值(少一个担心的事情)。
现在让我们将另一个节点添加到集群中。下面是新节点的简单配置。为简单起见,将第一个节点 IP 设置为 127.0.0.1,将第二个节点 IP 设置为 127.0.0.2。
num_tokens: 128
#initial_token: 0
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "127.0.0.1, 127.0.0.2"
我们刚刚向集群添加了一个新节点,node1 将作为种子节点。 num_token 值为 128,即 128 个标记范围。 initial_token 的值被注释了,这意味着 cassandra 将决定初始标记和范围。新节点加入集群后将立即开始数据传输。
第三个节点配置如下-
num_tokens: 128
#initial_token: 0
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "127.0.0.1, 127.0.0.2, 127.0.0.3"
因此第三个节点将共享来自节点 1 的少数令牌范围和来自节点 2 的少数令牌范围。
我希望,到目前为止,我们已经得到了问题 1 和问题 2 的答案。让我们转到下两个问题。
当一个节点出现故障时,hinted-handoff 帮助 Cassandra 保持一致性。剩余 2 个节点中的任何一个都保留了应该写入已关闭节点的数据提示。一旦节点启动,这些提示将被重放,数据将写入目标节点。没有必要做重新分区或重新平衡这类花哨的事情。提示存储在可以在 cassandra.yaml 文件中配置的目录中。默认情况下将存储 3 小时的提示,这意味着有缺陷的节点应在 3 小时内出现。此值也可在 cassandra.yaml 文件中配置。
hinted_handoff_enabled: true
max_hint_window_in_ms: 10800000 # 3 hours
hints_directory: /home/ubuntu/node1/data/hints
Murmur3Partitioner 使用分区键列计算散列,让我们安心接受吧。还有其他的实践者,如RandomPartitioner和ByteOrderedPartitioner。
以下是八卦信息的示例输出 -
您可以浏览以下协议数据中的每个字段
ubuntu@ds201-node1:~$ ./node1/bin/nodetool gossipinfo
/127.0.0.1
generation:1621506507 -- the tiem at this node is boot strapped.
heartbeat:2323
STATUS:28:NORMAL,-1316314773810616606 -----status of the node , NORMAL,LEFT,LEAVING,REMOVED,REMOVING.....
LOAD:2295:110299.0 -- Disk space usage
SCHEMA:64:c5c6bdbd-5916-347a-ab5b-21813ab9d135 -- Changes if schema changes
DC:37:Cassandra --- data center of the NODE
RACK:18:rack1 --- Rack of the within the datacenter
RELEASE_VERSION:4:4.0.0.2284
NATIVE_TRANSPORT_ADDRESS:3:127.0.0.1
X_11_PADDING:2307:{"dse_version":"6.0.0","workloads":"Cassandra","workload":"Cassandra","active":"true","server_id":"08-00-27-32-1E-DD","graph":false,"health":0.3}
NET_VERSION:1:256
HOST_ID:2:ebd0627a-2491-40d8-ba37-e82a31a95688
NATIVE_TRANSPORT_READY:66:true
NATIVE_TRANSPORT_PORT:6:9041
NATIVE_TRANSPORT_PORT_SSL:7:9041
STORAGE_PORT:8:7000
STORAGE_PORT_SSL:9:7001
JMX_PORT:10:7199
TOKENS:27:<hidden>
Gossip 是跨集群传播数据的广播协议。在 cassandra 集群中,没有人是大师,同行之间传播数据,这有助于他们维护最新信息。节点使用八卦协议随机相互通信(这种随机性有一些标准)。 Gossip 仅传播节点元数据,不传播客户端数据。
希望这能消除一些疑虑。
提供额外的深度:
令牌范围分配确实有一个随机成分,所以它不完全是“偶数”。但是,如果您使用 allocate_tokens_for_keyspace
,新的令牌分配算法将接管,并根据指定密钥空间的复制因子 (RF) 优化未来的范围分配。
这是 nodetool ring
的六行缩略输出部分,来自使用 num_tokens=16
构建的 3 节点集群。请注意,“范围”实际上是一直定义的起始标记(哈希),直到下一个起始标记减一:
10.0.0.1 -6595849996054463311
10.0.0.2 -5923426258674511018
10.0.0.2 -5194860430157391004
10.0.0.2 -4076256821118426122
10.0.0.2 -3750110785943336998
10.0.0.3 -3045824679140675270
观察当我添加第 4 个节点时会发生什么:
10.0.0.1 -6595849996054463311
10.0.0.2 -5923426258674511018
10.0.0.4 -5711305561631524277
10.0.0.2 -5194860430157391004
10.0.0.4 -4831174780910733952
10.0.0.2 -4076256821118426122
10.0.0.2 -3750110785943336998
10.0.0.4 -3659290179273062522
10.0.0.3 -3045824679140675270
请注意,三个原始节点中每个节点的起始令牌范围保持不变。但在这种特殊情况下,10.0.0.2
上的范围被 一分为二 ,后半部分分配给 10.0.0.4
.
请注意,一旦流式传输完成,10.0.0.4
上那些范围内的数据仍在 10.0.0.2
上。这是设计使然,如果新节点的 bootstrap 进程失败。一旦事情稳定下来,您可以通过 运行在原来的三个节点上设置 nodetool cleanup
来删除这些数据。
What happens when a node goes down? Does C* rebalanced the ring by re-distributing the tokens and moving data around?
当 nodetool removenode
为 运行 时会发生这种情况。但是对于一个简单的下线节点,“提示”存储在剩余的节点上,一旦下线节点恢复就会重播。
我最近开始为一个新项目探索 Cassandra。这是我目前对 Cassandra 的理解(基于大量在线博客)
- Cassandra (C*) 是 AP(CAP 定理),即它具有高可用性和分区容错性
- C*在逻辑上是环形拓扑。不是在真正的网络意义上(因为所有节点都可以相互通信),而是在数据复制意义上(数据被复制到相邻节点)
- C* 使用 Murmur3 分区算法将分区键映射到整数范围(大约 -2^63 到 2^63)
- 每个节点负责几个范围(启用Vnodes),即 node1: [-2^63 到 -2^61], [2^31 到 2^33] .... node2: [-2^61 - 1 到 2^59], [2^33 + 1 到 2^35]...
现在我的问题是,假设我创建了一个有 3 个节点且 RF = 2 的集群,那么
- 在这种情况下,整个令牌范围(我相信我在这里使用了正确的术语)-2^63 到 2^63 将均匀分布在这 3 个节点中?
- 如果我在此 运行 集群中添加另一个节点会怎样?我的假设是,C* 将重新平衡环,因为它使用一致性哈希,因此范围 -2^63 到 2^63 将被重新分配,相应的数据将被复制到新节点。 (在修复发生之前,从现有节点复制的数据不会被删除?)
- 当一个节点宕机时会发生什么? C* 是否通过重新分配代币和移动数据来重新平衡环?
- 令牌是 Murmur3hash(分区键)的花哨词吗?分区范围究竟意味着什么?是不是像partition range1= -2^63 to -2^61, partition range2 = -2^61 + 1 到 -2^59 等等。
- 八卦中实际分享的信息是什么?
抱歉,如果这些问题看起来很基础,但我花了很多时间却找不到明确的答案。
我尽量通俗易懂
Cassandra 提供了一种简单的配置方式,所有配置都在cassandra.yaml中完成。您还可以通过
让我们从基础开始,我们暂时只使用一个节点,而不是使用三个节点。 使用 cassandra 的默认配置,我们在 cassandra.yaml 文件
中得到以下值num_tokens: 1
initial_token: 0
这意味着只有一个节点,所有分区都将驻留在这个节点上。 现在,虚拟节点的概念,简单来说就是cassandra把token分成多个范围,虽然没有物理节点。现在,如何在配置文件 cassandra.yaml 中启用虚拟节点功能。答案是num_token值。
num_tokens: 128
#initial_token: 0
此配置生成 128 个令牌范围,例如 0-10、11-20、20-30 等。保留 initial_token 的值注释,这意味着我们希望 cassandra 决定初始令牌的值(少一个担心的事情)。
现在让我们将另一个节点添加到集群中。下面是新节点的简单配置。为简单起见,将第一个节点 IP 设置为 127.0.0.1,将第二个节点 IP 设置为 127.0.0.2。
num_tokens: 128
#initial_token: 0
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "127.0.0.1, 127.0.0.2"
我们刚刚向集群添加了一个新节点,node1 将作为种子节点。 num_token 值为 128,即 128 个标记范围。 initial_token 的值被注释了,这意味着 cassandra 将决定初始标记和范围。新节点加入集群后将立即开始数据传输。
第三个节点配置如下-
num_tokens: 128
#initial_token: 0
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "127.0.0.1, 127.0.0.2, 127.0.0.3"
因此第三个节点将共享来自节点 1 的少数令牌范围和来自节点 2 的少数令牌范围。
我希望,到目前为止,我们已经得到了问题 1 和问题 2 的答案。让我们转到下两个问题。
当一个节点出现故障时,hinted-handoff 帮助 Cassandra 保持一致性。剩余 2 个节点中的任何一个都保留了应该写入已关闭节点的数据提示。一旦节点启动,这些提示将被重放,数据将写入目标节点。没有必要做重新分区或重新平衡这类花哨的事情。提示存储在可以在 cassandra.yaml 文件中配置的目录中。默认情况下将存储 3 小时的提示,这意味着有缺陷的节点应在 3 小时内出现。此值也可在 cassandra.yaml 文件中配置。
hinted_handoff_enabled: true
max_hint_window_in_ms: 10800000 # 3 hours
hints_directory: /home/ubuntu/node1/data/hints
Murmur3Partitioner 使用分区键列计算散列,让我们安心接受吧。还有其他的实践者,如RandomPartitioner和ByteOrderedPartitioner。
以下是八卦信息的示例输出 - 您可以浏览以下协议数据中的每个字段
ubuntu@ds201-node1:~$ ./node1/bin/nodetool gossipinfo
/127.0.0.1
generation:1621506507 -- the tiem at this node is boot strapped.
heartbeat:2323
STATUS:28:NORMAL,-1316314773810616606 -----status of the node , NORMAL,LEFT,LEAVING,REMOVED,REMOVING.....
LOAD:2295:110299.0 -- Disk space usage
SCHEMA:64:c5c6bdbd-5916-347a-ab5b-21813ab9d135 -- Changes if schema changes
DC:37:Cassandra --- data center of the NODE
RACK:18:rack1 --- Rack of the within the datacenter
RELEASE_VERSION:4:4.0.0.2284
NATIVE_TRANSPORT_ADDRESS:3:127.0.0.1
X_11_PADDING:2307:{"dse_version":"6.0.0","workloads":"Cassandra","workload":"Cassandra","active":"true","server_id":"08-00-27-32-1E-DD","graph":false,"health":0.3}
NET_VERSION:1:256
HOST_ID:2:ebd0627a-2491-40d8-ba37-e82a31a95688
NATIVE_TRANSPORT_READY:66:true
NATIVE_TRANSPORT_PORT:6:9041
NATIVE_TRANSPORT_PORT_SSL:7:9041
STORAGE_PORT:8:7000
STORAGE_PORT_SSL:9:7001
JMX_PORT:10:7199
TOKENS:27:<hidden>
Gossip 是跨集群传播数据的广播协议。在 cassandra 集群中,没有人是大师,同行之间传播数据,这有助于他们维护最新信息。节点使用八卦协议随机相互通信(这种随机性有一些标准)。 Gossip 仅传播节点元数据,不传播客户端数据。
希望这能消除一些疑虑。
提供额外的深度:
令牌范围分配确实有一个随机成分,所以它不完全是“偶数”。但是,如果您使用 allocate_tokens_for_keyspace
,新的令牌分配算法将接管,并根据指定密钥空间的复制因子 (RF) 优化未来的范围分配。
这是 nodetool ring
的六行缩略输出部分,来自使用 num_tokens=16
构建的 3 节点集群。请注意,“范围”实际上是一直定义的起始标记(哈希),直到下一个起始标记减一:
10.0.0.1 -6595849996054463311
10.0.0.2 -5923426258674511018
10.0.0.2 -5194860430157391004
10.0.0.2 -4076256821118426122
10.0.0.2 -3750110785943336998
10.0.0.3 -3045824679140675270
观察当我添加第 4 个节点时会发生什么:
10.0.0.1 -6595849996054463311
10.0.0.2 -5923426258674511018
10.0.0.4 -5711305561631524277
10.0.0.2 -5194860430157391004
10.0.0.4 -4831174780910733952
10.0.0.2 -4076256821118426122
10.0.0.2 -3750110785943336998
10.0.0.4 -3659290179273062522
10.0.0.3 -3045824679140675270
请注意,三个原始节点中每个节点的起始令牌范围保持不变。但在这种特殊情况下,10.0.0.2
上的范围被 一分为二 ,后半部分分配给 10.0.0.4
.
请注意,一旦流式传输完成,10.0.0.4
上那些范围内的数据仍在 10.0.0.2
上。这是设计使然,如果新节点的 bootstrap 进程失败。一旦事情稳定下来,您可以通过 运行在原来的三个节点上设置 nodetool cleanup
来删除这些数据。
What happens when a node goes down? Does C* rebalanced the ring by re-distributing the tokens and moving data around?
当 nodetool removenode
为 运行 时会发生这种情况。但是对于一个简单的下线节点,“提示”存储在剩余的节点上,一旦下线节点恢复就会重播。