Тайм-аут Cassandra во время запроса чтения при согласованности ОДИН (требуется 1 ответ, но ответила только 0 реплика)

Я выполняю запросы на чтение и обновление в таблице, содержащей 500000 строк, и иногда получаю ошибку ниже после обработки около 300000 строк, даже если ни один узел не отключен.

Тайм-аут Cassandra во время запроса на чтение при согласованности ONE (требуется 1 ответ, но только 0 реплик)

Сведения об инфраструктуре:
Наличие 5 узлов Cassandra, 5 узлов Spark и 3 узлов Hadoop, каждый с 8 ядрами и 28 ГБ памяти, и коэффициент репликации 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 (мс) до 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';


person Abhinandan Satpute    schedule 01.09.2015    source источник
comment
Можете ли вы опубликовать свою таблицу создания   -  person phact    schedule 01.09.2015
comment
... и ваш запрос, и я также попробую TRACING ON проанализировать проблему.   -  person uri2x    schedule 01.09.2015
comment
@phact Я добавил создать таблицу. Спасибо за ответ.   -  person Abhinandan Satpute    schedule 02.09.2015
comment
@ uri2x также добавил запрос.   -  person Abhinandan Satpute    schedule 02.09.2015
comment
Не используйте разрешающую фильтрацию в производственных запросах oltp. Это будет медленно. Вместо этого вам следует разработать первичный ключ вашей таблицы (разделение и кластеризацию) так, чтобы вы могли использовать обычный запрос CQL.   -  person phact    schedule 02.09.2015
comment
@phact - учту ваше предложение и постараюсь его реализовать.   -  person Abhinandan Satpute    schedule 02.09.2015


Ответы (2)


Обычно, когда вы получаете ошибку тайм-аута, это означает, что вы пытаетесь сделать что-то, что плохо масштабируется в Cassandra. Часто исправление заключается в изменении вашей схемы.

Я предлагаю вам контролировать узлы во время выполнения вашего запроса, чтобы увидеть, можете ли вы определить проблемную область. Например, вы можете запустить «watch -n 1 nodetool tpstats», чтобы увидеть, выполняется ли резервное копирование или отбрасывание элементов в каких-либо очередях. См. Другие предложения по мониторингу здесь.

Одна вещь, которая может быть отключена в вашей конфигурации, - это то, что вы говорите, что у вас пять узлов Cassandra, но только 3 искровых воркера (или вы говорите, что у вас есть три искровых воркера на каждом узле Cassandra?). Вам понадобится хотя бы один искровый воркер. каждый узел Cassandra, так что загрузка данных в Spark выполняется локально на каждом узле, а не по сети.

Трудно сказать что-то большее, не видя схемы и выполняемого запроса. Вы читаете с одного раздела? Я начал получать ошибки тайм-аута около 300 000 строк при чтении из одного раздела. См. Вопрос здесь. Единственный обходной путь, который я нашел до сих пор, - это использовать хэш на стороне клиента в моем ключе раздела, чтобы разбить разделы на более мелкие фрагменты примерно по 100 тыс. Строк. До сих пор я не нашел способа сказать Кассандре, что не следует истекать тайм-аут для запроса, который, как я ожидаю, займет много времени.

