SlideShare a Scribd company logo
BUILDING TO SCALE

                            David Cramer
                           twitter.com/zeeg



Tuesday, February 26, 13
The things we build will not
                    and can not last




Tuesday, February 26, 13
Who am I?




Tuesday, February 26, 13
Tuesday, February 26, 13
Tuesday, February 26, 13
Tuesday, February 26, 13
What do we mean by scale?




Tuesday, February 26, 13
DISQUS
                 Massive traffic with a long tail


                                                  Sentry
                                 Counters and event aggregation




                 tenXer
                 More stats than we can count



Tuesday, February 26, 13
Does one size fit all?




Tuesday, February 26, 13
Practical Storage




Tuesday, February 26, 13
Postgres is the foundation of DISQUS




Tuesday, February 26, 13
MySQL powers the tenXer graph store




Tuesday, February 26, 13
Sentry is built on SQL




Tuesday, February 26, 13
Databases are not the problem




Tuesday, February 26, 13
Compromise




Tuesday, February 26, 13
Scaling is about Predictability




Tuesday, February 26, 13
Augment SQL with [technology]




Tuesday, February 26, 13
Tuesday, February 26, 13
Simple solutions using Redis
                           (I like Redis)




Tuesday, February 26, 13
Counters




Tuesday, February 26, 13
Counters are everywhere




Tuesday, February 26, 13
Counters in SQL
                           UPDATE table SET counter = counter + 1;




Tuesday, February 26, 13
Counters in Redis
                                  INCR counter 1
                             >>> redis.incr('counter')




Tuesday, February 26, 13
Counters in Sentry

                           event ID 1   event ID 2   event ID 3




                           Redis INCR   Redis INCR   Redis INCR




                                        SQL Update




Tuesday, February 26, 13
Counters in Sentry

                ‣
                     INCR event_id in Redis
                ‣
                     Queue buffer incr task
                      ‣
                           5 - 10s explicit delay


                ‣
                     Task does atomic GET event_id and DEL
                     event_id (Redis pipeline)
                ‣
                     No-op If GET is not > 0
                ‣
                     One SQL UPDATE per unique event per
                     delay



Tuesday, February 26, 13
Counters in Sentry (cont.)


                     Pros
                ‣
                     Solves database row lock contention
                ‣
                     Redis nodes are horizontally scalable
                ‣
                     Easy to implement


                     Cons
                ‣
                     Too many dummy (no-op) tasks




Tuesday, February 26, 13
Alternative Counters

                             event ID 1      event ID 2      event ID 3




                           Redis ZINCRBY   Redis ZINCRBY   Redis ZINCRBY




                                            SQL Update




Tuesday, February 26, 13
Sorted Sets in Redis




                           > ZINCRBY events ad93a 1
                           {ad93a: 1}

                           > ZINCRBY events ad93a 1
                           {ad93a: 2}

                           > ZINCRBY events d2ow3 1
                           {ad93a: 2, d2ow3: 1}



Tuesday, February 26, 13
Alternative Counters


                ‣
                     ZINCRBY events event_id in Redis
                ‣
                     Cron buffer flush


                ‣
                     ZRANGE events to get pending updates
                ‣
                     Fire individual task per update
                      ‣
                           Atomic ZSCORE events event_id and
                           ZREM events event_id to get and flush
                           count.



Tuesday, February 26, 13
Alternative Counters (cont.)



                     Pros
                ‣
                     Removes (most) no-op tasks
                ‣
                     Works without a complex queue due to no
                     required delay on jobs


                     Cons
                ‣
                     Single Redis key stores all pending updates




Tuesday, February 26, 13
Activity Streams




Tuesday, February 26, 13
Streams are everywhere




Tuesday, February 26, 13
Streams in SQL


                           class Activity:
                               SET_RESOLVED = 1
                               SET_REGRESSION = 6

                               TYPE = (
                                   (SET_RESOLVED, 'set_resolved'),
                                   (SET_REGRESSION, 'set_regression'),
                               )

                               event      =   ForeignKey(Event)
                               type       =   IntegerField(choices=TYPE)
                               user       =   ForeignKey(User, null=True)
                               datetime   =   DateTimeField()
                               data       =   JSONField(null=True)




Tuesday, February 26, 13
Streams in SQL (cont.)




                       >>> Activity(event, SET_RESOLVED, user, now)
                       "David marked this event as resolved."

                       >>> Activity(event, SET_REGRESSION, datetime=now)
                       "The system marked this event as a regression."

                       >>> Activity(type=DEPLOY_START, datetime=now)
                       "A deploy started."

                       >>> Activity(type=SET_RESOLVED, datetime=now)
                       "All events were marked as resolved"




