使用Cassandra进行LOCAL_ONE和意外数据复制

时间:2016-03-02 16:04:08

标签: cassandra datastax-enterprise datastax-startup

FYI。我们正在使用Cassandra 2.1.12.1047 |进行此测试DSE 4.8.4

我们在Cassandra有一个简单的表,里面有5000行数据。一段时间以来,作为预防措施,我们在每个Cassandra实例上添加了监控,以确保它拥有5,000行数据,因为我们的复制因素强制执行此操作,即我们在每个区域都有2个副本,并且我们的开发群集中总共有6个服务器。

CREATE KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', 'ap-southeast-1-A': '2', 'eu-west-1-A': '2', 'us-east-1-A': '2'} AND durable_writes = true;

我们最近强行终止服务器以模拟故障,并在网上带来一个新服务器,看看会发生什么。我们还使用nodetool removenode删除了旧节点,以便在每个区域中我们都希望所有数据都存在于每个服务器上。

新服务器上线后,它加入了群集,似乎开始复制数据。我们假设它处于引导模式,它将负责确保它从群集中获取所需的数据。大约一个小时后CPU终于掉线了,我们假设复制完成了。

但是,我们的监视器故意在每台服务器上使用LOCAL_ONE进行查询,报告所有服务器都有5,000行,并且新上线的服务器大约有2,600行。我们假设也许它仍在复制,所以我们离开了一段时间,但它保持在那个数字。

因此我们运行nodetool status进行检查并获得以下内容:

$ nodetool status my_keyspace
Datacenter: ap-southeast-1-A
======================================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load       Tokens  Owns (effective)  Host ID                               Rack
UN  54.255.17.28    7.9 GB     256     100.0%            a0c45f3f-8479-4046-b3c0-b2dd19f07b87  ap-southeast-1a
UN  54.255.64.1     8.2 GB     256     100.0%            b91c5863-e1e1-4cb6-b9c1-0f24a33b4baf  ap-southeast-1b
Datacenter: eu-west-1-A
=================================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load       Tokens  Owns (effective)  Host ID                               Rack
UN  176.34.207.151  8.51 GB    256     100.0%            30ff8d00-1ab6-4538-9c67-a49e9ad34672  eu-west-1b
UN  54.195.174.72   8.4 GB     256     100.0%            f00dfb85-6099-40fa-9eaa-cf1dce2f0cd7  eu-west-1c
Datacenter: us-east-1-A
=================================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load       Tokens  Owns (effective)  Host ID                               Rack
UN  54.225.11.249   8.17 GB    256     100.0%            0e0adf3d-4666-4aa4-ada7-4716e7c49ace  us-east-1e
UN  54.224.182.94   3.66 GB    256     100.0%            1f9c6bef-e479-49e8-a1ea-b1d0d68257c7  us-east-1d 

因此,如果服务器报告它拥有100%的数据,为什么LOCAL_ONE查询只给我们大约一半的数据?

当我运行LOCAL_QUORUM查询时,它返回了5,000行,从那时起,即使LOCAL_ONE次查询也返回了5,000行。

虽然LOCAL_QUORUM在这个实例中解决了问题,但我们将来可能需要做其他类型的查询,假设每个服务器a)都有它应该拥有的数据,b)知道如何满足查询时它没有数据,即它知道数据位于环上的其他位置。

24小时后再次更新 - 问题很多

因此,在没有关于此问题的任何反馈的情况下,我已经通过添加更多节点继续在群集上进行实验。根据{{​​3}},我已经按照建议的所有步骤将节点添加到群集中,实际上增加了容量。我相信Cassandra的前提是,当您添加节点时,群集负责重新平衡数据,在此期间,如果不是,则从环上的位置获取数据它应该在哪里。

不幸的是,事实并非如此。这是我的新戒指:

