Как быстро увеличить счетчики в Cassandra без устаревания

У меня есть вопрос о Кассандре. Знаете ли вы, как Кассандра делает обновления / приращения счетчиков?

Я хочу использовать штормовой болт (CassandraCounterBatchingBolt из репозитория шторм-вклад на github), который записывает в Кассандру. Тем не менее, я не уверен, как некоторые из реализаций метода incrementCounterColumn() работают.. и есть также ограничения со счетчиками cassandra (от: http://wiki.apache.org/cassandra/Counters), которые делают их бесполезно для моего сценария ИМХО

  • Если запись не удалась неожиданно (тайм-аут или потеря соединения с узлом-координатором), клиент не будет знать, была ли выполнена операция. Повторная попытка может привести к избыточному количеству CASSANDRA-2495.

  • Удаление счетчика изначально ограничено. Например, если вы выполните очень быстро последовательность "приращение, удаление, приращение", удаление может быть потеряно.

Во всяком случае, вот мой сценарий:
Я обновляю тот же счетчик быстрее, чем обновления распространяются на другие узлы Кассандры.

Пример:
Скажем, у меня есть 3 узла кассандры. Счетчики на каждом из этих узлов равны 0.
Узел 1:0, узел 2:0, узел 3:0

Прибавляется: 5 -> Узел1:0, узел2:0, узел3:0

Инкремент начинается на узле 2 - все еще должен распространяться на узел 1 и узел 3
Узел 1:0, узел 2:5, узел 3:0

В то же время, другой прирост прибывает до предыдущего приращения
распространяется: 3 -> Узел1:0, узел2:5, узел3:0

Предполагая, что 3 запускается в другом узле, чем 5, где мы начали:
Узел 1: 3, узел 2:5, узел 3:0

Теперь, если 3 распространяется на другие узлы как ДОХОД, а не как новое значение (и то же самое для 5), то в конечном итоге все узлы будут равны 8, и это то, что я хочу.

Если 3 перезаписывает 5 (потому что у него более поздняя временная метка), это проблематично, а не то, что я хочу.

Знаете ли вы, как Cassandra обрабатывает эти обновления / приращения?

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

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

3 ответа

Решение

Счетчики в C* имеют сложное внутреннее представление, которое позволяет избежать большинства (но не всех) проблем подсчета вещей в распределенной системе без лидера. Мне нравится думать о них как о приколах. Счетчик состоит из нескольких вспомогательных счетчиков, идентифицированных идентификатором хоста и номером версии. Хост, который получает операцию счетчика, увеличивает только свой собственный вспомогательный счетчик, а также увеличивает версию. Затем он копирует все свое состояние счетчика на другие реплики, которые объединяют его со своими состояниями. Когда счетчик считывается, узел, обрабатывающий операцию чтения, определяет значение счетчика путем суммирования суммы отсчетов от каждого хоста.

На каждом узле приращение счетчика точно так же, как и все остальное в Кассандре, просто запись. Приращение записывается в memtable, а локальное значение определяется во время чтения путем слияния всех приращений из memtable и всех SSTable.

Я надеюсь, что это объяснение поможет вам поверить мне, когда я скажу, что вам не нужно беспокоиться об увеличении счетчиков быстрее, чем справится Кассандра. Поскольку каждый узел хранит свой собственный счетчик и никогда не реплицирует операции приращения, нет никакой вероятности того, что счетчики будут потеряны из-за условий гонки, как в сценарии чтения-изменения-записи. Если Кассандра примет запись, вы в значительной степени будете уверены, что она будет засчитана.

Тем не менее, вы не гарантированы тем, что число будет отображаться правильно, если только. Если приращение записывается на один узел, а значение счетчика считывается с другого сразу после него, нет гарантии, что приращение было реплицировано, и вам также необходимо учитывать, что произойдет во время сетевого раздела. Это более или менее то же самое с любой записью в Cassandra, она в конечном итоге непротиворечива и зависит от того, какие уровни согласованности вы использовали для операций.

Существует также возможность потерянного подтверждения. Если вы сделаете шаг и потеряете соединение с Cassandra до того, как сможете получить ответ, вы не сможете узнать, получена ваша запись или нет. И когда вы получаете соединение обратно, вы тоже не можете сказать, так как вы не знаете, сколько было до того, как вы увеличили. Это неотъемлемая проблема систем, которые выбирают доступность вместо согласованности, а также цену, которую вы платите за многие другие преимущества.

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

Вот хорошее руководство по внутренним элементам счетчиков Кассандры: http://www.datastax.com/wp-content/uploads/2011/07/cassandra_sf_counters.pdf

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

Существуют операции увеличения и уменьшения, которые не будут сталкиваться друг с другом, и, исключая любые потерянные мутации или воспроизводимые мутации, вы получите правильный результат.

Перезапись счетчиков Кассандры ( https://issues.apache.org/jira/browse/CASSANDRA-6504) может быть интересна для вас, и она должна решить все текущие проблемы с получением правильного счетчика.

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

Это увеличивает нагрузку на сторону чтения, хотя она чрезвычайно эффективна на пути записи, поэтому может работать или не работать в вашем случае использования.

Чтобы понять обновления / приращения, т.е. операции записи, я предлагаю вам пройти через Gossip, протокол, используемый Cassandra для связи. В Сплетне каждый участник (узел) поддерживает свое состояние, используя кортеж σ(K) = (V*N) где σ(K) это состояние K ключ с V значение и N как номер версии.

Чтобы поддерживать единую версию истины для пакета данных, Gossip поддерживает механизм согласования, а именно Precise & Scuttlebutt(ток). В соответствии с Scuttlebutt Reconciliationперед обновлением любого кортежа они общаются друг с другом, чтобы проверить, кто владеет самой высокой версией (самым новым значением) ключа. Тот, кто держит наивысшую версию, отвечает за операцию записи.

Для получения дополнительной информации прочитайте эту статью.

Другие вопросы по тегам