Tuesday, February 26, 13
Stream == View == Cache




Tuesday, February 26, 13
Views as a Cache



                      TIMELINE = []
                      MAX = 500

                      def on_event_creation(event):
                          global TIMELINE

                           TIMELINE.insert(0, event)
                           TIMELINE = TIMELINE[:MAX]

                      def get_latest_events(num=100):
                          return TIMELINE[:num]



Tuesday, February 26, 13
Views in Redis



                  class Timeline(object):
                      def __init__(self):
                          self.db = Redis()

                           def add(self, event):
                               score = float(event.date.strftime('%s.%m'))
                               self.db.zadd('timeline', event.id, score)

                           def list(self, offset=0, limit=-1):
                               return self.db.zrevrange(
                                   'timeline', offset, limit)




Tuesday, February 26, 13
Views in Redis (cont.)




                  MAX_SIZE = 10000

                  def add(self, event):
                      score = float(event.date.strftime('%s.%m'))

                           # increment the key and trim the data to avoid
                           # data bloat in a single key
                           with self.db.pipeline() as pipe:
                               pipe.zadd(self.key, event.id, score)
                               pipe.zremrange(self.key, event.id, MAX_SIZE, -1)




Tuesday, February 26, 13
Queuing




Tuesday, February 26, 13
Introducing Celery




Tuesday, February 26, 13
RabbitMQ or Redis




Tuesday, February 26, 13
Asynchronous Tasks




                      # Register the task
                      @task(exchange=”event_creation”)
                      def on_event_creation(event_id):
                          counter.incr('events', event_id)


                      # Delay execution
                      on_event_creation(event.id)




Tuesday, February 26, 13
Fanout

                      @task(exchange=”counters”)
                      def incr_counter(key, id=None):
                          counter.incr(key, id)


                      @task(exchange=”event_creation”)
                      def on_event_creation(event_id):
                          incr_counter.delay('events', event_id)
                          incr_counter.delay('global')


                      # Delay execution
                      on_event_creation(event.id)




Tuesday, February 26, 13
Object Caching




Tuesday, February 26, 13
Object Cache Prerequisites




                ‣
                     Your database can't handle the read-load


                ‣
                     Your data changes infrequently


                ‣
                     You can handle slightly worse performance




Tuesday, February 26, 13
Distributing Load with Memcache


                           Memcache 1        Memcache 2        Memcache 3




                           Event   ID   01   Event   ID   02   Event   ID   03
                           Event   ID   04   Event   ID   05   Event   ID   06
                           Event   ID   07   Event   ID   08   Event   ID   09
                           Event   ID   10   Event   ID   11   Event   ID   12
                           Event   ID   13   Event   ID   14   Event   ID   15




Tuesday, February 26, 13
Querying the Object Cache

                      def make_key(model, id):
                          return '{}:{}'.format(model.__name__, id)

                      def get_by_ids(model, id_list):
                          model_name = model.__name__
                          keys = map(make_key, id_list)

                           res = cache.get_multi()

                           pending = set()
                           for id, value in res.iteritems():
                               if value is None:
                                   pending.add(id)

                           if pending:
                               mres = model.objects.in_bulk(pending)

                               cache.set_multi({make_key(o.id): o for o in mres})

                               res.update(mres)

                           return res



