Механізм синхронізації запуску застосунків на базі shared-lock
Привіт, спільното DOU. Мене звати Владислав Папідоха, я DevOps Engineer в компанії TENTENS Tech. Маю досвід трансформації процесів у продуктових компаніях; проводив значних розмірів технічне рішення через багатоетапні трансформації; також активно займаюся навчанням інженерної справи колег й не тільки.
Під час роботи з масштабованими розподіленими системами я не раз стикався з ситуаціями, коли певний сервіс має бути запущений лише в одному екземплярі, незалежно від кількості кластерів. Але як зробити це так, щоб сервіс гарантовано працював в одному місці, а у разі збою миттєво перемикався на інший кластер?
Ми використовуємо shared-lock — API-сервер на Go, який надає всього два ендпоїнти для зовнішніх клієнтів. Він працює на базі etcd, що зазвичай є частиною будь-якого Kubernetes-кластера, і дозволяє будувати навколо себе систему, в якій синглтон-застосунки можуть запускатися в кількох кластерах одночасно з можливістю миттєвого фейловеру.
Наразі у компанії я основний мейнтейнер shared-lock. Сьогодні розберемо, що це за звір та як легко можна з ним інтегруватися. Якщо ви працюєте з багатопотоковими чи розподіленими системами й вам доводиться синхронізувати доступ до ресурсів або ви шукаєте способи керування конкурентним запуском застосунків — ця стаття стане для вас корисним гайдом.
У боротьбі за відмовостійкість
Наша інженерна команда постійно працює над підвищенням доступності та відмовостійкості наших застосунків. У певний момент ми вирішили не просто запускати кілька реплік кожного сервісу, а реплікувати весь Kubernetes-кластер у режимі активного failover. Це означає, що для критичних сервісів ми розгортаємо кілька незалежних кластерів у різних зонах доступності, що дозволяє уникнути проблем при виході з ладу будь-якого з них.
Однак це рішення зіткнулося з новим викликом: деякі навантаження не можуть бути репліковані, а натомість мають існувати в єдиному екземплярі через закладену бізнес-логіку. Ми називаємо такі процеси «сінглтонами».
Щоб розв’язати цю проблему, ми створили shared-lock — розподілений менеджер блокувань, який дозволяє синхронізувати запуск таких сервісів між усіма нашими production-кластерами.
Крім того, розподілене блокування — це типовий патерн у розробці, який багато інженерів змушені реалізовувати всередині своїх застосунків. Ми вирішили винести цей механізм в окремий сервіс з універсальним API, що дозволило позбутися потреби створення низки окремих рішень, які незалежно працюють у різноманітних частинах наших систем. Цей підхід зробив систему гнучкішою й зменшив витрати на підтримку унікальних реалізацій у кожному окремому сервісі.
Як це працює
Як вже згадувалося, API shared-lock має всього два ендпоїнти:
- /lease — для отримання резервації;
- /keepalive — для регулярного підтвердження своєї присутності та подовження резервації.
Щоб гарантувати, що в будь-який момент часу працює тільки один інстанс застосунку, нам потрібно реалізувати наступний механізм:
- Відправляємо запит на /lease для отримання резервації:
- якщо резервацію отримано — продовжуємо запуск.
- опісля кожні Х секунд надсилаємо запит на /keepalive для продовження часу життя резервації;
- якщо не вдалося — чекаємо таймаут і повторюємо спробу.
- якщо резервацію отримано — продовжуємо запуск.
Якщо ж потрібен приклад представлення в коді, його можна знайти у репозиторії проєкту за посиланням.
Як запустити власний shared-lock сервер
Віднедавна наша реалізація shared-lock стала публічно доступною на Github, а готові docker-імеджі можна знайти в нашому публічному реджистрі. Ви можете вільно запустити цей застосунок в рамках власної інфраструктури. У репозиторії є вичерпний README, а також маніфести, що дозволяють швидко розгорнути shared-lock у k8s-кластері.
Все, що вам необхідно зробити:
- Знайти адресу вашого etcd-сервера у Kubernetes (або розгорнути новий).
- Проставити необхідні параметри у маніфесті.
- Зробити kubectl apply -f kubernetes-example.yaml.
Відтепер ви можете користуватися застосунком.
Найбільша технічна конфа ТУТ! 👇
Можливі підводні камені
Ми на сто відсотків впевнені, що shared-lock здатний обробляти 500+ rps у конфігурації ворклоаду з 3 реплік. Втім, варто стежити за логами etcd інсталяції, оскільки під високим навантаженням вона може тимчасово припинити відповідати за визначений період часу. У такому випадку достатньо буде збільшити її ресурси.
Сподіваємося, що наявність готової відтестованої реалізації shared-lock спростить ваше життя. А якщо у вас будуть думки чи побажання щодо покращення застосунку — діліться з нами або ж закидуйте пул реквести. Будемо раді обговорити 😉
21 коментар
Додати коментар Підписатись на коментаріВідписатись від коментарів