Как отследить просмотр страницы с помощью Google App Engine?

У меня есть веб-приложение, которое позволяет пользователям отправлять сообщения в блоге. Я хотел бы отслеживать просмотры страниц каждой страницы блога. Итак, когда некоторые посещения:

/post/123

Посетитель должен видеть количество людей, посетивших эту страницу.

Одно, казалось бы, не масштабируемое решение, о котором я подумал, - это добавить свойство page_views к виду Blog:

class Blog(ndb.Model):
    title = ndb.StringProperty()
    page_views = ndb.IntegerProperty()

Затем при каждом посещении страницы просто blog.page_views плюс 1. Тогда blog.put(), Однако эта попытка будет означать, что мы будем слишком часто писать в БД.

Есть ли способ лучше?

2 ответа

Если ваше намерение состоит в том, чтобы иметь очень точный счетчик просмотров страниц, то вам нужно сохранить его в хранилище данных, и вам придется учитывать риск превышения максимальной скорости записи группы сущностей ~1/ сек. Типичный подход в этом случае - счетчики Шардинга.

Однако, если у вас все в порядке с возможностью пропустить несколько видов время от времени (что IMHO может быть вполне приемлемым), вы можете использовать другую стратегию, используя memcache, где вы будете хранить счетчик и метку времени, которую вы можете настроить, чтобы быть много более расслабленным с точки зрения операций хранилища данных. На каждом просмотре страницы вы вызываете транзакционную функцию (чтобы не повредить значение счетчика хранилища данных), которая бы:

  • увеличить значение счетчика memcache (или установить его в 1, если оно отсутствует или недействительно)
  • проверьте значение метки времени в memcache и, если оно действительно и "достаточно недавно" (настраивается), оно просто вернется, в противном случае продолжите
  • обновите метку времени в memcache, указав текущее время (чтобы предотвратить, наряду со следующим шагом, условие гонки с той же функцией, вызванной для другого одновременного запроса)
  • добавить значение счетчика memcache к значению счетчика хранилища данных и сохранить счетчик хранилища данных; если эта транзакция завершается неудачей, это означает, что какой-то другой параллельный запрос уже делает это, ничего не делать (функция завершится на этом этапе)
  • сбросить счетчик memcache на ноль
  • необязательно, не требуется, если вы не ожидаете достаточно длительных периодов неактивности, в течение которых вы рискуете потерять значительное количество просмотров, накопленных в счетчике памяти, которые могут исчезнуть в любое время - поставьте в очередь отложенную задачу (или отложенную, если вы предпочитаете использовать отложенную библиотеку), которая также будет вызывать ту же самую транзакционную функцию, за исключением этого запуска:
    • не будет увеличивать значение счетчика memcache
    • это не поставит в очередь другую отложенную задачу

Я бы выбрал значение задержки задачи, равное "достаточно недавнему".

Настраивая "достаточно недавнее" значение, вы контролируете, как часто вы обновляете значение счетчика хранилища данных.

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

Из-за проблем согласованности в ndb запись на счетчик в хранилище данных может быть очень неточной, особенно если ваше приложение получает много трафика. Один из ваших экземпляров может прочитать текущий счет 1234 page_views, затем попробуйте написать 1235 в хранилище данных. Но, тем временем, могут прийти другие посетители, и они все увидят то же самое page_views значение. Кроме того, из-за последовательности прочитанное вами чтение может оказаться устаревшим. Таким образом, ваш 1235 может быть 1278 или даже больше.

Чтобы избежать такого большого количества записей, подумайте о создании счетчика в memcache, а затем увеличьте его. Memcache сохраняется во всех случаях, и значения изменяются практически мгновенно. Затем периодически сбрасывайте счетчик Memcache в хранилище данных, увеличивая его, и удаляйте его.

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

Memcache подвержен сбоям, поэтому ваш счет никогда не будет на 100% точным. Но сброс каждые 5 минут или около того уменьшает ошибку.

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