Эффективная работа с глобальными счетчиками

Оригинал статьи – http://blog.appenginefan.com/2008/06/efficient-global-counters.html

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

from google.appengine.ext import db
import random

SHARDS_PER_COUNTER = 20

class CounterShard(db.Model):
  name = db.StringProperty(required=True)
  count = db.IntegerProperty(default=0)

def GetCount(nameOfCounter):
  result = 0
  for shard in CounterShard.gql('WHERE name=:1', nameOfCounter):
    result += shard.count
  return result

def ChangeCount(nameOfCounter, delta):
  shard_id = '/%s/%s' % (
     nameOfCounter, random.randint(1, SHARDS_PER_COUNTER))
  def update():
   shard = CounterShard.get_by_key_name(shard_id)
   if shard:
     shard.count += delta
   else:
     shard = CounterShard(
         key_name=shard_id, name=nameOfCounter, count=delta)
   shard.put()
  db.run_in_transaction(update)

Очень интересное решение, но можно сделать еще лучше с помощью использования интерфейса Memcache API, путем сохранения значения счетчика в памяти и обновления его при необходимости. Следующий пример показывает, как можно установить период устаревания значения счетчика на одну минуту:

def GetCount(nameOfCounter):
  memcache_id = '/CounterShard/%s' %  nameOfCounter
  result = memcache.get(memcache_id)
  if not (result == None):
    return result
  result = 0
 for shard in CounterShard.gql('WHERE name=:1', nameOfCounter):
   result += shard.count
  memcache.set(memcache_id, result, 60)
  return result

Один ответ на “Эффективная работа с глобальными счетчиками”

  1. Операции AVG и SUM Google App Engine « Technology@Work:

    [...] Замечание по производительности: Приведенный выше пример показывает неэффективную работу с счетчиками, однако он указан только для объяснения принципов работы. На практике же необходимо использовать разделение счетчиков. [...]

Добавить комментарий