2014-12-01 2 views
2

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

Мы хотели бы получить ОБЗОРЫ от наших ПОЛЬЗОВАТЕЛЕЙ по поводу некоторых ДОКУМЕНТОВ, которые мы собираемся опубликовать. Для каждой статьи мы ищем 3 отзыва. Но мы отправляем отзыв на 3 * 2 = 6 пользователей. Все 6 пользователей могут отправлять свои отзывы в нашу систему, но только первые 3 счета; и эти первые 3 рецензента получат вознаграждение за свою работу.

В нашем Cassandra DB есть три таблицы: USER, PAPER и REVIEW. Таблицы USER и PAPER просты: каждый пользователь соответствует строке в таблице USER с уникальным USER_ID; аналогично, каждая бумага имеет уникальный PAPER_ID в таблице PAPER.

В обзоре таблица выглядит следующим образом

CREATE TABLE REVIEW(
    PAPER_ID uuid, 
    USER_ID uuid, 
    REVIEW_CONTENT text, 
    PRIMARY KEY(PAPER_ID, USER_ID) 
    ); 

Мы используем PAPER_ID в качестве ключа секционирования таблицы REVIEW так, что все отзывы о данной работе хранятся в одном Кассандре ряда. Для каждой бумаги мы получаем 6 пользователей, вставляем 6 записей в таблицу REVIEW и отправляем 6 приглашений этим пользователям. Таким образом, для бумаги «P1», есть 6 записей в таблице ОБЗОРНОЙ, которые выглядят так

---------------------------------------------------- 
PAPER_ID  | USER_ID  | REVIEW_CONTENT | 
---------------------------------------------------- 
P1   | U1    |  null  | 
---------------------------------------------------- 
P1   | U2    |  null  | 
---------------------------------------------------- 
P1   | U3    |  null  | 
---------------------------------------------------- 
P1   | U4    |  null  | 
---------------------------------------------------- 
P1   | U5    |  null  | 
---------------------------------------------------- 
P1   | U6    | This paper ... | 
--------------------------------------------------- 
...   | ...   | ...    | 

пользователей отправить отзыв через веб-браузер, используя HTTP. На внутреннем интерфейсе, мы используем следующий процесс для обработки представленных обзоров (использование бумаги «P1» в качестве примера):

  1. Используйте клавишу раздел «P1», чтобы получить все 6 записей из таблицы обзора.
  2. Узнайте, сколько из этих 6 записей имеет ненулевые значения в столбце REVIEW_CONTENT (ненулевые значения указывают, что соответствующий пользователь уже отправил свой отзыв. Например, в приведенной выше таблице пользователь «U6» отправил его обзор, в то время как другие 5 еще не были).
  3. Если это число> = 3, у нас уже было достаточно отзывов, вернитесь к текущему обозревателю с сообщением типа «Спасибо, у нас уже было достаточно отзывов».
  4. Если этот номер < 2, сохраните текущий отзыв в соответствующей записи в таблице REVIEW, вернитесь к рецензенту с сообщением типа «Ваш отзыв был принят». (Например, если текущий рецензент «U1», затем заполните столбец REVIEW_CONTENT записи «P1, U1» текущим содержимым обзора.)
  5. Если это число = 2, это самый сложный случай, поскольку текущая передача это последний, который мы примем. В этом случае мы сначала сохраняем текущий обзор в таблице REVIEW, затем находим идентификаторы всех трех пользователей, которые отправили обзоры (включая текущего пользователя), запишите их идентификаторы в таблицу транзакций, чтобы выплатить им вознаграждение позже.

Но этот процесс не работает. Проблема в том, что он не обрабатывает параллельные представления правильно. Рассмотрим следующий случай: два пользователя уже отправили свои отзывы, а между тем 3 других пользователя отправляют свои обзоры через три одновременных процесса, показанных выше. На шаге 5 каждый из трех будет считать, что он является третьим и последним подателем и вставляет новые записи в таблицу транзакций. Это приводит к двойному счету: один пользователь может быть вознагражден более одного раза за тот же обзор, который он представил.

Другой проблемой этого процесса является то, что он может никогда не достигнуть шага 5. Предположим, что нет никакой информации в таблице REVIEW, и 4 пользователя отправляют свои обзоры одновременно. Все они сохранили свои отзывы на шаге 4.После этого позже отправитель будет всегда отклонен, так как уже есть 4 принятых отзыва. Но так как мы никогда не достигли шага 5, никакие идентификаторы не будут записаны в таблицу транзакций, и пользователи никогда не получат никаких наград.

Итак, вот мой вопрос: как я должен обрабатывать свой прецедент, используя Cassandra в качестве внутренней базы данных? Помог ли Cassandra COUNTER? Если да, то как? Я еще не подумал, как использовать COUNTER, но этот блог() предупредил, что Cassandra COUNTER небезопасен (цитата «Следовательно, счетчики Cassandra будут перегружены или подсчитаны по широкому диапазону во время сетевого раздела».) Будет ли Справка Cassandra's Compare and Set (CAS) поможет? Если да, то как? Опять же блог с сохранением предупреждал, что «легкие транзакции Cassandra даже не близки к правильным».

ответ

1

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

CREATE TABLE review(
    paper_id uuid, 
    submission_time timeuuid, 
    user_id uuid, 
    content text, 
    PRIMARY KEY (paper_id, submission_time) 
); 

Когда пользователь делает их представление, добавить запись в таблицу. Затем ПОСЛЕ успешной записи запросите таблицу (только на paper_id) и узнайте, является ли идентификатор пользователя одним из первых трех. Отвечайте на пользователя соответственно. Поскольку вы привержены небольшому набору рецензентов, дополнительные накладные расходы на выборку всех обзоров должны быть минимальными (особенно потому, что вам не нужно включать столбец содержимого в запрос).

Если вам нужно отслеживать, кто просматривает документы, добавьте набор идентификаторов пользователей на бумажный стол и напишите шесть идентификаторов пользователя.

+0

Мне нравится ваше решение. Похоже, что общий принцип разработки для Cassandra заключается в том, что он всегда добавляется к таблице, старайтесь не обновлять ее. Один быстрый вопрос: что произойдет, если один рецензент X успешно представит свой обзор, но когда следующий обзор Y выберет все отзывы, вновь представленный обзор X не включен из-за сетевых задержек? Я предполагаю, что это может произойти. Будет ли помощь ConsistencyLevel.ALL? – user3839198

+0

Поскольку ваш случай использования требует такого уровня согласованности, я бы рекомендовал писать и читать в QUORUM. Предполагая, что у вас есть 3 или более реплик (стандартный), это даст вам идеальную последовательность, не имея хрупкости ALL. То, где вы создаете метку времени, также оказывает влияние. В этом случае было бы лучше использовать функцию CQL [now()] (http://www.datastax.com/documentation/cql/3.0/cql/cql_reference/timeuuid_functions_r.html). С этими двумя соображениями (и NTP), я думаю, вы должны быть очень близки к гарантированному уровню согласованности. – mildewey

+0

Если «очень близко» просто не режет его для вас, прочитайте [Новые транзакции Кассандры] (http://www.datastax.com/dev/blog/lightweight-transactions-in-cassandra-2- 0). – mildewey