cassandra 如何处理新节点(令牌如何重新分配)?

How cassandra handles new node ( how tokens are redistributed)?

我最近开始为一个新项目探索 Cassandra。这是我目前对 Cassandra 的理解(基于大量在线博客)

  1. Cassandra (C*) 是 AP(CAP 定理),即它具有高可用性和分区容错性
  2. C*在逻辑上是环形拓扑。不是在真正的网络意义上(因为所有节点都可以相互通信),而是在数据复制意义上(数据被复制到相邻节点)
  3. C* 使用 Murmur3 分区算法将分区键映射到整数范围(大约 -2^63 到 2^63)
  4. 每个节点负责几个范围(启用Vnodes),即 node1: [-2^63-2^61], [2^312^33] .... node2: [-2^61 - 12^59], [2^33 + 12^35]...

现在我的问题是,假设我创建了一个有 3 个节点且 RF = 2 的集群,那么

  1. 在这种情况下,整个令牌范围(我相信我在这里使用了正确的术语)-2^63 到 2^63 将均匀分布在这 3 个节点中?
  2. 如果我在此 运行 集群中添加另一个节点会怎样?我的假设是,C* 将重新平衡环,因为它使用一致性哈希,因此范围 -2^63 到 2^63 将被重新分配,相应的数据将被复制到新节点。 (在修复发生之前,从现有节点复制的数据不会被删除?)
  3. 当一个节点宕机时会发生什么? C* 是否通过重新分配代币和移动数据来重新平衡环?
  4. 令牌是 Murmur3hash(分区键)的花哨词吗?分区范围究竟意味着什么?是不是像partition range1= -2^63 to -2^61, partition range2 = -2^61 + 1 -2^59 等等。
  5. 八卦中实际分享的信息是什么?

抱歉,如果这些问题看起来很基础,但我花了很多时间却找不到明确的答案。

我尽量通俗易懂

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 为 运行 时会发生这种情况。但是对于一个简单的下线节点,“提示”存储在剩余的节点上,一旦下线节点恢复就会重播。