Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Построение распределённых Django систем

Построение распределённых Django систем

Александр Ковалёв @ Moscow Python Conf 2017
"Занимаюсь разработкой почти 25 лет. Последние 4 года пишу backend и утилиты на Python. В докладе расскажу, из чего можно построить сеть однотипных веб-сайтов с централизованным управлением пользователями и публикуемыми материалами. Как обычно, пишем максимально абстрактный код, чтобы избежать постоянного переписывания кода и "допиливания" под каждый сайт. Я рассмотрю выбранный и отвергнутый инструментарий (Django, Redis, RabbitMQ, Celery, Docker), подход к синхронизации данных, вспомню про любимые аббревиатуры DRY и MVP и расскажу про некоторые ошибки и недоработки. Постараюсь успеть рассказать про deploy".
Видео: https://conf.python.ru/distributed-django/

Moscow Python Meetup

October 20, 2017
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. О себе  Почти 25 лет в разработке:  Assembler

     C/C++  FoxBase/FoxPro/Clipper  PHP  Perl  VBA (Макросы Microsoft Office)  1С 7.7 - 8.3
  2. Структура проекта site# 1 1 site# 1 2 site# 1

    site# 3 site# 4 site# 5 site# 6 site# 7 site# 8 site# 9 site# 1 0 site# 2 service
  3. class RedisStorage: _db = None _tries = 3 def __init__(self):

    self._host = getattr(settings, 'REDIS_HOST', 'localhost') self._port = getattr(settings, 'REDIS_PORT', 6379) self._db_num = getattr(settings, 'REDIS_DB', 0) def connect(self): self._db = redis.StrictRedis(host=self._host, port=self._port, db=self._db_num) def execute(self, func_name, *args, **kwargs): if not self._db: self.connect() result = False for i in range(self._tries - 1): try: func = getattr(self._db, func_name, None) result = func(*args, **kwargs) except (ConnectionError, TimeoutError):
  4. class RedisCache: _media_change = 'change/media' _key_changes = 'change/site' _key_email =

    'send/email' def __init__(self): self._rs = RedisStorage() self._media_sync_tries = getattr(settings, 'MEDIA_SYNC_TRIES', 3) self._chunk_size = getattr(settings, 'SITE_SYNC_CHUNK_SIZE', 10) self._send_tries = getattr(settings, 'SITE_SYNC_SEND_TRIES', 3) def push_media_change(self, filename, action='update', tries=0): if filename: print('FILENAME: {}'.format(filename)) if tries <= self._media_sync_tries: _key = self._media_change self._rs.rpush(_key, json.dumps({ 'filename': filename, 'action': action, 'tries': tries, })) def iter_media_changes(self):
  5. site# N service Изменение данных Django Django Celery Redis Celery

    Redis ►создание ►изменение ►удаление!
  6. Профит При изменении моделей не нужно дорабатывать синхронизацию Простая и

    удобная работа с кэшем и запросами к API «Лучше день потерять, потом за пять минут долететь» :) Но это не точно! ;) Не DDOS’им свои же сервера Сайты можно переустановить без потери данных
  7. Что дальше? Возможно сделать свои async tasks вместо Celery Рассмотреть

    варианты масштабирования Много интересных связанных сервисов. Это намек ;) Нагрузочное тестирование Оптимизация деплоя (оставить ли вообще docker?)