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

时间:2015-09-01 09:07:33

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

我正在对具有500000行的表进行读取和更新查询,并且在处理大约300000行后有时会出现以下错误,即使没有节点关闭也是如此。

  

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

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

Cassandra 2.1.8.621 | DSE 4.7.1 | Spark 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语句:

创建表格

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';

2 个答案:

答案 0 :(得分:9)

通常当你收到超时错误时,这意味着你正在尝试做一些在Cassandra中不能很好地扩展的东西。修复通常是修改您的架构。

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

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

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

答案 1 :(得分:-1)

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

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

建议仔细考虑设计表结构之前预期会运行的具体查询。

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

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

第一个:

  

SELECT encounter_uuid,encounter_start_date FROM section_ks.encounters   WHERE patient_id ='1234'和encounter_start_date> ='“+   formatted_documentation_date +“'允许过滤;

  • 第一点,如果Cassandra强迫您添加ALLOW FILTERING,那就是非最佳查询或表结构的符号。
  • 第二点。首要的关键。关于what are primary keys in Cassandra给定查询的一个很棒的解释可以快速和快速地工作如果 patient_id 列和 encounter_start_date 列将形成复合主键,则不使用强制ALLOW FILTERING语句。 枚举PRIMARY KEY()语句中的列应与查询中的过滤顺序相对应。
  • 为什么在原始查询中必须允许过滤?通过分区密钥,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 列将是“群集密钥”负责分区内的数据排序。

现在可以从查询中删除允许过滤:

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

第二次查询:

  

UPDATE section_ks.encounters SET testproblem_uuid_set =   testproblem_uuid_set + {'1256'} WHERE encounter_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 进行快速过滤,则应将其定义为分区键。

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