Kubernetes v1.36: серверный шардированный list и watch для масштабирования кластеров

Когда кластер Kubernetes разрастается до десятков тысяч узлов, контроллеры, которые следят за ресурсами с высокой кардинальностью, например Pod, начинают испытывать серьёзные проблемы с производительностью. Каждая реплика горизонтально масштабированного контроллера получает полный поток событий от A

Kubernetes v1.36: серверный шардированный list и watch для масштабирования кластеров

Когда кластер Kubernetes разрастается до десятков тысяч узлов, контроллеры, которые следят за ресурсами с высокой кардинальностью, например Pod, начинают испытывать серьёзные проблемы с производительностью. Каждая реплика горизонтально масштабированного контроллера получает полный поток событий от API-сервера, вынуждена десериализовать все данные, тратя ресурсы CPU, памяти и сети, а затем отбрасывать объекты, за которые она не отвечает. Увеличение числа реплик не снижает нагрузку на каждую из них, а лишь умножает общие затраты. В Kubernetes v1.36 появилась альфа-функция серверного шардированного list и watch (KEP-5866), которая переносит фильтрацию событий на сторону API-сервера. Теперь каждая реплика контроллера получает только ту часть коллекции ресурсов, за которую она отвечает, что значительно снижает избыточную нагрузку и улучшает масштабируемость кластера.

Проблема клиентского шардирования

Некоторые контроллеры, например kube-state-metrics, уже поддерживают горизонтальное шардирование на стороне клиента. Каждая реплика получает назначенную ей часть ключевого пространства и отбрасывает объекты, которые ей не принадлежат. Хотя это работает функционально, такой подход не уменьшает объём данных, передаваемых от API-сервера: N реплик умножить на полный поток событий означает, что каждая реплика десериализует и обрабатывает каждое событие, а затем выбрасывает то, что ей не нужно. Пропускная способность сети растёт пропорционально числу реплик, а не размеру шарда. Процессорное время, потраченное на десериализацию, оказывается напрасным для отброшенной части данных.

Серверный шардированный list и watch решает эту проблему, перемещая фильтрацию вверх по потоку — непосредственно в API-сервер. Каждая реплика сообщает API-серверу, какой диапазон хешей ей принадлежит, и API-сервер отправляет только соответствующие события. Это кардинально меняет модель: вместо того чтобы каждая реплика обрабатывала весь поток данных, она получает только то, что ей действительно нужно.

Как это работает

Функция добавляет поле shardSelector в ListOptions. Клиенты указывают диапазон хешей с помощью функции shardRange(), например: shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')

API-сервер вычисляет детерминированный 64-битный хеш FNV-1a указанного поля и возвращает только те объекты, чей хеш попадает в диапазон [start, end). Это применяется как к ответам на list-запросы, так и к потокам событий watch. Хеш-функция даёт одинаковый результат на всех экземплярах API-сервера, поэтому функция работает корректно в многомастерных конфигурациях.

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

Какие контроллеры выиграют от серверного шардирования?

Новая функция в первую очередь полезна для операторов крупных кластеров Kubernetes, где количество узлов превышает несколько тысяч. Контроллеры, которые следят за ресурсами с высокой кардинальностью, такие как Pod, Service, EndpointSlice, получат наибольшую выгоду. Например, kube-state-metrics, prometheus-operator и custom controllers, которые горизонтально масштабируются, смогут значительно снизить потребление ресурсов. Разработчикам контроллеров потребуется обновить код для поддержки серверного шардирования, но это окупится за счёт снижения нагрузки на сеть и CPU.

Технические детали и производительность

Хеш FNV-1a выбран из-за его простоты, скорости и детерминированности. Он равномерно распределяет UID объектов по всему 64-битному пространству, что позволяет эффективно разбивать ресурсы на шарды произвольного размера. Разработчики могут задавать любые границы диапазона, что даёт гибкость при балансировке нагрузки между репликами.

При использовании серверного шардирования объём данных, передаваемых по сети, сокращается пропорционально числу шардов. Например, если кластер разбит на 4 шарда, каждая реплика получает примерно четверть всех событий вместо полного потока. Это снижает нагрузку на сеть, CPU и память как на стороне контроллера, так и на стороне API-сервера, поскольку последнему не нужно отправлять лишние данные. Важно отметить, что функция не изменяет семантику list и watch — она лишь фильтрует события на стороне сервера. Клиенты по-прежнему получают объекты в том же формате и могут использовать стандартные механизмы обработки.

Кого затронет и как

Новая функция в первую очередь полезна для операторов крупных кластеров Kubernetes, где количество узлов превышает несколько тысяч. Контроллеры, которые следят за ресурсами с высокой кардинальностью (Pod, Service, EndpointSlice), получат наибольшую выгоду. Например, kube-state-metrics, prometheus-operator и custom controllers, которые горизонтально масштабируются, смогут значительно снизить потребление ресурсов.

Разработчикам контроллеров потребуется обновить код для поддержки серверного шардирования. Это включает добавление логики для вычисления диапазона хешей и указания его в запросах list/watch. Библиотеки client-go, вероятно, получат поддержку этой функции в будущих версиях, что упростит интеграцию. Для пользователей, не управляющих крупными кластерами, функция может быть неактуальна, но она закладывает основу для более эффективного масштабирования в будущем.

Что будет дальше

Функция находится в альфе в Kubernetes v1.36. Ожидается, что она пройдёт цикл тестирования и получит обратную связь от сообщества. В следующих версиях возможно улучшение API, добавление поддержки в client-go и других официальных библиотеках, а также оптимизация производительности. Планируется также рассмотреть возможность шардирования по другим полям, помимо UID.

Итог

Серверный шардированный list и watch — важный шаг к улучшению масштабируемости Kubernetes для крупных кластеров. Перенося фильтрацию на сторону API-сервера, функция снижает избыточную нагрузку на контроллеры и сеть, позволяя эффективнее использовать ресурсы. Следите за развитием этой функции, если вы управляете большими кластерами или разрабатываете контроллеры для них.