Ошибка запроса Кассандры (надгробия)

Так что это сводит меня с ума. Я попытался запросить одну из моих таблиц в Кассандре, и она показала сбой запроса. Я попытался докопаться до причины этого и обнаружил, что это из-за надгробия. Я изменил GC_GRACE_SECONDS на ноль и запустил сжатие с помощью nodetool, и когда я снова запросил, он работал нормально. однако при последующих вызовах запрос снова не удался по той же причине. Я использую драйвер cassandra-nodejs. Это моя модель данных.

CREATE TABLE my_table (
    firstname text,
    lastname text,
    email text,
    mobile text,
    date timeuuid,
    value float,
    PRIMARY KEY (firstname, lastname, email, mobile)
) WITH CLUSTERING ORDER BY (lastname ASC, email ASC, mobile ASC);

это запрос, который я хочу выполнить для этой модели данных.

SELECT firstname, email, toDate(date) as date, mobile, value FROM my_table  WHERE date >= minTimeuuid('2017-03-25 00:00:00+0000') AND date <= minTimeuuid('2017-03-28 23:59:59+0000') ALLOW FILTERING;

в результате будет примерно 40 тыс. строк. это показывает, что если мы удаляем что-то, это будет помечено как надгробие и будет удалено после установки GC_GRACE_SECONDS для данной таблицы. Если я правильно понимаю, тогда.

  1. Почему возникает проблема с надгробиями, когда я никогда не удаляю ни одной строки таблицы?
  2. Верно ли, что строка будет помечена как Надгробие тогда и только тогда, когда мы удалим строку?
  3. очистка надгробий с последующим запросом тех же результатов иногда работает, а иногда нет, почему так?
  4. это хорошая идея увеличить значение tombstone_failure_threshold? (одноузловое кластерное приложение)

Я использую cassandra 3.5 с версией cqlsh 5.0.1. И запрос отлично работает с терминалом, но выдает ошибку, когда мы выполняем с использованием внешнего клиента (экспресс-приложение с использованием драйвера nodejs для cassandra). у меня есть одноузловое кластерное приложение.

РЕДАКТИРОВАТЬ 1

Это журнал моего вставленного нулевого значения в поле (я вставил только имя и временную метку);

  activity                                                                                        | timestamp                  | source        | source_elapsed
