Есть ли способ уменьшить размеры модулей только тогда, когда сообщение обрабатывается (модуль завершил свою задачу) с помощью HorizontalPodAutoscaler в Кубернетесе? - PullRequest
0 голосов
/ 12 июня 2019

Я установил Kubernetes Horizontal Pod Autoscaler с пользовательскими метриками с помощью адаптера prometheus https://github.com/DirectXMan12/k8s-prometheus-adapter. Prometheus следит за rabbitmq, а я наблюдаю за rabbitmq_queue_messages метрикой. Сообщения из очереди отбираются модулями, которые затем выполняют некоторую обработку, которая может длиться несколько часов.

Увеличение и уменьшение работают в зависимости от количества сообщений в очереди.

Проблема: Когда модуль завершает обработку и подтверждает сообщение, это уменьшит число. сообщений в очереди, и это приведет к тому, что Autoscaler прекратит работу модуля. Если у меня есть несколько модулей, выполняющих обработку, и один из них завершает работу, если я не ошибаюсь, Kubernetes может завершить работу модуля, который все еще выполняет обработку своего собственного сообщения. Это нежелательно, поскольку вся обработка, выполняемая модулем, будет потеряна.

Есть ли способ преодолеть это или другой способ, как это можно достичь?

Вот конфигурация Autoscaler:

kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
metadata:
  name: sample-app-rabbitmq
  namespace: monitoring
spec:
  scaleTargetRef:
    # you created above
    apiVersion: apps/v1
    kind: Deployment
    name: sample-app
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Object
    object:
      target:
        kind: Service
        name: rabbitmq-cluster
      metricName: rabbitmq_queue_messages_ready
      targetValue: 5

Ответы [ 2 ]

0 голосов
/ 05 июля 2019

Horizontal Pod Autoscaler не предназначен для длительных задач и не подойдет.Если вам нужно создать одну длительную задачу обработки для каждого сообщения, я бы выбрал один из этих двух подходов:

  • Использовать очередь задач, такую ​​как Celery .Он предназначен для точного решения вашей проблемы: создайте очередь задач, которую необходимо распределить среди работников, и убедитесь, что задачи выполняются до конца.Kubernetes даже предоставляет официальный пример этой установки.
  • Если вы не хотите вводить другой компонент, такой как Celery, вы можете создать Kubernetes job для каждоговходящее сообщение самостоятельно.Kubernetes позаботится о том, чтобы задание было выполнено хотя бы один раз - перепланируйте модуль, если он умрет, и т. Д. В этом случае вам нужно будет написать сценарий, который читает сообщения RabbitMQ и самостоятельно создает для них задания.

В обоих случаях убедитесь, что у вас также включен Cluster Autoscaler , чтобы новые узлы автоматически настраивались, если текущих узлов недостаточно для обработки нагрузки.

0 голосов
/ 14 июня 2019

Вы можете рассмотреть подход с использованием ловушки preStop .

Согласно документации Состояния контейнера , Определить обработчики postStart и preStop :

Перед входом контейнера в Termination выполняется preStop hook (если есть).

Таким образом, вы можете использовать в своем развертывании:

lifecycle:
      preStop:
        exec:
          command: ["your script"]

### обновление :

  1. Я хотел бы предоставить больше информации в связи с некоторыми исследованиями: существует интересный проект :

    KEDA позволяет выполнять мелкозернистое автоматическое масштабирование (в том числе до нуля) для управляемых событиями рабочих нагрузок Kubernetes.KEDA служит сервером метрик Kubernetes и позволяет пользователям определять правила автоматического масштабирования с использованием специального определения ресурса Kubernetes.KEDA может работать как в облаке, так и на периферии, изначально интегрируется с компонентами Kubernetes, такими как горизонтальный модуль автоматического масштабирования, и не имеет внешних зависимостей.

  2. По основному вопросу "Kubernetesможет завершить модуль, который все еще выполняет обработку своего собственного сообщения ".

    Согласно документации:

    "Развертывание - это концепция более высокого уровня, которая управляет ReplicaSets и предоставляет декларативные обновления для модулей вместе с множеством других полезных функций"

Развертывание поддерживается Replicaset.Согласно этому коду контроллера существует функция " getPodsToDelete ".В сочетании с « FilterPods » это дает результат: « Это гарантирует, что мы удаляем стручки на более ранних этапах, когда это возможно. »

Так как подтверждение концепции:

Вы можете создать развертывание с помощью init container .Контейнер Init должен проверить, есть ли сообщение в очереди, и завершить работу, когда появится хотя бы одно сообщение.Это позволит основному контейнеру запускать, принимать и обрабатывать это сообщение.В этом случае у нас будет два вида модулей - те, которые обрабатывают сообщение и потребляют процессор, а те, кто находится в начальном состоянии , находятся в режиме ожидания и ожидаютследующее сообщение.В этом случае начальные контейнеры будут удалены в первую очередь , когда HPA решит уменьшить количество реплик в развертывании.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: complete
  name: complete
spec:
  replicas: 5
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: complete
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: complete
    spec:
      hostname: c1
      containers:
      - name: complete
        command: 
        - "bash"
        args:
        - "-c"
        - "wa=$(shuf -i 15-30 -n 1)&& echo $wa && sleep $wa"
        image: ubuntu
        imagePullPolicy: IfNotPresent
        resources: {}
      initContainers:
      - name: wait-for
        image: ubuntu
        command: ['bash', '-c', 'sleep 30']


  dnsPolicy: ClusterFirst
  restartPolicy: Always
  terminationGracePeriodSeconds: 30

Надеюсь, эта помощь.

...