Tuesday, February 26, 13
Pushing State




                      def save(self):
                          cache.set(make_key(type(self), self.id), self)


                      def delete(self):
                          cache.delete(make_key(type(self), self.id)




Tuesday, February 26, 13
Redis for Persistence


                             Redis 1           Redis 2           Redis 3




                           Event   ID   01   Event   ID   02   Event   ID   03
                           Event   ID   04   Event   ID   05   Event   ID   06
                           Event   ID   07   Event   ID   08   Event   ID   09
                           Event   ID   10   Event   ID   11   Event   ID   12
                           Event   ID   13   Event   ID   14   Event   ID   15




Tuesday, February 26, 13
Routing with Nydus


                      # create a cluster of Redis connections which
                      # partition reads/writes by (hash(key) % size)

                      from nydus.db import create_cluster

                      redis = create_cluster({
                          'engine': 'nydus.db.backends.redis.Redis',
                          'router': 'nydus.db...redis.PartitionRouter',
                          'hosts': {
                              {0: {'db': 0} for n in xrange(10)},
                          }
                      })


                               github.com/disqus/nydus

Tuesday, February 26, 13
Planning for the Future




Tuesday, February 26, 13
One of the largest problems for
         Disqus is network-wide moderation




Tuesday, February 26, 13
Be Mindful of Features




Tuesday, February 26, 13
Sentry's Team Dashboard




                ‣
                     Data limited to a single team
                ‣
                     Simple views which could be materialized
                ‣
                     Only entry point for "data for team"


Tuesday, February 26, 13
Sentry's Stream View




                ‣
                     Data limited to a single project
                ‣
                     Each project could map to a different DB



Tuesday, February 26, 13
Preallocate Shards




Tuesday, February 26, 13
redis-1


                           DB0   DB1    DB2      DB3   DB4




                           DB5   DB6    DB7      DB8   DB9




Tuesday, February 26, 13
redis-1


                           DB0   DB1    DB2      DB3   DB4




             When a physical machine becomes
            overloaded migrate a chunk of shards
                    to another machine.

                                       redis-2


                           DB5   DB6    DB7      DB8   DB9




Tuesday, February 26, 13
Takeaways




Tuesday, February 26, 13
Enhance your database
                          Don't replace it




Tuesday, February 26, 13
Queue Everything




Tuesday, February 26, 13
Learn to say no
                            (to features)




Tuesday, February 26, 13
Complex problems do not
               require complex solutions




Tuesday, February 26, 13
QUESTIONS?



Tuesday, February 26, 13

More Related Content

More from it-people

«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
it-people
 
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАН«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
it-people
 
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
it-people
 
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
it-people
 
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
it-people
 
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
it-people
 
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
it-people
 
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
it-people
 
«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologies«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologies
it-people
 
«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндекс«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндекс
it-people
 
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
it-people
 
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
it-people
 
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
it-people
 
ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...
ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...
ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...
it-people
 
ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...
ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...
ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...
it-people
 
"Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ...
"Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ..."Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ...
"Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ...
it-people
 
"Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже...
"Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже..."Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже...
"Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже...
it-people
 
"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ
"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ
"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ
it-people
 
"Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З...
"Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З..."Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З...
"Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З...
it-people
 
"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс
"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс
"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс
it-people
 

More from it-people (20)

«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
 
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАН«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
 
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
 
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
 
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
 
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
 
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
 
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
 
«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologies«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologies
 
«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндекс«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндекс
 
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
 
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
 
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
 
ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...
ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...
ЗАВИСИМОСТИ В КОМПОНЕНТНОМ ВЕБЕ, ПРИГОТОВЛЕННЫЕ ПРАВИЛЬНО, Гриненко Владимир,...
 
ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...
ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...
ПРАКТИЧЕСКИЙ ОПЫТ ИСПОЛЬЗОВАНИЯ REACT NATIVE + REDUX, Краснояров Станислав, R...
 
"Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ...
"Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ..."Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ...
"Как повысить мотивацию удаленных разработчиков и повысить значимость каждой ...
 
"Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже...
"Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже..."Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже...
"Профессиональное выгорание менеджера проекта" Орлов Александр, Школа менедже...
 
"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ
"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ
"Как поднять цену в разы и не потерять в продажах?" Калаев Дмитрий, ФРИИ
 
"Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З...
"Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З..."Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З...
"Как работать из 20 разных городов с ощущением, что находитесь в 1 комнате" З...
 
"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс
"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс
"Коммуникация в распределенной команде" Жаринов Андрей, Яндекс
 

Recently uploaded

Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Pitangent Analytics & Technology Solutions Pvt. Ltd
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
Edge AI and Vision Alliance
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
AstuteBusiness
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Safe Software
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
Neo4j
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
DanBrown980551
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
DianaGray10
 
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and BioinformaticiansBiomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Neo4j
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
saastr
 
JavaLand 2024: Application Development Green Masterplan
JavaLand 2024: Application Development Green MasterplanJavaLand 2024: Application Development Green Masterplan
JavaLand 2024: Application Development Green Masterplan
Miro Wengner
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
Jason Packer
 
GNSS spoofing via SDR (Criptored Talks 2024)
GNSS spoofing via SDR (Criptored Talks 2024)GNSS spoofing via SDR (Criptored Talks 2024)
GNSS spoofing via SDR (Criptored Talks 2024)
Javier Junquera
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
Brandon Minnick, MBA
 
"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota
Fwdays
 
Principle of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptxPrinciple of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptx
BibashShahi
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
Ivanti
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
Antonios Katsarakis
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
panagenda
 

Recently uploaded (20)

Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
 
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and BioinformaticiansBiomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
 
JavaLand 2024: Application Development Green Masterplan
JavaLand 2024: Application Development Green MasterplanJavaLand 2024: Application Development Green Masterplan
JavaLand 2024: Application Development Green Masterplan
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
 
GNSS spoofing via SDR (Criptored Talks 2024)
GNSS spoofing via SDR (Criptored Talks 2024)GNSS spoofing via SDR (Criptored Talks 2024)
GNSS spoofing via SDR (Criptored Talks 2024)
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
 
"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota
 
Principle of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptxPrinciple of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptx
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
 

David Cramer: Building to scale

  • 1. BUILDING TO SCALE David Cramer twitter.com/zeeg Tuesday, February 26, 13
  • 2. The things we build will not and can not last Tuesday, February 26, 13
  • 3. Who am I? Tuesday, February 26, 13
  • 7. What do we mean by scale? Tuesday, February 26, 13
  • 8. DISQUS Massive traffic with a long tail Sentry Counters and event aggregation tenXer More stats than we can count Tuesday, February 26, 13
  • 9. Does one size fit all? Tuesday, February 26, 13
  • 11. Postgres is the foundation of DISQUS Tuesday, February 26, 13
  • 12. MySQL powers the tenXer graph store Tuesday, February 26, 13
  • 13. Sentry is built on SQL Tuesday, February 26, 13
  • 14. Databases are not the problem Tuesday, February 26, 13
  • 16. Scaling is about Predictability Tuesday, February 26, 13
  • 17. Augment SQL with [technology] Tuesday, February 26, 13
  • 19. Simple solutions using Redis (I like Redis) Tuesday, February 26, 13
  • 22. Counters in SQL UPDATE table SET counter = counter + 1; Tuesday, February 26, 13
  • 23. Counters in Redis INCR counter 1 >>> redis.incr('counter') Tuesday, February 26, 13
  • 24. Counters in Sentry event ID 1 event ID 2 event ID 3 Redis INCR Redis INCR Redis INCR SQL Update Tuesday, February 26, 13
  • 25. Counters in Sentry ‣ INCR event_id in Redis ‣ Queue buffer incr task ‣ 5 - 10s explicit delay ‣ Task does atomic GET event_id and DEL event_id (Redis pipeline) ‣ No-op If GET is not > 0 ‣ One SQL UPDATE per unique event per delay Tuesday, February 26, 13
  • 26. Counters in Sentry (cont.) Pros ‣ Solves database row lock contention ‣ Redis nodes are horizontally scalable ‣ Easy to implement Cons ‣ Too many dummy (no-op) tasks Tuesday, February 26, 13
  • 27. Alternative Counters event ID 1 event ID 2 event ID 3 Redis ZINCRBY Redis ZINCRBY Redis ZINCRBY SQL Update Tuesday, February 26, 13
  • 28. Sorted Sets in Redis > ZINCRBY events ad93a 1 {ad93a: 1} > ZINCRBY events ad93a 1 {ad93a: 2} > ZINCRBY events d2ow3 1 {ad93a: 2, d2ow3: 1} Tuesday, February 26, 13
  • 29. Alternative Counters ‣ ZINCRBY events event_id in Redis ‣ Cron buffer flush ‣ ZRANGE events to get pending updates ‣ Fire individual task per update ‣ Atomic ZSCORE events event_id and ZREM events event_id to get and flush count. Tuesday, February 26, 13
  • 30. Alternative Counters (cont.) Pros ‣ Removes (most) no-op tasks ‣ Works without a complex queue due to no required delay on jobs Cons ‣ Single Redis key stores all pending updates Tuesday, February 26, 13
  • 33. Streams in SQL class Activity: SET_RESOLVED = 1 SET_REGRESSION = 6 TYPE = ( (SET_RESOLVED, 'set_resolved'), (SET_REGRESSION, 'set_regression'), ) event = ForeignKey(Event) type = IntegerField(choices=TYPE) user = ForeignKey(User, null=True) datetime = DateTimeField() data = JSONField(null=True) Tuesday, February 26, 13
  • 34. Streams in SQL (cont.) >>> Activity(event, SET_RESOLVED, user, now) "David marked this event as resolved." >>> Activity(event, SET_REGRESSION, datetime=now) "The system marked this event as a regression." >>> Activity(type=DEPLOY_START, datetime=now) "A deploy started." >>> Activity(type=SET_RESOLVED, datetime=now) "All events were marked as resolved" Tuesday, February 26, 13
  • 35. Stream == View == Cache Tuesday, February 26, 13
  • 36. Views as a Cache TIMELINE = [] MAX = 500 def on_event_creation(event): global TIMELINE TIMELINE.insert(0, event) TIMELINE = TIMELINE[:MAX] def get_latest_events(num=100): return TIMELINE[:num] Tuesday, February 26, 13
  • 37. Views in Redis class Timeline(object): def __init__(self): self.db = Redis() def add(self, event): score = float(event.date.strftime('%s.%m')) self.db.zadd('timeline', event.id, score) def list(self, offset=0, limit=-1): return self.db.zrevrange( 'timeline', offset, limit) Tuesday, February 26, 13
  • 38. Views in Redis (cont.) MAX_SIZE = 10000 def add(self, event): score = float(event.date.strftime('%s.%m')) # increment the key and trim the data to avoid # data bloat in a single key with self.db.pipeline() as pipe: pipe.zadd(self.key, event.id, score) pipe.zremrange(self.key, event.id, MAX_SIZE, -1) Tuesday, February 26, 13
  • 41. RabbitMQ or Redis Tuesday, February 26, 13
  • 42. Asynchronous Tasks # Register the task @task(exchange=”event_creation”) def on_event_creation(event_id): counter.incr('events', event_id) # Delay execution on_event_creation(event.id) Tuesday, February 26, 13
  • 43. Fanout @task(exchange=”counters”) def incr_counter(key, id=None): counter.incr(key, id) @task(exchange=”event_creation”) def on_event_creation(event_id): incr_counter.delay('events', event_id) incr_counter.delay('global') # Delay execution on_event_creation(event.id) Tuesday, February 26, 13
  • 45. Object Cache Prerequisites ‣ Your database can't handle the read-load ‣ Your data changes infrequently ‣ You can handle slightly worse performance Tuesday, February 26, 13
  • 46. Distributing Load with Memcache Memcache 1 Memcache 2 Memcache 3 Event ID 01 Event ID 02 Event ID 03 Event ID 04 Event ID 05 Event ID 06 Event ID 07 Event ID 08 Event ID 09 Event ID 10 Event ID 11 Event ID 12 Event ID 13 Event ID 14 Event ID 15 Tuesday, February 26, 13
  • 47. Querying the Object Cache def make_key(model, id): return '{}:{}'.format(model.__name__, id) def get_by_ids(model, id_list): model_name = model.__name__ keys = map(make_key, id_list) res = cache.get_multi() pending = set() for id, value in res.iteritems(): if value is None: pending.add(id) if pending: mres = model.objects.in_bulk(pending) cache.set_multi({make_key(o.id): o for o in mres}) res.update(mres) return res Tuesday, February 26, 13
  • 48. Pushing State def save(self): cache.set(make_key(type(self), self.id), self) def delete(self): cache.delete(make_key(type(self), self.id) Tuesday, February 26, 13
  • 49. Redis for Persistence Redis 1 Redis 2 Redis 3 Event ID 01 Event ID 02 Event ID 03 Event ID 04 Event ID 05 Event ID 06 Event ID 07 Event ID 08 Event ID 09 Event ID 10 Event ID 11 Event ID 12 Event ID 13 Event ID 14 Event ID 15 Tuesday, February 26, 13
  • 50. Routing with Nydus # create a cluster of Redis connections which # partition reads/writes by (hash(key) % size) from nydus.db import create_cluster redis = create_cluster({ 'engine': 'nydus.db.backends.redis.Redis', 'router': 'nydus.db...redis.PartitionRouter', 'hosts': { {0: {'db': 0} for n in xrange(10)}, } }) github.com/disqus/nydus Tuesday, February 26, 13
  • 51. Planning for the Future Tuesday, February 26, 13
  • 52. One of the largest problems for Disqus is network-wide moderation Tuesday, February 26, 13
  • 53. Be Mindful of Features Tuesday, February 26, 13
  • 54. Sentry's Team Dashboard ‣ Data limited to a single team ‣ Simple views which could be materialized ‣ Only entry point for "data for team" Tuesday, February 26, 13
  • 55. Sentry's Stream View ‣ Data limited to a single project ‣ Each project could map to a different DB Tuesday, February 26, 13
  • 57. redis-1 DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7 DB8 DB9 Tuesday, February 26, 13
  • 58. redis-1 DB0 DB1 DB2 DB3 DB4 When a physical machine becomes overloaded migrate a chunk of shards to another machine. redis-2 DB5 DB6 DB7 DB8 DB9 Tuesday, February 26, 13
  • 60. Enhance your database Don't replace it Tuesday, February 26, 13
  • 62. Learn to say no (to features) Tuesday, February 26, 13
  • 63. Complex problems do not require complex solutions Tuesday, February 26, 13