Счетчики с высоким параллелизмом без шардинга - PullRequest
14 голосов
/ 05 мая 2010

Этот вопрос касается двух реализаций счетчиков, которые предназначены для масштабирования без шардинга (с компромиссом, который они могут недооценивать в некоторых ситуациях):

  1. http://appengine -cookbook.appspot.com / recipe / счетчики с высоким уровнем параллелизма без шардинга / (код в комментариях)
  2. http://blog.notdot.net/2010/04/High-concurrency-counters-without-sharding

Мои вопросы:

  • В отношении # 1: Выполнение memcache.decr() в отложенной транзакционной задаче кажется излишним. Если memcache.decr() выполняется вне транзакции, я думаю, что в худшем случае транзакция завершится неудачно, и мы пропустим подсчет того, что мы уменьшили. Я пропускаю какую-то другую проблему, которая может возникнуть при этом?
  • Каковы существенные компромиссы между двумя реализациями?

Вот компромиссы, которые я вижу:

  • 2 не требует транзакций хранилища данных.

  • Чтобы получить значение счетчика, # 2 требует выборки из хранилища данных, в то время как с # 1 обычно требуется только memcache.get() и memcache.add().
  • При увеличении счетчика оба вызывают memcache.incr(). Периодически # 2 добавляет задачу в очередь задач, в то время как # 1 транзакционно выполняет получение и установку хранилища данных. # 1 также всегда выполняет memcache.add() (чтобы проверить, настало ли время сохранить счетчик в хранилище данных).

Выводы

(без каких-либо тестов производительности):

  • 1 обычно должен быть быстрее при извлечении счетчика (# 1 memcache против # 2 хранилища данных). Хотя № 1 должен выполнить дополнительно memcache.add().

  • Однако # 2 должен быть быстрее при обновлении счетчиков (# 1 хранилище данных get + put vs # 2 ставит задачу в очередь).
  • С другой стороны, с # 1 вам нужно быть немного более осторожным с интервалом обновления, поскольку квота очереди задач почти в 100 раз меньше, чем в API хранилища данных или memcahce.

Ответы [ 2 ]

1 голос
/ 05 июня 2010

Переход в хранилище данных, вероятно, будет более дорогим, чем использование memcache. Иначе memcache не был бы таким уж полезным: -)

Я бы порекомендовал первый вариант.

Если у вас разумный уровень запросов, вы можете реализовать его еще проще:

1) update the value in memcache
2) if the returned updated value is evenly divisible by N
2.1) add N to the datastore counter
2.2) decrement memcache by N

Предполагается, что вы можете установить достаточно длительный тайм-аут в своей кэше памяти, чтобы он жил между последовательными событиями, но если события настолько редки, что время вашей памяти кэша истекло, скорее всего, вам не понадобится счетчик "высокого параллелизма": -)

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

При использовании memcache, однако, имейте в виду, что некоторые клиентские API предполагают, что тайм-аут в одну секунду означает, что значение отсутствует. Если пакет TCP SYN для экземпляра memcache будет отброшен, это означает, что ваш запрос ошибочно предположит, что данных там нет. (Подобные проблемы могут возникнуть с UDP для memcache)

0 голосов
/ 27 мая 2010

Memcache сбрасывается, вы теряете счетчик. УЧ. Использование базы данных mysql или решения NOSQL решит эту проблему с возможным падением производительности. (Redis, Tokyotyrant, MongoDB и т. Д.) Могут не иметь такой производительности.

Имейте в виду, вы можете сделать 2 действия:

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