【问题标题】:Cassandra timeout during read query at consistency ONE (1 responses were required but only 0 replica responded)Cassandra 在一致性 ONE 的读取查询期间超时(需要 1 个响应,但只有 0 个副本响应)
【发布时间】:2015-11-26 10:55:16
【问题描述】:

我正在对具有 500000 行的表进行读取和更新查询,并且在处理大约 300000 行后有时会低于错误,即使没有节点关闭。

一致性 ONE 读取查询期间 Cassandra 超时(需要 1 个响应,但只有 0 个副本响应)

基础设施详情:
有 5 个 Cassandra 节点、5 个 spark 和 3 个 Hadoop 节点,每个节点有 8 个内核和 28 GB 内存,Cassandra 复制因子3

卡桑德拉 2.1.8.621 | DSE 4.7.1 |火花1.2.1 | Hadoop 2.7.1。

Cassandra 配置:

read_request_timeout_in_ms (ms): 10000
range_request_timeout_in_ms (ms): 10000
write_request_timeout_in_ms (ms): 5000
cas_contention_timeout_in_ms (ms): 1000 
truncate_request_timeout_in_ms (ms): 60000
request_timeout_in_ms (ms): 10000.

我也尝试过同样的工作,将 read_request_timeout_in_ms (ms) 增加到 20,000,但没有帮助。

我正在对两个表进行查询。以下是其中一张表的创建语句:

创建表:

CREATE TABLE section_ks.testproblem_section (
    problem_uuid text PRIMARY KEY,
    documentation_date timestamp,
    mapped_code_system text,
    mapped_problem_code text,
    mapped_problem_text text,
    mapped_problem_type_code text,
    mapped_problem_type_text text,
    negation_ind text,
    patient_id text,
    practice_uid text,
    problem_category text,
    problem_code text,
    problem_comment text,
    problem_health_status_code text,
    problem_health_status_text text,
    problem_onset_date timestamp,
    problem_resolution_date timestamp,
    problem_status_code text,
    problem_status_text text,
    problem_text text,
    problem_type_code text,
    problem_type_text text,
    target_site_code text,
    target_site_text text
    ) WITH bloom_filter_fp_chance = 0.01
    AND caching = '{"keys":"ALL", "rows_per_partition":"NONE"}'
    AND comment = ''
    AND compaction = {'class': 
    'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'}
    AND compression = {'sstable_compression': 
    'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND dclocal_read_repair_chance = 0.1
    AND default_time_to_live = 0
    AND gc_grace_seconds = 864000
    AND max_index_interval = 2048
    AND memtable_flush_period_in_ms = 0
    AND min_index_interval = 128
    AND read_repair_chance = 0.0
    AND speculative_retry = '99.0PERCENTILE';

查询:

1) SELECT encounter_uuid, encounter_start_date FROM section_ks.encounters WHERE patient_id = '1234' AND encounter_start_date >= '" + formatted_documentation_date + "' ALLOW FILTERING;

2) UPDATE section_ks.encounters SET testproblem_uuid_set = testproblem_uuid_set + {'1256'} WHERE encounter_uuid = 'abcd345';

【问题讨论】:

  • 你可以发布你的创建表
  • ...和您的查询,我也会尝试TRACING ON 来分析问题。
  • @phact 我已经添加了创建表。感谢您的回复。
  • @uri2x 也添加了查询。
  • 不要在生产 oltp 查询中使用允许过滤。它会很慢。相反,您应该设计表的主键(分区和集群),以便可以使用常规 CQL 查询。

标签: hadoop cassandra apache-spark datastax datastax-java-driver


【解决方案1】:

通常,当您遇到超时错误时,这意味着您正在尝试做一些在 Cassandra 中无法很好扩展的事情。解决方法通常是修改您的架构。

我建议您在运行查询时监控节点,看看是否可以发现问题区域。例如,您可以运行“watch -n 1 nodetool tpstats”来查看是否有任何队列正在备份或删除项目。查看其他监控建议here

您的配置中可能存在的一件事是,您说您有五个 Cassandra 节点,但只有 3 个 spark worker(或者您是说每个 Cassandra 节点上有三个 spark worker?)您至少需要一个每个 Cassandra 节点上的 spark worker,以便将数据加载到 spark 中是在每个节点上本地完成的,而不是通过网络。