Datacenter: ap-southeast-1-A
======================================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load       Tokens  Owns (effective)  Host ID                               Rack
UN  54.255.xxx.xxx  8.06 GB    256     50.8%             a0c45f3f-8479-4046-b3c0-b2dd19f07b87  ap-southeast-1a
UN  54.254.xxx.xxx  2.04 MB    256     49.2%             e2e2fa97-80a0-4768-a2aa-2b63e2ab1577  ap-southeast-1a
UN  54.169.xxx.xxx  1.88 MB    256     47.4%             bcfc2ff0-67ab-4e6e-9b18-77b87f6b3df3  ap-southeast-1b
UN  54.255.xxx.xxx  8.29 GB    256     52.6%             b91c5863-e1e1-4cb6-b9c1-0f24a33b4baf  ap-southeast-1b
Datacenter: eu-west-1-A
=================================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load       Tokens  Owns (effective)  Host ID                               Rack
UN  54.78.xxx.xxx   8.3 GB     256     49.9%             30ff8d00-1ab6-4538-9c67-a49e9ad34672  eu-west-1b
UN  54.195.xxx.xxx  8.54 GB    256     50.7%             f00dfb85-6099-40fa-9eaa-cf1dce2f0cd7  eu-west-1c
UN  54.194.xxx.xxx  5.3 MB     256     49.3%             3789e2cc-032d-4b26-bff9-b2ee71ee41a0  eu-west-1c
UN  54.229.xxx.xxx  5.2 MB     256     50.1%             34811c15-de8f-4b12-98e7-0b4721e7ddfa  eu-west-1b
Datacenter: us-east-1-A
=================================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address         Load       Tokens  Owns (effective)  Host ID                               Rack
UN  54.152.xxx.xxx  5.27 MB    256     47.4%             a562226a-c9f2-474f-9b86-46c3d2d3b212  us-east-1d
UN  54.225.xxx.xxx  8.32 GB    256     50.3%             0e0adf3d-4666-4aa4-ada7-4716e7c49ace  us-east-1e
UN  52.91.xxx.xxx   5.28 MB    256     49.7%             524320ba-b8be-494a-a9ce-c44c90555c51  us-east-1e
UN  54.224.xxx.xxx  3.85 GB    256     52.6%             1f9c6bef-e479-49e8-a1ea-b1d0d68257c7  us-east-1d

正如您将看到的,我将环的大小加倍,并且每个服务器的有效所有权大约为50%(我的复制因子在每个区域都是2个副本)。但是,你可以看到一些服务器完全没有负载(它们是新的),而其他服务器负载过大(它们很旧,显然没有发生数据分发)。

现在这本身并不令人担心,因为我相信Cassandra的力量及其最终将数据放到正确位置的能力。令我非常担心的是,我的完全 5,000行的表现在不再在我的三个区域中有5,000行。

# From ap-southeast-1

cqlsh> CONSISTENCY ONE;
Consistency level set to ONE.

cqlsh> select count(*) from health_check_data_consistency;

 count
-------
  3891

cqlsh> CONSISTENCY LOCAL_QUORUM;
Consistency level set to LOCAL_QUORUM.

cqlsh> select count(*) from health_check_data_consistency;

 count
-------
  4633


# From eu-west-1

cqlsh> CONSISTENCY ONE;
Consistency level set to ONE.

cqlsh> select count(*) from health_check_data_consistency;

 count
-------
  1975

cqlsh> CONSISTENCY LOCAL_QUORUM;
Consistency level set to LOCAL_QUORUM.

cqlsh> select count(*) from health_check_data_consistency;

 count
-------
  4209


# From us-east-1

cqlsh> CONSISTENCY ONE;
Consistency level set to ONE.

cqlsh> select count(*) from health_check_data_consistency;

 count
-------
  4435

cqlsh> CONSISTENCY LOCAL_QUORUM;
Consistency level set to LOCAL_QUORUM.

cqlsh> select count(*) from health_check_data_consistency;

 count
-------
  4870

如此认真,这里发生了什么?让我们回顾一下:

  • 我的复制因子是'ap-southeast-1-A': '2', 'eu-west-1-A': '2', 'us-east-1-A': '2',因此每个区域都应该能够完整地满足查询。
  • 引入新实例不应该导致数据丢失,但显然我们甚至使用LOCAL_QUORUM
  • 每个地区对数据都有不同的看法,但我没有引入任何新数据,只有新服务器会自动引导。

然后我想,为什么不在整个多区域集群中进行QUORUM查询。不幸的是,完全失败了:

cqlsh> CONSISTENCY QUORUM;
Consistency level set to QUORUM.

cqlsh> select count(*) from health_check_data_consistency;
OperationTimedOut: errors={}, last_host=172.17.0.2

然后我转向TRACING ON;,但也失败了。我在日志中可以看到以下内容:

INFO  [SlabPoolCleaner] 2016-03-03 19:16:16,616  ColumnFamilyStore.java:1197 - Flushing largest CFS(Keyspace='system_traces', ColumnFamily='events') to free up room. Used total: 0.33/0.00, live: 0.33/0.00, flushing: 0.00/0.00, this: 0.02/0.02
INFO  [SlabPoolCleaner] 2016-03-03 19:16:16,617  ColumnFamilyStore.java:905 - Enqueuing flush of events: 5624218 (2%) on-heap, 0 (0%) off-heap
INFO  [MemtableFlushWriter:1126] 2016-03-03 19:16:16,617  Memtable.java:347 - Writing Memtable-events@732346653(1.102MiB serialized bytes, 25630 ops, 2%/0% of on/off-heap limit)
INFO  [MemtableFlushWriter:1126] 2016-03-03 19:16:16,821  Memtable.java:382 - Completed flushing /var/lib/cassandra/data/system_traces/events/system_traces-events-tmp-ka-3-Data.db (298.327KiB) for commitlog position ReplayPosition(segmentId=1456854950580, position=28100666
)
INFO  [ScheduledTasks:1] 2016-03-03 19:16:21,210  MessagingService.java:929 - _TRACE messages were dropped in last 5000 ms: 212 for internal timeout and 0 for cross node timeout