person Jim Meyer    schedule 01.09.2015
comment
Большое спасибо. Я попробую ваши предложения. Извините за неверную / краткую информацию о кластере. Фактически, кластер EC2, имеющий 5 узлов Cassandra, 5 рабочих узлов Spark, из которых 2 рабочих узла Spark находятся на 2 узлах Cassandra, а остальные 3 узла имеют на нем рабочих Hadoop и Spark. Извините, но как проверить, из скольких разделов считываются данные? - person Abhinandan Satpute; 02.09.2015
comment
cfstats и cfhistograms - person phact; 02.09.2015
comment
@Abhinandan - Ваше использование РАЗРЕШЕНИЯ ФИЛЬТРАЦИИ предполагает, что вы пытаетесь выполнить сканирование таблицы. Это неэффективно в Cassandra, поэтому вам следует либо реструктурировать схему, чтобы выполнять запросы к отдельным разделам, либо загрузить таблицу в искровой RDD, чтобы с ней можно было работать параллельно. - person Jim Meyer; 02.09.2015
comment
@JimMeyer - я запустил watch -n 1 nodetool tpstats и вижу, что ни одна очередь не выполняет резервное копирование и не отбрасывает какой-либо элемент. Я загрузил таблицу только в Spark RDD, а затем выполняю запрос. Есть ли какое-либо обходное решение, кроме реструктуризации схемы? - person Abhinandan Satpute; 02.09.2015
comment
Я изменил concurrent_reads с 64 на 128, с 20 ядрами, и теперь он не дает никаких ошибок. Это реальное решение? - person Abhinandan Satpute; 02.09.2015
comment
Вы получали ошибку тайм-аута в запросе CQL или при загрузке данных в Spark? Я раньше не экспериментировал с concurrent_reads. Главное, что следует учитывать, - действительно ли вам нужно полное сканирование таблицы или вы можете разделить данные на более мелкие части, которые можно запросить с меньшими затратами. Если это так, то имеет смысл пересмотреть вашу схему. - person Jim Meyer; 02.09.2015
comment
У меня есть искровое задание, которое выполняет запросы на чтение, запись и обновление, которое через некоторое время дает ошибку тайм-аута чтения. Мне нужно прочитать полную таблицу, поскольку от этого зависят запросы на обновление. - person Abhinandan Satpute; 03.09.2015

Не думайте, что конфигурация является основной причиной, а проблема с моделью данных.

Было бы здорово увидеть структуру таблицы section_ks.encounters.

Рекомендуется тщательно подумать о том, какие конкретные запросы должны выполняться, прежде чем создавать структуру таблиц.

Насколько я понимаю, эти два запроса предполагают разную структуру section_ks.encounters, чтобы выполнять их с хорошей производительностью.

Давайте рассмотрим каждый предоставленный запрос и попробуем создать таблицы:

Первый:

ВЫБЕРИТЕ meet_uuid, meet_start_date FROM section_ks.encounters WHERE Patient_id = '1234' И meet_start_date> = '"+ formatted_documentation_date +"' РАЗРЕШИТЬ ФИЛЬТРАЦИЮ;

  • Во-первых, если Кассандра вынуждает вас добавить РАЗРЕШЕННУЮ ФИЛЬТРАЦИЮ, это симхтом неоптимальной структуры запроса или таблицы.
  • Второй момент. Основной ключ. Прекрасное объяснение что такое первичные ключи в Cassandra. Данный запрос будет работать быстро и без обязательного оператора ALLOW FILTERING, если Patient_id столбец и столбец begin_start_date образуют составной первичный ключ. Перечисление столбцов внутри оператора PRIMARY KEY () должно соответствовать порядку фильтрации в вашем запросе.
  • Почему РАЗРЕШИТЬ ОБЯЗАТЕЛЬНУЮ ФИЛЬТРАЦИЮ в исходном запросе? По ключу раздела Кассандра знает, на каком узле расположены данные. В случае, когда столбец 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. Проще говоря (без функции репликации): разные диапазоны пациентов будут храниться на разных узлах.
  • Столбец begin_start_date будет «ключом кластеризации», ответственным за сортировку данных внутри раздела.

РАЗРЕШИТЬ ФИЛЬТРАЦИЮ теперь можно убрать из запроса:

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

Второй запрос:

ОБНОВЛЕНИЕ section_ks.encounters УСТАНОВИТЬ testproblem_uuid_set = testproblem_uuid_set + {'1256'} ГДЕ meet_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)
);

Если мы определенно хотим сделать быструю фильтрацию только по meet_uuid, ее следует определить как ключ раздела.

Хорошие статьи о проектировании эффективной модели данных:

person Yurii Bratchuk    schedule 19.08.2017