如果不查看您的架构和正在运行的查询,很难说出更多信息。您是从单个分区读取吗?从单个分区读取时,我开始在 300,000 行附近出现超时错误。见问题here。到目前为止,我发现的唯一解决方法是在我的分区键中使用客户端哈希将分区分成大约 100K 行的较小块。到目前为止,我还没有找到一种方法来告诉 Cassandra 不要让我预计需要很长时间的查询超时。

【讨论】:

  • 非常感谢。我会尝试您的建议。抱歉,关于集群的错误/简要信息。实际上,EC2 集群有 5 个 Cassandra 节点,5 个 Spark 工作节点,其中 2 个 Spark 工作节点位于 2 个 Cassandra 节点上,其他 3 个节点上有 hadoop 和 spark 工作节点。抱歉,如何查看正在读取多少个分区数据?
  • cfstats 和 cfhistograms
  • @Abhinandan - 您使用 ALLOW FILTERING 表明您正在尝试进行表扫描。这在 Cassandra 中效率不高,因此您应该重新构建架构以针对单个分区进行查询,或者将表加载到 spark RDD 中以便可以并行处理。
  • @JimMeyer - 我运行了“watch -n 1 nodetool tpstats”,我可以看到没有队列正在备份,也没有删除任何项目。我只将表加载到 spark RDD 中,然后对其进行查询. 除了重组架构,还有其他解决方法吗?
  • 我将 concurrent_reads 从 64 改为 128,有 20 个内核,现在它没有给出任何错误。这是真正的解决方案吗?
【解决方案2】:

不要认为配置是根本原因,而是数据模型问题。

看到 section_ks.encounters 表的结构会很酷。

建议在设计表结构之前仔细考虑需要运行的具体查询。

据我所知,这两个查询期望 section_ks.encounters 的不同结构以良好的性能运行它们。

让我们回顾每个提供的查询并尝试设计表格:

第一个:

从 section_ks.encounters 中选择遇到_uuid、遇到_开始日期 WHERE Patient_id = '1234' AND meet_start_date >= '" + formatted_documentation_date + "' 允许过滤;

  • 第一点,如果 Cassandra 强制您添加 ALLOW FILTERING,这是非最佳查询或表结构的症状。
  • 第二点。首要的关键。如果 patient_id 列和 encounter_start_date 列将形成复合主键,则关于 what are primary keys in Cassandra 给定查询的一个很棒的解释将快速运行且无需强制 ALLOW FILTERING 语句。 PRIMARY KEY() 语句中的列枚举应与查询中的过滤顺序相对应。
  • 为什么在原始查询中强制使用 ALLOW FILTERING?通过分区键 Cassandra 知道数据位于哪个节点上。如果 patient_id 列不是分区键,Cassandra 必须扫描所有 5 个节点以查找请求的患者。当我们跨节点有大量数据时,这种全扫描通常会因超时而失败。

这里是一个表结构的例子,可以有效地适应给定的查询:

create table section_ks.encounters(
    patient_id bigint, 
    encounter_start_date timestamp, 
    encounter_uuid text,
    some_other_non_unique_column text,
    PRIMARY KEY (patient_id, encounter_start_date)
);
  • patient_id 列将是一个“分区键”。负责跨 Cassandra 节点的数据分发。简而言之(省略复制功能):不同范围的患者将存储在不同的节点上。
  • encounter_start_date 列将是一个“集群键”,负责分区内的数据排序。

现在可以从查询中删除 ALLOW FILTERING:

SELECT encounter_uuid, encounter_start_date 
FROM section_ks.encounters 
WHERE patient_id = '1234' AND encounter_start_date >= '2017-08-19';

第二次查询:

更新 section_ks.encounters SET testproblem_uuid_set = testproblem_uuid_set + {'1256'} WHERE遇到_uuid = 'abcd345';

表结构应该类似于:

create table section_ks.encounters(
    encounter_uuid text, -- partition key
    patient_id bigint,
    testproblem_uuid_set text, 
    some_other_non_unique_column text,
    PRIMARY KEY (encounter_uuid)
);

如果我们确实想仅通过 encounter_uuid 进行快速过滤,则应将其定义为分区键。

关于设计有效数据模型的好文章:

【讨论】:

    猜你喜欢
    • 2020-10-23
    • 2018-04-14
    • 2019-06-05
    • 2015-12-17
    • 2021-12-14
    • 1970-01-01
    • 2015-03-14
    • 2015-11-10
    • 1970-01-01
    相关资源
    最近更新 更多