Всем привет!
Наверняка большинство инженеров, работающих с высоконагруженными системами, слышали о Aerospike.
Для тех, кто всё ещё не знает, что это, приведу короткую цитату из документации:
The high‑performance, distributed, NoSQL database designed for real‑time applications requiring low latency and high availability.
Вообще‑то, Aerospike — это платный продукт, причём он стоит немалых денег. Настолько немалых, что наша небольшая компания не может его себе позволить.
Однако Aerospike распространяется как в коммерческой сборке, так и в версии Community Edition. Community Edition, хоть и урезана по возможностям, но в старых версиях была вполне пригодна для использования в продакшене. Именно в тот период, когда лимиты Aerospike CE были щадящими, наша компания «подсела» на эту БД и успешно её использовала.
Однако годы шли, и с каждой новой версией бесплатной сборки лимиты становились всё жёстче. В итоге их урезали до такой степени, что обновляться мы больше не смогли и застряли примерно на версии 5 (актуальная сейчас — 8). В результате сейчас у нас используются очень старые версии Aerospike CE.
Какие именно лимиты имеются в виду:
лимит на размер кластера — 8 нод;
не более двух неймспейсов на кластер;
лимит на количество уникальных данных на хранилище в ноде (в новых версиях — всего 640 ГБ).
Всё это мешает горизонтальному масштабированию и добавляет проблем как команде эксплуатации, так и разработке. А лимит в 640 ГБ на ноду вместе с лимитом кластера в 8 нод — это как раз та причина, по которой такую БД невозможно полноценно использовать в продакшене.
Кроме того, из‑за очень старых версий Aerospike, возникают проблемы с поддержкой кластера, и, что печальнее всего, со временем эти проблемы только усугубляются.
В прошлом у нас были попытки купить платный Aerospike, но оказалось, что под наши задачи они выкатывают чудовищный ценник. И еще им сложно продавать в РФ, а нам сложно притворяться, что мы не из РФ.
Таким образом, компания оказалась «заблокирована» на старом ПО, а кодовая база наших сервисов настолько завязана на Aerospike, что «съехать» на альтернативу мы сможем примерно никогда.
Ситуация, казалось бы, патовая. Но мы нашли решение.
Как мы с этим справились
Aerospike — это коммерческое ПО, но, внезапно, исходные коды community‑edition опубликованы. Причём это не классический open source, а код, распространяемый под лицензией AGPLv3.
Это даёт надежду, что нужные лимиты мы сможем ослабить или снять.
Перед тем, как нырять с головой в исходники, чётко сформулируем цели:
Кластер должен масштабироваться до 64 нод (для наших задач этого достаточно).
Кластер должен поддерживать больше двух неймспейсов (32 — с запасом).
Не должно быть искусственного лимита по объёму уникальных данных в хранилище.
Хочется изменить название сборки, чтобы на серверах сразу видеть, что это наша версия.
Теперь можно скачать исходники и попытаться найти нужные места (в примере используется версия 8.1.2.1 — актуальная на момент написания):
% git clone https://github.com/aerospike/aerospike-server.git % cd aerospike-server % git fetch --all --tags % git checkout 8.1.2.1
Размер кластера
Попробуем найти лимит по размеру кластера:
% grep -r "CLUSTER" ./* | grep 8 ./as/include/fabric/hb.h:#define AS_CLUSTER_SZ 8 ./as/include/fabric/partition_balance.h:COMPILER_ASSERT(AS_CLUSTER_SZ_MASKN >> (sizeof(sl_ix_t) * 8) == 0); ./as/include/fabric/partition.h: uint8_t align_3[AS_CLUSTER_SZ == 8 ? 56 : 0]; ./as/src/fabric/skew_monitor.c: uint8_t buffer[AS_CLUSTER_SZ * sizeof(cf_node)]; ./as/src/fabric/skew_monitor.c: uint8_t buffer[AS_CLUSTER_SZ * sizeof(cf_node)]; ./as/src/fabric/skew_monitor.c: uint8_t buffer[AS_CLUSTER_SZ * sizeof(cf_node)]; ./as/src/fabric/skew_monitor.c: uint8_t buffer[AS_CLUSTER_SZ * sizeof(cf_node)];
Из результата сразу бросается в глаза директива:
#define AS_CLUSTER_SZ 8
Если посмотреть, где эта директива используется, становится понятно, что именно она определяет максимальный размер кластера.
Количество неймспейсов
Аналогично ищем лимит по количеству namespace:
% grep -r "NAMESPACE" ./* | grep 2$ ./as/include/base/datamodel.h:#define AS_ID_NAMESPACE_SZ 32 ./as/include/base/cfg.h:#define AS_NAMESPACE_SZ 2
В результате находим строку:
#define AS_NAMESPACE_SZ 2
Вчитываемся в код и убеждаемся, что это ровно то, что нам надо.
Замена названия сборки
Здесь всё просто: ищем по слову «community» и меняем упоминания в Makefile‑ах на желаемое название сборки — например, unchained.
Лимит на количество уникальных данных
А вот тут действительно пришлось повозиться, чтобы найти необходимую директиву в коде. Во‑первых, директива называется не совсем очевидным образом. И, во‑вторых, декларируется она следующим образом AS_NODE_STORAGE_SZ (5L 1024 1024 1024 1024 / 8). Если посчитать это выражение, то получим те самые 640Гб, которыми лимитированы уникальные данные.
Если судить по коду, то такая декларация ничем не мотивирована. Кроме того, если выставить AS_NODE_STORAGE_SZ 0, то у нас вообще лимита не будет.
Автоматизация
Как вы видите, лимиты снимаются довольно просто. То есть изменения в кода можно внести несколькими sed‑ами. В такой ситуации форкать код и потом поддерживать его измененную версию нет никакой необходимости. Тут достаточно запилить Doker‑файл, который будет вносить изменения и собирать необходимые пакетики для установки в систему или готовый для использования docker‑образ.
Собственно по этому пути мы и пошли.
С результатом можно ознакомиться здесь.
Тестирование
Во‑первых, надо проверить что лимиты действительно удалось раздвинуть. Для этого надо просто поднять кластер больше чем из 8-ми нод, добавить в конфигурацию больше чем два нэймспэйса и напихать в каждую ноду больше чем 640Гб уникальных данных.
Сделано
Во‑вторых, надо убедиться что производительность кластера не стала хуже. Тоже ничего сложного — находим кластер (НЕ В ПРОДЕ!!!) производительность которого известна, деплоим туда нашу сборку (версии должны совпадать) и убеждаемся, что с производительностью ничего не изменилось.
Cделано
В‑третьих, надо убедиться, что наши изменения не привели к какому‑нибудь странному поведению кластера (потеря данных или внезапное падение сервиса). Для этого надо куда‑то деплоить нашу версию и уже смотреть. Например, задеплоить на несколько хорошо нагруженных кластеров в дев‑окружении и погонять месяц — другой.
В процессе
Итоги
Aerospike Community Edition — отличный продукт, но за последние годы его бесплатная версия получила жесткие ограничители, несовместимые с нуждами продакшн‑систем. Благодаря открытости исходников под лицензией AGPLv3 мы смогли самостоятельно снять искусственные лимиты и масштабировать кластеры под свои задачи. Вмешательство оказалось минимальным: несколько строк изменяются автоматически при сборке — без необходимости поддерживать отдельный форк. Все основные проверки на лимиты, производительность и стабильность показали, что снятие ограничений не ведёт к «поломке» или ухудшению работы (конечно, с поправкой на то, что Aerospike не виноват, если железо под нагрузкой не вывозит). Весь процесс автоматизирован и воспроизводим, код изменений и инструкции доступны для всех желающих.
Open Source, в очередной раз, спас!
Спасибо, что дочитали до конца!
MountainGoat
Ну а теперь вам нужно создать базу данных, полностью аналогичную проду по размерам, и проделать с ней всё, что вы когда-либо будете с ней делать. Потому что вполне может оказаться, что этот лимит неявно захардкожен где то ещё. И теперь всё нормально, только какая-нибудь дефрагментация понемножку совсем портит данные. Но только те, что выходят за лимит.