Разделенная балансировка нагрузки для сервисов с отслеживанием состояния в Kubernetes

В настоящее время я перехожу с Service Fabric на Kubernetes, и мне было интересно, как сделать настраиваемую и более сложную балансировку нагрузки.

До сих пор я уже читал о Kubernetes, предлагающих «Сервисы», которые выполняют балансировку нагрузки для скрытых за ними подов, но это доступно только более простыми способами.

То, что я хочу переписать прямо сейчас, выглядит в Service Fabric следующим образом:

У меня такой интерфейс:

public interface IEndpointSelector
{
    int HashableIdentifier { get; }
}

Контекст, отслеживающий учетную запись в моем приложении ASP.Net, например. наследует это. Затем я написал код, который на данный момент будет выполнять обнаружение служб через API кластера служебной фабрики и отслеживать все службы, обновляя их, когда какие-либо экземпляры умирают или возрождаются.

Затем, основываясь на детерминированном характере этого идентификатора (из-за кешируемого контекста и т. Д.) И учитывая несколько реплик целевой службы вызова frontend -> backend, я могу надежно маршрутизировать трафик для определенной учетной записи в определенный экземпляр конечной точки. .

Теперь, как мне это сделать в Kubernetes?

Как я уже упоминал, я нашел «Службы», но похоже, что их балансировка нагрузки не поддерживает настраиваемую логику и полезна только при работе с экземплярами без состояния.

Есть ли также способ обнаружения сервисов в Kubernetes, который я мог бы использовать здесь для замены моего существующего кода в некоторых точках?


person Sossenbinder    schedule 02.11.2019    source источник


Ответы (2)


StatefulSet

StatefulSet - это строительный блок для рабочей нагрузки с отслеживанием состояния на Kubernetes с определенными гарантиями.

Стабильная и уникальная сетевая идентичность

Модули StatefulSet Pods имеют уникальную идентичность, которая состоит из порядкового номера, стабильной сетевой идентичности и стабильного хранилища.

Например, если ваш StatefulSet имеет имя sharded-svc

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sharded-svc

И у вас, например, 3 реплики, им будет присвоено имя <name>-<ordinal>, где порядковый номер начинается с 0 до реплики-1.

Название ваших стручков будет:

sharded-svc-0
sharded-svc-1
sharded-svc-2

и эти pod'ы могут быть доступны с dns-name:

sharded-svc-0.sharded-svc.your-namespace.svc.cluster.local
sharded-svc-1.sharded-svc.your-namespace.svc.cluster.local
sharded-svc-2.sharded-svc.your-namespace.svc.cluster.local

учитывая, что ваша Безголовая служба называется sharded-svc, и вы развертываете ее в пространстве имен your-namespace.

Шардинг или разбиение на разделы

учитывая несколько реплик целевой службы вызова frontend -> backend, я могу надежно маршрутизировать трафик для определенной учетной записи на определенный экземпляр конечной точки.

Здесь вы описываете, что ваша служба с отслеживанием состояния называется сегментированной или секционированной. Kubernetes не предлагает этого "из коробки", но у вас есть все необходимые строительные блоки для такого рода услуг. Может случиться, что существует сторонняя служба, предоставляющая эту функцию, которую вы можете развернуть или разработать.

Прокси-сервер для шардинга

Вы можете создать службу sharding-proxy, состоящую из одного или нескольких модулей (возможно, из Deployment поскольку он может быть без гражданства). Этому приложению необходимо следить за модулями / сервисом / конечными точками в вашем sharded-svc, чтобы знать куда он может направлять трафик. Это можно разработать с помощью client-go или других альтернатив.

Этот сервис реализует логику вашего шардинга, например account-nr модуль 3 направляется в соответствующий pod порядковый номер

Обновление. Существуют сторонние прокси с функцией сегментирования, например Weaver Proxy

Запрос на сегментирование на основе полей заголовков / пути / тела

Рекомендуемая литература: Weaver: простота шардинга

Использование сегментированного сервиса

Чтобы использовать ваш сегментированный сервис, клиенты отправляют запрос вашему sharding-proxy, который затем применяет вашу маршрутизацию или логику сегментирования (например, запрос с модулем account-nr 3 направляется в соответствующий модуль порядковый номер) и перенаправляет запрос на реплику sharded-svc, которая соответствует вашей логике.

Альтернативные решения

Служба каталогов. Возможно, проще реализовать sharded-proxy как службу каталогов, но это зависит от ваших требований. Клиенты могут спросить вашу службу каталогов, на какую реплику statefulSet я должен отправить account-nr X и ваш ответ службы, например, sharded-svc-2

Логика маршрутизации в клиенте. Вероятно, наиболее простое решение - иметь вашу логику маршрутизации в клиенте и позволить этой логике вычислять, в какую реплику statefulSet отправить запрос.

person Jonas    schedule 03.11.2019
comment
@Sossenbinder В конце я добавил еще более простое решение (маршрутизация в клиенте), но это зависит от ваших требований. - person Jonas; 03.11.2019
comment
Я думаю, что сейчас я пойду по пути простого переписывания моей существующей логики на обнаружение сервисов kubernetes, но как только у меня будет время, я обязательно посмотрю на другие решения - person Sossenbinder; 03.11.2019
comment
Быстрый вопрос, который я только что придумал: когда я выполняю логику маршрутизации вручную, я все еще прячу свои модули за сервисом? Могу ли я каким-то образом вызвать службу с определенным идентификатором модуля, к которому я хочу получить доступ? Или мой клиент явно отслеживает стручки? - person Sossenbinder; 04.11.2019
comment
@Sossenbinder воспользуйтесь услугой! Модули одноразового использования и приходят и уходят (например, сбой узла или обновление), но обслуживание единообразно. - person Jonas; 04.11.2019
comment
Поэтому для ручной маршрутизации я бы, например, поставить службу перед одним модулем, а затем вручную направить к соответствующей службе вместо модуля, чтобы избежать эфемерного поведения конечной точки? - person Sossenbinder; 04.11.2019
comment
@Sossenbinder да, именно так - person Jonas; 04.11.2019
comment
@Sossenbinder, посмотрите мое обновление о прокси-сервере Weaver с сегментированием: github.com/gojek/weaver - person Jonas; 04.11.2019
comment
comment
Спасибо, вы очень помогли! - person Sossenbinder; 04.11.2019

Службы обычно запускают прокси в пространстве ядра по соображениям производительности, поэтому писать собственный код сложно. Cillium действительно позволяет писать программы eBPF для некоторых сетевых функций, но я не думаю, что маршрутизация услуг является одним из них. Так что это в значительной степени означает работу с прокси-сервером пользовательского пространства. Если ваша служба основана на HTTP, вы можете посмотреть на некоторые из существующих контроллеров Ingress, чтобы увидеть, подходят ли они достаточно близко или позволяют ли вам написать свою собственную логику маршрутизации сеанса. В противном случае вам пришлось бы самому написать демона, чтобы справиться с этим.

person coderanger    schedule 02.11.2019