При миграции системы иногда приходится создавать небольшие леса. Нам пришлось сделать это недавно: в Instagram по устаревшим причинам нам нужно было сопоставить около 300 миллионов фотографий с идентификатором пользователя, который их создал, чтобы знать, какой сегмент запрашивать (см.нашДополнительная информация)Настройки шарда). Хотя все клиентские и API-приложения были обновлены и вернули нам полную информацию, многие все еще кэшируют старые данные. Нам нужно решение:
- Быстро найти ключ и возвращаемое значение
- Храните данные в памяти, в идеале в типе высокой памяти EC2 (17 ГБ или 34 ГБ, а не тип экземпляра 68 ГБ).
- Совместимость с нашей существующей инфраструктурой
- Постоянство, поэтому нам не нужно перезапускать, если сервер выйдет из строя
Простое решение этой проблемы — просто хранить их в строке базы данных со столбцами «ID носителя» и «ID пользователя». Однако, учитывая, что эти идентификаторы никогда не обновляются (только вставляются), база данных SQL кажется избыточной. Никаких транзакций не требуется, и она не имеет отношения к другим таблицам.
Вместо этого мы обращаемся кRedis, хранилище ключей и значений, которое мы широко используем в Instagram. Redis — это швейцарский армейский нож «ключ-значение»; вместо приземленного механизма «Установи ключ, получи ключ», такого как Memcached, он предоставляет мощные типы агрегации, такие как отсортированные наборы и списки. Он имеет настраиваемую модель постоянства, в которой фон сохраняется через определенные промежутки времени, и можно установить синхронизацию ведущий-ведомый. Все наши Redis работают на серверах master-slave, настроенных на сохранение на диск каждую минуту.
Во-первых, мы решили использовать Redis самым простым способом: для каждого ID ключом будет ID носителя, а значением будет ID пользователя:
SET media:1155315 939
GET media:1155315
> 939
Однако при моделировании этого решения мы обнаружили, что Redis требуется около 70 МБ для хранения 1 000 000 ключей. Исходя из необходимых нам 300 000 000, это около 21 ГБ данных, что уже больше, чем тип экземпляра 17 ГБ на Amazon EC2.
Мы говорим одному из основных разработчиков Redis, полезныйPieter NoordhuisВ комментарии он предложил использовать хэши Redis. Хэши в Redis являются словарями и могут быть очень эффективно закодированы в памяти; параметр Redis «hash-zipmap-max-entries» настраивает максимальное количество записей, которые хеш может эффективно кодировать. Мы обнаружили, что этот параметр лучше всего около 1000; любые команды HSET с более высокой конфигурацией вызовут заметное использование ЦП. Для более подробной информации вы можетеПросмотр исходных файлов zipmap.
Чтобы использовать хеш-тип, мы распределяем все идентификаторы медиа в корзины по 1000 (мы просто берем идентификаторы, делим на 1000 и отбрасываем остальные). Это определяет, какой ключ принадлежит следующему в хэше этого ключа, идентификатор носителя является ключом поиска в хэше, а идентификатор пользователя является значением. Пример с идентификатором носителя 1155315, который принадлежит корзине 1155 (1155315/1000 = 1155):
HSET "mediabucket:1155" "1155315" "939"
HGET "mediabucket:1155" "1155315"
> "939"
Разница в памяти ошеломляет: с нашими 1 000 000 ключей (закодированных как 1000 хэшей, каждый из которых имеет 1000 подразделов), Redis требуется всего 16 МБ памяти. Масштабируется до 300 миллионов ключей, что в сумме составляет менее 5 ГБ, и на самом деле он даже подходит для более дешевого экземпляра типа m1.large на Amazon, что составляет около 1/3 стоимости более крупного экземпляра, который нам в противном случае потребовался бы. Лучше всего то, что поиск в хэше по-прежнему O(1), очень быстрый.
Если вы заинтересованы в том, чтобы попробовать их, сценарии, которые мы используем для запуска этих тестовДоступен как Gist на GitHub(У нас в скрипте для сравнения Memcached, который занимает около 52 МБ на миллион ключей).
Для получения дополнительных статей, пожалуйста, посетите: http://www.apexyun.com
Общедоступный номер: Galaxy № 1
Контактный адрес электронной почты: public@space-explore.com
(Пожалуйста, не перепечатывайте без разрешения)