Lumber room
March 2009 25

Создание системы авторизации в высоконагруженном проекте с использованием MemcacheDB

Здравствуйте!

В этой статье я хочу рассказать о проблемах авторизации с которыми может столкнуться любой посещаемый веб-сайт в период роста.

Где хранить аутентификационную базу пользователей?
Как быстро авторизовать пользователя по его строковому логину?
Как собирать распределенные по нескольким шард-таблицам и нескольким базам данных пользовательские данные?
Как заставить все это работать и как в этом нам может помочь MemcacheDB?


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

Проблема


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

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

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

Поиск решения


Путей решения было несколько.

С одной стороны мы рассматривали возможность разбиения пользователей по множеству таблиц аутентификации в MySQL наподобие user1,user2,...,userN где N каким-либо образом вычислялось из логина пользователя. Но что сделать когда число таблиц в пределах одной базы станет слишком велико для нормальной производительности реляционной базы данных?
Как нам добится гибкости в масштабировании? Крупные порталы создают собственные системы аутентификации, однако наша команда работает прежде всего на результат в ограниченных ресурсах, когда подобная работа заняла бы слишком много времени, и мы стали искать уже существующее решение.

Тогда мы обратили свой взгляд в сторону Key-Value баз данных о которых вы можете прочитать здесь (http://habrahabr.ru/blogs/hi/55077/)
В силу ряда обстоятельств, из которых, прежде всего, была относительная известность мы остановились на MemcacheDB.

Архитектура


Итак, теперь об архитектуре.

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

Основные операции записи в MemcacheDB решено было дублировать в MySQL базу, поскольку мы не были уверены в стабильности MemcacheDB в поддержании целостности, и не уверены до сих пор. Автор MemcacheDB — Steve Chu, в ответ на наше письмо, о котором мы расскажем позже рекомендовал то же решение.

Операции чтения совершались только из MemcacheDB, а в кроне раз в сутки была поставлена проверка идентичности базы MySQL и MemcacheDB.

Проект работает на PHP5, изначально в качестве клиента к MCDB мы использовали pecl-memcache модуль, однако в процессе нагрузочного тестирования на большом объеме данных выяснилось что модуль имеет склонности к разрыву соединения при большой (для memcache) задержки чтения. После ряда мучений и извращений, мы написали письмо автору, Steve Chu, который сообщил что знает о проблемах подобного рода и рекоммендовал использовать в качестве клиента недавно опубликованный модуль pecl-memcached (обратите внимание на добавленную d). Это решило наши проблемы, кроме того быстрый ответ автора окончательно убедил нас в правильности сделанного выбора.

Для быстрого восстановления в случае потери базы на отдельном сервере поднят еще один экземпляр MemcacheDB в который реплицируются данные основного. В случае сбоя данных мы организуем быстрое переключение на backup-сервер.

Итак, каждый пользователь сохраняется по данным ключ=>значение дважды.
В данных всегда сохраняются данные пользоватлея, а в качестве ключа выступают:
  • логин пользователя
  • идентификатор пользователя

Таким образом процесс регистрации предстает в виде:
  1. Данные пользователя сохраняются в БД.
  2. Данные пользователя сохраняются в MemcacheDB с ключем user_login, где login — логин пользователя
  3. Данные пользователя сохраняются в MemcacheDB с ключем user_id, где id — идентификатор пользователя.

Процесс авторизации:
  1. Пользователь вводит свои аутентификационные данные — login и пароль.
  2. Система получает данные пользователя из MemcacheDB по ключу user_login и проводит аутентификацию.

Процесс получения информации о друзьях пользователя:
  1. Пользователь загружает список друзей.
  2. Система получив список идентфикаторов друзей пользователя (возможно из того же MemcacheDB) получает информацию о каждом друге по user_id и на основании этой информации собирает другие данные пользователя распределенные в БД.

Преимущества


Основные преимущества этого подхода:
1. MemcacheDB на и на малых и на больших объемах данных показывает производительность в разы превыщающую производительность MySQL на той же задаче.
2. MemcacheDB легко относится к большому числу пар ключ-значение в базе, в настоящий момент в базе порядка 4 миллионов пар ключ-значение.
3. Шардинг и разделение данных по сущностям также возможны в MemcacheDB, его можно представив запустив несколько экземляров MemcacheDB с разными базами данных.

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

Спасибо за внимание!

+17
556 41
Comments 31