(java || kotlin) && devOps
369 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

В прошлом посте я "забыл" про еще один, возможно ключевой аспект NoSQL хранилищ. А именно способность к горизонтальному масштабированию.
Почему ключевой - потому что причиной возникновения многих если не всех NoSQL решений стала недостаточная производительность RDBMS. А производительность начиная с некоторого момента (оптимальная архитектура, оптимальный запрос к СУБД, есть все индексы) прямо связана с возможностью масштабирования.
RDBMS как правило масштабируются горизонтально, а как я уже писал для этого способа есть физические ограничения - частота и число ядер процессора, сложность материнской платы.
Да, для реляционных СУБД часто есть репликация master-slave из коробки https://www.dmosk.ru/miniinstruktions.php?mini=postgresql-replication#master. Все примеры здесь и далее приведу для PostgreSQL.
Но в системе master-slave все равно есть узкое место в виде master-а, через которого идут все записи. Т.е. решение подходит для отчетных БД и для систем, где нагрузка на чтение в разы больше нагрузки на запись.
Да, есть сторонние библиотеки для репликации master-master https://github.com/bucardo/bucardo
Но появились они относительно недавно (думаю в ответ на популярность NoSQL). Часто это сторонние решения, и в любом случае гибкость SQL в плане выборки данных и строгая транзакционность плохо сочетаются с работой в режиме master-master.
Этих проблем нет в NoSQL, более того, они изначально проектируются для разрешения конфликтов чтения и записи с помощью таких средств, как вектора изменений, автоматический выбор master-а, обновление при чтении, возможность настройки степени согласованности данных. Это отдельная большая тема, в одном посте ее раскрыть невозможно.
Да, важное замечание - это не касается графовых хранилищ, т.к. для выборки может понадобиться обойти весь граф, а, следовательно, он должен храниться на одном сервере, в этом они похожи на традиционные реляционные СУБД.

#NoSQL #scalability
Всем привет!

Как можно масштабировать нагрузку в облаке? Под облаком я понимаю k8s как некий стандарт.

1) "ручками". Простой, но не надежный способ. Отягощающий фактор - не всегда у сопровождения ПРОМ есть права на смену настроек Deployment, тогда требуется отдельный деплой

2) выставить число подов и limits, соответствующими максимальной нагрузке. Еще проще, но совсем не рационально в плане использования ресурсов

3) HorizontalPodAutoscaler https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ Позволяет менять число подов сервиса при превышении некого порога нагрузки по cpu и memory. Порог - это не процент использования, а соотношения заданного requests с текущим значением. Подходит если требуемая нагрузка может превышать возможности 1 пода, и если сервис поддерживает горизонтальное масштабирование - т.е. stateless.

4) VerticalPodAutoscaler https://habr.com/ru/companies/flant/articles/541642/ Как следует из название - масштабирует поды вертикально. Тут есть нюанс - на данный момент k8s не позволяет менять requests и limits у пода "на ходу". Данная фича называется In-Place Update of Pod Resources и пока находится в бета-версии https://github.com/kubernetes/enhancements/issues/1287
Сейчас VerticalPodAutoscaler может следующее:
а) на основе истории использования подом ресурсов рассчитать и выдать рекомендуемые значения
б) применить эти значения при очередном плановом рестарте
в) самому рестартовать под
Подходит для следующих случаев:
а) statefull сервисы типа хранилища данных в облаке StatefullSet, для которых горизонтальное масштабирование или невозможно, или не приветствуется
б) "легкие" сервисы, которым достаточно одной реплики (или двух по требованиям надежности)
Из особенностей - не гарантируется корректная работа совместно с HorizontalPodAutoscaler по одним и тем же метрикам cpu и memory. И не работает с Java приложениями в плане нагрузки по памяти, т.к. Java сама управляет памятью, а VerticalPodAutoscaler эти данные не видит.
Ну и главный минус - необходимость рестарта для применения настроек

5) как избавиться от необходимости рестарта? Дождаться полноценного внедрения In-Place Update of Pod Resources и доработки VerticalPodAutoscaler. Или использовать бета-версию In-Place Update of Pod Resources реализовать соответствующий k8s controller самому. Это уже сделано: https://piotrminkowski.com/2023/08/22/resize-cpu-limit-to-speed-up-java-startup-on-kubernetes/
Данная реализация не умеет сама рассчитывать рекомендуемые значения requests. Зато позволяет красиво проблему JVM приложений, о которой я уже писал ранее - проблему долгого старта. Java, а точнее Spring приложение, при старте производит достаточно ресурсоемкую настройку контекста. Речь идет про обычный Spring Boot без применения всех возможных способов ускорить запуск. Если память после первоначальной настройки так и остается занятой созданными бинами, то cpu при старте требуется сильно больше, чем при обычной работе. Что с этим делать?
а) Не выделять лишние cpu - время старта увеличивается в разы
б) Пойти по пути, описанному в п.2 - выдать максимум ресурсов. Тогда может получиться, что мы тратим cpu на быстрый старт приложения, а далее ресурсы не утилизируются
в) In-Place Update of Pod Resources
Конкретно по данной реализации - мне она кажется не идеальной, т.к. ресурс по cpu настраивается в 2 манифестах, это не наглядно и способствует внесению несогласованных правок. Но решение в целом - полезное.

#k8s #cloud #scalability