-------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------
                                                                              Execute CQL3 query | 2017-03-29 10:28:27.342000 | 172.31.34.179 |              0
                   Parsing select * FROM testtomb WHERE name = 'Dhaval45'; [SharedPool-Worker-2] | 2017-03-29 10:28:27.342000 | 172.31.34.179 |             64
                                                       Preparing statement [SharedPool-Worker-2] | 2017-03-29 10:28:27.342000 | 172.31.34.179 |            101
                              Executing single-partition query on testtomb [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 |            210
                                              Acquiring sstable references [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 |            223
 Skipped 0/0 non-slice-intersecting sstables, included 0 due to tombstones [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 |            243
                                 Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 |            288
                                         Read 2 live and 0 tombstone cells [SharedPool-Worker-3] | 2017-03-29 10:28:27.342001 | 172.31.34.179 |            310
                                 Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:28:27.342001 | 172.31.34.179 |            323
                                                                                Request complete | 2017-03-29 10:28:27.342385 | 172.31.34.179 |            385

И это журнал, когда я запрашиваю поле, в котором я выполнил запрос на удаление. Первоначально пользователь Dhaval15 имеет имя «aaaa», а затем - ячейку aaa. затем снова выполнение запроса выбора для того же пользователя дало мне этот журнал.

       activity                                                                                        | timestamp                  | source        | source_elapsed
-------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------
                                                                              Execute CQL3 query | 2017-03-29 10:35:18.581000 | 172.31.34.179 |              0
                   Parsing select * FROM testtomb WHERE name = 'Dhaval15'; [SharedPool-Worker-1] | 2017-03-29 10:35:18.581000 | 172.31.34.179 |             65
                                                       Preparing statement [SharedPool-Worker-1] | 2017-03-29 10:35:18.581000 | 172.31.34.179 |            113
                              Executing single-partition query on testtomb [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 |            223
                                              Acquiring sstable references [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 |            235
 Skipped 0/0 non-slice-intersecting sstables, included 0 due to tombstones [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 |            256
                                 Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 |            305
                                         Read 1 live and 1 tombstone cells [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 |            338
                                 Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 |            351
                                                                                Request complete | 2017-03-29 10:35:18.581430 | 172.31.34.179 |            430

person Dhaval P    schedule 29.03.2017    source источник
comment
Не могли бы вы предоставить сообщение об ошибке? Журнал исключений, который создается.   -  person Chaity    schedule 29.03.2017
comment
Я продолжаю получать Операция не удалась - получено 0 ответов и 1 сбой. Параметр {traceQuery: true} почему-то не работает, и на терминале запрос выполняется успешно   -  person Dhaval P    schedule 29.03.2017


Ответы (2)


В Cassandra надгробие создается, даже если вы не выполняете запрос на удаление, когда вы вставляете нулевое значение.

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

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

Измените свою модель данных, как показано ниже:

CREATE TABLE my_table (
    year int,
    month int,
    date timeuuid,
    email text,
    firstname text,
    lastname text,
    mobile text,
    value float,
    PRIMARY KEY ((year, month), date)
);

Здесь вы можете указать год и месяц, извлечение из даты.
Теперь вы можете запросить с указанием ключа раздела:

SELECT * FROM my_table WHERE year = 2017 AND month = 03 AND date >= minTimeuuid('2017-03-25 00:00:00+0000') AND date <= minTimeuuid('2017-03-28 23:59:59+0000') ;

Это даст результат очень эффективно и не подведет.

Если вам нужно запросить имя и фамилию, создайте для них индекс

CREATE INDEX index_firstname ON my_table (firstname) ;
CREATE INDEX index_lastname ON my_table (lastname) ;

Затем вы можете запросить имя или фамилию

SELECT * FROM my_table WHERE firstname = 'ashraful' ;
SELECT * FROM my_table WHERE lastname  = 'islam' ;

Здесь я не создавал индекс по электронной почте и телефону из-за проблемы с высокой мощностью. Вместо этого создайте материализованное представление или другую таблицу для запроса по телефону или электронной почте.

CREATE MATERIALIZED VIEW mview_mobile AS
    SELECT *
    FROM my_table
    WHERE mobile IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND date IS NOT NULL
    PRIMARY KEY (mobile, year, month, date);


CREATE MATERIALIZED VIEW mview_email AS
        SELECT *
        FROM my_table
        WHERE email IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND date IS NOT NULL
        PRIMARY KEY (email, year, month, date);

Теперь вы можете делать запросы по телефону или электронной почте

SELECT * FROM mview_mobile WHERE mobile = '018..';
SELECT * FROM mview_email WHERE email = 'ashraful@...';

Подробнее о надгробной плите кассандры: http://thelastpickle.com/blog/2016/07/27/about-deletes-and-tombstones.html

person Ashraful Islam    schedule 29.03.2017
comment
Я попробую, но все еще не понимаю, что иногда очистка надгробий работает, а иногда нет? почему так? - person Dhaval P; 29.03.2017
comment
Надгробные плиты занимают место. Когда вы выполняете выборочный запрос, кассандре необходимо отфильтровать данные по надгробным камням. Если сгенерировано огромное надгробие, производительность выбранного вами запроса снизится. - person Ashraful Islam; 29.03.2017
comment
если я не хочу менять структуру таблицы, есть ли другой способ? - person Dhaval P; 29.03.2017
comment
Затем проверьте все инструкции вставки и обновления, убедитесь, что не вставлено нулевое значение. - person Ashraful Islam; 29.03.2017
comment
Спасибо за уделенное время :) - person Dhaval P; 29.03.2017
comment
Как насчет того, чтобы смоделировать свою таблицу как этот ПЕРВИЧНЫЙ КЛЮЧ ((имя, фамилия, адрес электронной почты, мобильный, дата)), то есть я использую несколько первичных ключей, а не какой-либо ключ кластеризации? это вызовет проблемы? - person Dhaval P; 29.03.2017
comment
Тогда вы не сможете использовать какой-либо запрос, не указав имя, фамилию, адрес электронной почты, мобильный телефон и дату. Тогда вы должны использовать РАЗРЕШЕННУЮ ФИЛЬТРАЦИЮ, что очень дорого и не рекомендуется. - person Ashraful Islam; 29.03.2017
comment
Я попытался покопаться, но обнаружил, что надгробные плиты создаются только при удалении ячейки / строки. Итак, как они влияют на мой случай. - person Dhaval P; 29.03.2017
comment
В основном на вас влияют две вещи: первая РАЗРЕШИТЬ ФИЛЬТРАЦИЮ и вторая надгробная плита. - person Ashraful Islam; 29.03.2017
comment
да, это правда, но я не считаю, что надгробие создается при вставке .. это правда? - person Dhaval P; 29.03.2017
comment
Если вы вставите только имя и метку времени, надгробие не будет создано, но если вы явно вставите значение null, надгробие будет создано как insert into (pk1,pk2, ck1,ck2, d1,d2) values(1,10,100,1000, null,null); - person Ashraful Islam; 29.03.2017
comment
в чем смысл создания индекса? скажем, я хочу получить диапазон значений, и я проиндексировал столбец значений. мне в конечном итоге придется использовать разрешающую фильтрацию, верно? в этом случае (без разрешения фильтрации) мне придется использовать материализованное представление для поддержки такого рода запросов, верно? - person Dhaval P; 30.03.2017

  1. Почему возникает проблема с надгробиями, когда я никогда не удаляю ни одной строки таблицы?

Ответ @Ashraful Ислама правильный.

Кроме того, если вы явно вставляете данные со значениями NULL, это внутренне создает надгробные камни.

Пример: вставить в my_table (имя, фамилия, электронная почта, мобильный, .....) значения ('abd', 'gef', '[email protected]', '+67899 ...', null, null, .....);

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

Как вы упомянули, слишком много столбцов в качестве первичных ключей, это создаст слишком большие широкие строки (что также не рекомендуется) со слишком большим количеством нулевых значений, что приведет к появлению большого количества надгробий. В вашем случае он мог превысить пороговый предел.

Как заявил @Ashraful, эта модель данных не подходит. Поскольку вам нужно выполнять запросы по времени, вы должны разработать свою модель таким образом, чтобы вы могли выполнять некоторые запросы по диапазону вовремя. Запрос без упоминания ключа раздела, таким образом, используя РАЗРЕШЕННУЮ ФИЛЬТРАЦИЮ в большом наборе данных, является анти-шаблоном в Cassandra.

  1. Верно ли, что строка будет помечена как Надгробие тогда и только тогда, когда мы удалим строку?

Вы можете удалить весь столбец или отдельный столбец. Если строка удалена, вся строка помечается как надгробие. Если определенный столбец удаляется (или вставляется / обновляется значение NULL), надгробные камни будут созданы в этом конкретном столбце (что также не рекомендуется), я думаю, это произойдет в вашем случае.

  1. очистка надгробий с последующим запросом тех же результатов иногда работает, а иногда нет, почему так?

Думаю, теперь вы можете определить, почему это происходит :).

  1. это хорошая идея увеличить значение tombstone_failure_threshold? (одноузловое кластерное приложение)

Увеличение tombstone_failure_threshold только уменьшит количество ошибок, но не решит фактическую проблему. Это не увеличит производительность и не пересечет пороговое значение по мере увеличения набора данных.

И, что важно, в приложении кластера с одним узлом вы можете установить GC_GRACE_SECONDS на 0. Надгробные камни будут удалены сразу после того, как произойдет сжатие. GC_GRACE_SECONDS жизненно важен при использовании многоузлового кластера, что, как я полагаю, является реальной целью использования NoSQL.

person Chaity    schedule 29.03.2017
comment
Спасибо за потраченное время :) и да, может случиться так, что в каждой строке слишком много нулевых столбцов - person Dhaval P; 29.03.2017
comment
Я думаю, прежде чем моделировать свои данные в Cassandra, вы должны следовать некоторым основным правилам. Об этом написано так много статей. Вы поместили все столбцы в качестве ключа раздела, что означает, что вы ограничили запрос (вы должны указать все столбцы в предложении where). Можете ли вы представить все ценности? Опять же, это не решает проблему разрешающей фильтрации. Вы по-прежнему не можете выполнить запрос диапазона по времени. Для поддержки вашего запроса вам все равно нужно читать данные без упоминания ключа раздела, поэтому в конечном итоге вы используете РАЗРЕШЕННУЮ ФИЛЬТРАЦИЮ. - person Chaity; 29.03.2017
comment
К вашему сведению, C * использует ключ раздела, чтобы найти узел, в котором находится запрошенная строка. Теперь вы должны указать все значения, чтобы сообщить C *, какой узел она должна запросить для получения данных. Опять же, вы уже изменили структуру данных. тогда почему бы не изменить модель по вашему запросу :) - person Chaity; 29.03.2017
comment
да, я не против его изменить. но немного любопытно узнать о вещах. - person Dhaval P; 29.03.2017
comment
Убедитесь, что вы явно вставляете нулевые значения. Посмотрите пример, который я привел в своем ответе. - person Chaity; 29.03.2017
comment
Вы не можете предоставить нулевые значения в первичном ключе. Проверьте, вставлен ли столбец "дата" нулевым. Пример: вставить в my_table (имя, фамилия, электронная почта, мобильный телефон, дата) значения ('abd', 'gef', '[email protected]', '+67899 ...', null); - person Chaity; 29.03.2017