在我运行查询的每台服务器上都会发生这种情况。

检查群集,似乎一切都在同步

$ nodetool describecluster;
Cluster Information:
    Name: Ably
    Snitch: org.apache.cassandra.locator.DynamicEndpointSnitch
    Partitioner: org.apache.cassandra.dht.Murmur3Partitioner
    Schema versions:
            51e57d47-8870-31ca-a2cd-3d854e449687: [54.78.xxx.xxx, 54.152.xxx.xxx, 54.254.xxx.xxx, 54.255.xxx.xxx, 54.195.xxx.xxx, 54.194.xxx.xxx, 54.225.xxx.xxx, 52.91.xxx.xxx, 54.229.xxx.xxx, 54.169.xxx.xxx, 54.224.xxx.xxx, 54.255.xxx.xxx]

1小时后再次更新

有人建议,或许这只是范围内的查询无法按预期工作。因此,我编写了一个简单的脚本,分别查询每个5k行(它们的ID范围为1> 5,000)。不幸的是结果是我担心的,我缺少数据。我使用LOCAL_ONELOCAL_QUORUM和事件QUORUM尝试了此操作。

ruby> (1..5000).each { |id| put "#{id} missing" if session.execute("select id from health_check_data_consistency where id = #{id}", consistency: :local_quorum).length == 0 }
19 missing, 61 missing, 84 missing, 153 missing, 157 missing, 178 missing, 248 missing, 258 missing, 323 missing, 354 missing, 385 missing, 516 missing, 538 missing, 676 missing, 708 missing, 727 missing, 731 missing, 761 missing, 863 missing, 956 missing, 1006 missing, 1102 missing, 1121 missing, 1161 missing, 1369 missing, 1407 missing, 1412 missing, 1500 missing, 1529 missing, 1597 missing, 1861 missing, 1907 missing, 2005 missing, 2168 missing, 2207 missing, 2210 missing, 2275 missing, 2281 missing, 2379 missing, 2410 missing, 2469 missing, 2672 missing, 2726 missing, 2757 missing, 2815 missing, 2877 missing, 2967 missing, 3049 missing, 3070 missing, 3123 missing, 3161 missing, 3235 missing, 3343 missing, 3529 missing, 3533 missing, 3830 missing, 4016 missing, 4030 missing, 4084 missing, 4118 missing, 4217 missing, 4225 missing, 4260 missing, 4292 missing, 4313 missing, 4337 missing, 4399 missing, 4596 missing, 4632 missing, 4709 missing, 4786 missing, 4886 missing, 4934 missing, 4938 missing, 4942 missing, 5000 missing

从上面可以看出,这意味着我有大约1.5%的数据不再可用。

所以我很难过。我真的需要一些建议,因为我肯定认为Cassandra是专门为按需横向扩展而设计的。非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

关于所有权。这基于令牌所有权,而不是实际数据。因此,无论每个节点上的数据量如何,每种情况下报告的所有权都是正确的。

其次,您不能保证与两个节点的一致性(除非您牺牲可用性并使用CL = ALL)。 QUORUM =多数。每个DC至少需要三个节点才能真正获得法定数量。如果一致性对于每个DC部署三个节点并执行QUORUM读取和写入非常重要。

DC之间的SELECT count(*)将超时。我们和ap数据中心之间可能有几百毫秒的延迟。加上选择计数(*)是一项昂贵的操作。

当您执行QUORUM读取时,Cassandra将使用读取修复来修复不一致的数据。这就是您在仲裁时运行查询后计数准确的原因。

所有这一切,你似乎确实有一个引导问题,因为新节点没有获得所有数据。首先,我将对所有节点进行修复,并确保它们在执行此操作后都有5,000条记录。那会让你知道流媒体没有被打破。然后像以前一样重复节点替换。此时使用nodetool netstats监视并查看日志。发布什么奇怪的。并且不要忘记您必须运行nodetool cleanup以从旧节点中删除数据。

您能描述一下您的硬件配置(RAM,CPU,磁盘等)吗?

答案 1 :(得分:0)

我应该说的是你无法保证一致性和可用性。由于您的仲裁查询本质上是一个ALL查询。查询其中一个节点何时关闭的唯一方法是降低CL。如果可用节点上的数据不一致,则不会进行读取修复。

运行修复后,您还需要在旧节点上运行清理以删除不再拥有的数据。此外,修复不会删除已删除/ TTLd数据,直到gc_grace_seconds期间之后。所以如果你有任何这个,它至少会坚持gc_grace_seconds。

你在日志中找到了什么吗?你可以分享你的配置吗?