Kubernetes: тестирование нагрузки и нагрузки на грузоподъемность — проблемы и решения
На самом деле, этот пост был запланирован как короткое описание об использовании Ideaffinity Для Kubernetes Pod:
Но потом, как часто бывает, после начала писать об одном, я столкнулся с другим, а потом еще один, и в результате — я сделал это длительное посмотрение по поводу тестирования нагрузки Kubernetes.
Итак, я начал о Ideaffinity
, но потом удивился, как будет Кубернаны кластер-автоскалер
Работа — потребуется во внимание настройку Nodefiness во время создания новых рабочих пользователей?
Чтобы проверить это, я сделал простой тест на нагрузку, используя Apache Benchmark Чтобы вызвать Kubernetes HorizontalPodautoScaler которые должны были создать новые стручки, а эти новые стручки должны были вызвать кластер-автоскалер Чтобы создать новые экземпляры AWS EC2, которые будут прикреплены к кластеру Kubernetes в качестве рабочих пользователей.
Затем я начал более сложный тест на нагрузку и сталкиваться с проблемой, когда стручки перестали масштабирование.
А потом … Я решил, что, поскольку я делаю нагрузочные тесты, то может быть хорошая идея проверить различные типы экземпляров AWS EC2 — T3, M5, C5. И, конечно же, нужно добавить результаты к этому посту.
И после этого — мы начали полное тестирование нагрузки и столкнуться с несколькими другими проблемами, и, очевидно, я должен был написать о том, как я их решил.
В конце концов, этот пост о том, что kubernetes Load-Testing в целом, а про типы экземпляров EC2 и о сетевом и DNS и пару других вещей вокруг высокогруженного приложения в кластере Kubernetes.
Примечание : Kk здесь: псевдоним> ~/.bashrc.
- Задание
- Выбор типа EC2
- EC2 AMD экземпляры
- ЭК2 Экземпляры гравитона
- Eksctl и Kubernetes Workernode Группы
- План тестирования
- Kubernetes NodeAffinity && Nodeselector
- Обновление развертывания
- Nodeselector Пользовательская этикетка
- Nodeselector от Kuber Label
- Тестирование AWS EC2 T3 VS M5 VS C5
- Kubernetes Nodeaffinity VS Kubernetes CluerautoScaler
- Тестирование нагрузки
- 1 день
- День 2
- NET/HTTP: запрос отменен (клиент. Тайм-аут превышен во время ожидания заголовков)
- AWS RDS — «Соединение отказано»
- AWS RDS Max Connections
- 3 день
- Kubernetes Livys и готовности
- Kubernetes: журналы PHP от Docker
- Первый тест
- php_network_getaddresses: getAddrinfo не удалось и DNS
- Kubernetes dnspolicy.
- Запуск DNS NODELOCAL в Куберате
- Kubernetes POD DNSCONFIG && Nameservers
- Второй тест
- Apache jmeter è grafana
Задание
Итак, у нас есть приложение, которое действительно любит ЦП.
Php, laravel. В настоящее время он работает в Digitalocean на 50 беговых капельках, плюс доля NFS, Memcache, Redis и MySQL.
Чего мы хотим, — это переместить это приложение к кластеру Kubernetes в AWS EKS, чтобы сэкономить деньги на инфраструктуре, потому что текущий в DiumperoCean стоит нам около 4000 долларов США/месяц, а один кластер EKS, который стоит около 500-600 долларов США. (сам кластер, плюс на 4 AWS T3.Medium Экземпляры EC2 для рабочих пользователей в двух отделенных людях доступности AWS, полностью 8 EC2).
При этой настройке на Diumpanyocean приложение перестало работать на 12 000 пользователей моделирования (48 000 в час).
Мы хотим продолжать до 15 000 пользователей (60 000/час, 1.440.000/день) на наших AWS EKS с AutoScaling.
Проект будет жить на выделенной группе на рабочих местах, чтобы избежать затрагивания других приложений в кластере. Чтобы создавать новые стручки только на этих рабочих местах — мы будем использовать NodeAffinity.
Кроме того, мы будем выполнять тестирование нагрузки с помощью трех разных типов экземпляров AWS EC2 — T3 , M5 , C5 , выбрать, какой из них лучше подойдет потребности нашей заявки, и сделает еще одно тестирование нагрузки, чтобы проверить, как наш Горизонтальподаутоскалер
и кластер-автоскалер
буду работать.
Выбор типа EC2
Какой использовать для нас?
- Т3 ? Blassable Processors, хорошая цена/процессор/рацион памяти, хорошо для большинства потребностей: T3 экземпляры следующее поколение Тип экземпляра общего назначения. Это обеспечивает базовый уровень производительности процессора с возможностью разрыва использования CPU в любое время до тех пор, пока требуется. М5
- ? Лучше всего для памяти на расходуемых приложений — больше оперативной памяти, меньше процессора: М5 экземпляры являются последними генерацией экземпляров общего назначения, работающие на процессорах Intel Xeon® Platinum 8175M. Эта семья предоставляет баланс вычисления, памяти и сетевых ресурсов и является хорошим выбором для многих приложений. С5
- ? Лучше всего для процессора Предназначенные приложения — больше процессорных ядер, лучший процессор, но меньшее количество памяти в сравнении с типом M5: С5 экземпляры Оптимизируются для вычисляющих рабочих нагрузок и доставляют экономически эффективные высокие показатели по низкой цене за соотношение вычислений.
Начнем с T3A — немного дешевле, чем общий T3.
EC2 AMD экземпляры
AWS обеспечивает экземпляры процессоров на базе AMD — T3A, M5A, C5A — с почти одинаковым процессором/памятью/сетью, которые они стоят немного меньше, но доступны не в каждом регионе и даже не во всех возможностях одинакового региона.
Например, в регионе AWS US-East-2 C5A доступны в US-East-2B и US-East-2C ДоступностьЗоны — но до сих пор не могут быть использованы в US-East-2a Отказ Поскольку я не хочу менять нашу автоматизацию прямо сейчас (доступностиЗоны выбраны во время предоставления, см. AWS: CloudFation — Использование списков по параметрам ) — тогда мы будем использовать общий тип T3.
ЭК2 Экземпляры гравитона
Кроме того, AWS введен M6G и C6. g Типы экземпляров с AWS Graviton2 процессоры , но использовать их, ваш кластер должен соответствовать некоторым ограничениям, проверять документацию Здесь >>> Отказ
Теперь давайте пойдем вперед и создадим три группы рабочих портов с экземплярами T3, M5 и C5 и проверим потребление ЦП на наше приложение на каждого из них.
Eksctl и Kubernetes Workernode Группы
Файл конфигурации для ваших групп узлов работников выглядит следующим:
--- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: "{{ eks\_cluster\_name }}" region: "{{ region }}" version: "{{ k8s\_version }}" nodeGroups: - name: "eat-test-t3-{{ item }}" instanceType: "t3.xlarge" privateNetworking: true labels: { role: eat-workers } volumeSize: 50 volumeType: gp2 desiredCapacity: 1 minSize: 1 maxSize: 1 availabilityZones: ["{{ item }}"] ssh: publicKeyName: "bttrm-eks-nodegroup-{{ region }}" iam: withAddonPolicies: autoScaler: true cloudWatch: true albIngress: true efs: true securityGroups: withShared: true withLocal: true attachIDs: [{{ worker\_nodes\_add\_sg }}] - name: "eat-test-m5-{{ item }}" instanceType: "m5.xlarge" privateNetworking: true labels: { role: eat-workers } volumeSize: 50 volumeType: gp2 desiredCapacity: 1 minSize: 1 maxSize: 1 availabilityZones: ["{{ item }}"] ssh: publicKeyName: "bttrm-eks-nodegroup-{{ region }}" iam: withAddonPolicies: autoScaler: true cloudWatch: true albIngress: true efs: true securityGroups: withShared: true withLocal: true attachIDs: [{{ worker\_nodes\_add\_sg }}] - name: "eat-test-c5-{{ item }}" instanceType: "c5.xlarge" privateNetworking: true labels: { role: eat-workers } volumeSize: 50 volumeType: gp2 desiredCapacity: 1 minSize: 1 maxSize: 1 availabilityZones: ["{{ item }}"] ssh: publicKeyName: "bttrm-eks-nodegroup-{{ region }}" iam: withAddonPolicies: autoScaler: true cloudWatch: true albIngress: true efs: true securityGroups: withShared: true withLocal: true attachIDs: [{{ worker\_nodes\_add\_sg }}]
Здесь у нас есть три группы узел рабочие, каждый с собственным типом EC2.
Развертывание описано с использованием Anisible и Экктл
см. AWS Elastic Kubernetes Service: автоматизация создания кластера, часть 2 — Anisible, eksctl пост, в двух разных доступных случаях.
Minsize
и Maxsize
установлены на 1 Таким образом, наш кластер AutoScaLer не начнет их масштабировать — у прошу прошумирования тестов я хочу увидеть нагрузку CPU на единственном экземпляре EC2 и для запуска kubectl Top
для стручек и узлов.
После того, как мы выберем наиболее подходящего типа EC2 для нас — бросит другие группы рабочихерных и включите автоскализацию.
План тестирования
Что и как мы проверим:
- PHP, Laravel, упакованный в докерный образ
- Все серверы имеют 4 ядра CPU и 16 ГБ ОЗУ (исключая RAM C5-8 GB)
- В развертывании приложения с Запросы Мы установим, чтобы запустить только один POD на рабочую сторону, попросив немного больше их половину на его процессоре, так что планировщик Kubernetes должен будет разместить POD на выделенный экземпляр рабочего режима
- Используя
Ideaffinity
Мы поставим на наших стручках только на необходимых рабочих местах - Стручки и кластерные автоскализаторы отключены сейчас
Мы создадим три группы рабочих портов с разными типами EC2 и развернут приложение на четыре пространства имен Kubernetes — один «по умолчанию» и три на каждый тип экземпляра.
В каждом таком пространстве имен приложение внутри будет настроено с помощью Ideaffinity
Для бега на необходимый тип EC2.
Делая это, у нас будет четыре Вход
Ресурсы с AWS LoadBalancer, Смотрите Kubernetes: Clusterip VS NodePort VS LoadBalancer, Services и Ingress — обзор с примерами И у нас будет четыре конечных точка для испытаний.
Kubernetes NodeAffinity && Nodeselector
Документация — Назначение стручков к узлам Отказ
Чтобы выбрать, на каком уземе работника Kubernetes должен запустить POD, мы можем использовать две типы меток — созданные самими собой или назначенными рабочими узлами Kubernetes.
В нашем файле конфигурации для рабочих пользователей мы установили такую метку:
... labels: { role: eat-workers } ...
Который будет прикреплен к каждому EC2, созданному в этой группе рабочего режима.
Обновите кластер:
И давайте проверим все теги на экземпляр:
Давайте проверим группы для рабочих портов с Экктл
:
$ eksctl — profile arseniy — cluster bttrm-eks-dev-1 get nodegroups CLUSTER NODEGROUP CREATED MIN SIZE MAX SIZE DESIRED CAPACITY INSTANCE TYPE IMAGE ID bttrm-eks-dev-1 eat-test-c5-us-east-2a 2020–08–20T09:29:28Z 1 1 1 c5.xlarge ami-0f056ad53eddfda19 bttrm-eks-dev-1 eat-test-c5-us-east-2b 2020–08–20T09:34:54Z 1 1 1 c5.xlarge ami-0f056ad53eddfda19 bttrm-eks-dev-1 eat-test-m5-us-east-2a 2020–08–20T09:29:28Z 1 1 1 m5.xlarge ami-0f056ad53eddfda19 bttrm-eks-dev-1 eat-test-m5-us-east-2b 2020–08–20T09:34:54Z 1 1 1 m5.xlarge ami-0f056ad53eddfda19 bttrm-eks-dev-1 eat-test-t3-us-east-2a 2020–08–20T09:29:27Z 1 1 1 t3.xlarge ami-0f056ad53eddfda19 bttrm-eks-dev-1 eat-test-t3-us-east-2b 2020–08–20T09:34:54Z 1 1 1 t3.xlarge ami-0f056ad53eddfda19
Давайте проверим созданный экземпляр Workernode ES2 с помощью The -L, чтобы выбрать только те, которые имеют нашу собственную этикетку « Роль: есть рабочие » и сортируя их по их типам EC2:
$ kk -n eks-dev-1-eat-backend-ns get node -l role=eat-workers -o=json | jq -r '[.items | sort\_by(.metadata.labels["beta.kubernetes.io/instance-type"])[] | {name:.metadata.name, type:.metadata.labels["beta.kubernetes.io/instance-type"], region:.metadata.labels["failure-domain.beta.kubernetes.io/zone"]}]' [ { "name": "ip-10–3–47–253.us-east-2.compute.internal", "type": "c5.xlarge", "region": "us-east-2a" }, { "name": "ip-10–3–53–83.us-east-2.compute.internal", "type": "c5.xlarge", "region": "us-east-2b" }, { "name": "ip-10–3–33–222.us-east-2.compute.internal", "type": "m5.xlarge", "region": "us-east-2a" }, { "name": "ip-10–3–61–225.us-east-2.compute.internal", "type": "m5.xlarge", "region": "us-east-2b" }, { "name": "ip-10–3–45–186.us-east-2.compute.internal", "type": "t3.xlarge", "region": "us-east-2a" }, { "name": "ip-10–3–63–119.us-east-2.compute.internal", "type": "t3.xlarge", "region": "us-east-2b" } ]
Узнать больше о форматировании kubectl выхода Здесь >> >
Обновление развертывания
Nodeselector Пользовательская этикетка
Сначала давайте разверним наше приложение для всех экземпляров с Этикетки: {роль: есть работники}
— Kubernetes придется создать стручки на 6 серверов — на двоих на каждом типе EC2.
Обновите развертывание, добавьте Nodeselector с роль Этикетка с ценностью « есть рабочие »:
apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Chart.Name }} annotations: reloader.stakater.com/auto: "true" spec: replicas: {{ .Values.replicaCount }} strategy: type: RollingUpdate selector: matchLabels: application: {{ .Chart.Name }} template: metadata: labels: application: {{ .Chart.Name }} version: {{ .Chart.Version }}-{{ .Chart.AppVersion }} managed-by: {{ .Release.Service }} spec: containers: - name: {{ .Chart.Name }} image: {{ .Values.image.registry }}/{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ .Values.image.tag }} imagePullPolicy: Always ... ports: - containerPort: {{ .Values.appConfig.port }} livenessProbe: httpGet: path: {{ .Values.appConfig.healthcheckPath }} port: {{ .Values.appConfig.port }} initialDelaySeconds: 10 readinessProbe: httpGet: path: {{ .Values.appConfig.healthcheckPath }} port: {{ .Values.appConfig.port }} initialDelaySeconds: 10 resources: requests: cpu: {{ .Values.resources.requests.cpu | quote }} memory: {{ .Values.resources.requests.memory | quote }} nodeSelector: role: eat-workers volumes: imagePullSecrets: - name: gitlab-secret
репликонт
Установлено на 6, согласно номеру экземпляров.
Развернуть это:
$ helm secrets upgrade --install --namespace eks-dev-1-eat-backend-ns --set image.tag=179217391 --set appConfig.appEnv=local --set appConfig.appUrl=https://dev-eks.eat.example.com/ --atomic eat-backend . -f secrets.dev.yaml --debug
Проверить:
$ kk -n eks-dev-1-eat-backend-ns get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector NAME STATUS NODE TYPE eat-backend-57b7b54d98–7m27q Running ip-10–3–63–119.us-east-2.compute.internal map[role:eat-workers] eat-backend-57b7b54d98–7tvtk Running ip-10–3–53–83.us-east-2.compute.internal map[role:eat-workers] eat-backend-57b7b54d98–8kphq Running ip-10–3–47–253.us-east-2.compute.internal map[role:eat-workers] eat-backend-57b7b54d98-l24wr Running ip-10–3–61–225.us-east-2.compute.internal map[role:eat-workers] eat-backend-57b7b54d98-ns4nr Running ip-10–3–45–186.us-east-2.compute.internal map[role:eat-workers] eat-backend-57b7b54d98-sxzk4 Running ip-10–3–33–222.us-east-2.compute.internal map[role:eat-workers] eat-backend-memcached-0 Running ip-10–3–63–119.us-east-2.compute.internal
Хорошо — у нас есть наши 6 стручков на 6 рабочих местах.
Nodeselector от Kuber Label
Теперь давайте обновим развертывание, чтобы использовать этикетки, установленные самими kubernetes, например, мы можем использовать beta.kubernetes.io/instance-type Где мы можем установить тип экземпляра, который мы хотели бы использовать для развертывания POD только на EC2 выбранного типа.
репликонт
Теперь установлено значение 2 в соответствии с примером того же типа — будет иметь два стручка, работающих на двух EC2.
Снимите развертывание:
$ helm --namespace eks-dev-1-eat-backend-ns uninstall eat-backend release "eat-backend" uninstalled
Обновите манифест — добавьте T3 Так что оба условия будут работать — роль
и Тип экземпляра
:
... nodeSelector: beta.kubernetes.io/instance-type: t3.xlarge role: eat-workers ...
Давайте разверним их до трех новых пространств имен, и давайте добавим постфикс к каждому из T3, M5, C5, поэтому для группы T3 имя будет « EKS-DEV-1-EAT — BASHEND-NS- T3 «.
Добавьте --create-пространство имен
Для хелмы:
$ helm secrets upgrade --install --namespace eks-dev-1-eat-backend-ns-t3 --set image.tag=180029557 --set appConfig.appEnv=local --set appConfig.appUrl=https://t3-dev-eks.eat.example.com/ --atomic eat-backend . -f secrets.dev.yaml --debug --create-namespace
Повторите то же самое для M5, C5 и проверьте.
T3:
$ kk -n eks-dev-1-eat-backend-ns-t3 get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector NAME STATUS NODE TYPE eat-backend-cc9b8cdbf-tv9h5 Running ip-10–3–45–186.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:t3.xlarge role:eat-workers] eat-backend-cc9b8cdbf-w7w5w Running ip-10–3–63–119.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:t3.xlarge role:eat-workers] eat-backend-memcached-0 Running ip-10–3–53–83.us-east-2.compute.internal
M5:
$ kk -n eks-dev-1-eat-backend-ns-m5 get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector NAME STATUS NODE TYPE eat-backend-7dfb56b75c-k8gt6 Running ip-10–3–61–225.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:m5.xlarge role:eat-workers] eat-backend-7dfb56b75c-wq9n2 Running ip-10–3–33–222.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:m5.xlarge role:eat-workers] eat-backend-memcached-0 Running ip-10–3–47–253.us-east-2.compute.internal
И C5:
$ kk -n eks-dev-1-eat-backend-ns-c5 get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector NAME STATUS NODE TYPE eat-backend-7b6778c5c-9g6st Running ip-10–3–47–253.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:c5.xlarge role:eat-workers] eat-backend-7b6778c5c-sh5sn Running ip-10–3–53–83.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:c5.xlarge role:eat-workers] eat-backend-memcached-0 Running ip-10–3–47–58.us-east-2.compute.internal
Все готово к тестированию.
Тестирование AWS EC2 T3 VS M5 VS C5
Запустите тесты, один и тот же набор для всех групп рабочихернгов, и посмотреть на расход CPU с помощью стручков.
T3.
Стручки:
$ kk top nod-n eks-dev-1-eat-backend-ns-t3 top pod NAME CPU(cores) MEMORY(bytes) eat-backend-79cfc4f9dd-q22rh 1503m 103Mi eat-backend-79cfc4f9dd-wv5xv 1062m 106Mi eat-backend-memcached-0 1m 2Mi
Узлы:
$ kk top node -l role=eat-workers,beta.kubernetes.io/instance-type=t3.xlarge NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% ip-10–3–45–186.us-east-2.compute.internal 1034m 26% 1125Mi 8% ip-10–3–63–119.us-east-2.compute.internal 1616m 41% 1080Mi 8%
M5.
Стручки:
$ kk -n eks-dev-1-eat-backend-ns-m5 top pod NAME CPU(cores) MEMORY(bytes) eat-backend-6f5d68778d-484lk 1039m 114Mi eat-backend-6f5d68778d-lddbw 1207m 105Mi eat-backend-memcached-0 1m 2Mi
Узлы:
$ kk top node -l role=eat-workers,beta.kubernetes.io/instance-type=m5.xlarge NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% ip-10–3–33–222.us-east-2.compute.internal 1550m 39% 1119Mi 8% ip-10–3–61–225.us-east-2.compute.internal 891m 22% 1087Mi 8%
C5.
Стручки:
$ kk -n eks-dev-1-eat-backend-ns-c5 top pod NAME CPU(cores) MEMORY(bytes) eat-backend-79b947c74d-mkgm9 941m 103Mi eat-backend-79b947c74d-x5qjd 905m 107Mi eat-backend-memcached-0 1m 2Mi
Узлы:
$ kk top node -l role=eat-workers,beta.kubernetes.io/instance-type=c5.xlarge NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% ip-10–3–47–253.us-east-2.compute.internal 704m 17% 1114Mi 19% ip-10–3–53–83.us-east-2.compute.internal 1702m 43% 1122Mi 19%
На самом деле, вот и все.
Результаты:
- T3 : 1000-1500 мкпу, 385 мс ответ
- M5 : 1000-1200 мкпу, 371 мс ответ
- C5 : 900-1000 МКПУ, 370 мс ответ
Итак, давайте используем тип S5 сейчас, поскольку они, кажется, лучше, используя процессор.
Kubernetes Nodeaffinity VS Kubernetes CluerautoScaler
Одним из главных вопросов, с которыми я борется — будет ли автоскалер кластера уважать Ideaffinity
?
Идти вперед — да, это будет.
Наше Горизонтальподаутоскалер
выглядит так:
--- apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: {{ .Chart.Name }}-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: {{ .Chart.Name }} minReplicas: {{ .Values.hpa.minReplicas }} maxReplicas: {{ .Values.hpa.maxReplicas }} metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: {{ .Values.hpa.cpuUtilLimit }}
cpuutillimit
Установлено на 30%, поэтому, когда PHP-FPM начнет активно использовать свои FPM-работники — тогда нагрузка на процессор повысится, и предел 30% даст нам некоторое время для раскрутки новых экземпляров EC2, пока уже существующие средства будут сохранять уже существующие соединения.
Смотрите Kubernetes: HorizontalPodautoScaler — обзор с примерами пост для более подробной информации.
Nodeselector
Теперь описывается с помощью шаблона HELM и его Значения.yaml
Проверьте Helm: Cubernetes Package Manager — обзор, начать :
... nodeSelector: beta.kubernetes.io/instance-type: {{ .Values.nodeSelector.instanceType | quote }} role: {{ .Values.nodeSelector.role | quote }} ...
И его ценности.yaml:
... nodeSelector: instanceType: "c5.xlarge" role: "eat-workers ...
Восстановите все, и давайте начнем с полного тестирования нагрузки.
Без действия во всех ресурсах расход было следующим:
$ kk -n eks-dev-1-eat-backend-ns top pod NAME CPU(cores) MEMORY(bytes) eat-backend-b8b79574–8kjl4 50m 55Mi eat-backend-b8b79574–8t2pw 39m 55Mi eat-backend-b8b79574-bq8nw 52m 68Mi eat-backend-b8b79574-swbvq 40m 55Mi eat-backend-memcached-0 2m 6Mi
На 4-х … C5.xlarge Сервер (4 ядра, 8 ГБ ОЗУ):
$ kk top node -l role=eat-workers NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% ip-10–3–34–151.us-east-2.compute.internal 105m 2% 1033Mi 18% ip-10–3–39–132.us-east-2.compute.internal 110m 2% 1081Mi 19% ip-10–3–54–32.us-east-2.compute.internal 166m 4% 1002Mi 17% ip-10–3–56–98.us-east-2.compute.internal 106m 2% 1010Mi 17%
И уже упомянул Горизонтальподаутоскалер
С 30% CPU Запросы
Ограничение:
$ kk -n eks-dev-1-eat-backend-ns get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE eat-backend-hpa Deployment/eat-backend 1%/30% 4 40 4 6m27s
Тестирование нагрузки
1 день
Короче говоря, это был самый первый день всего тестирования, который всего три дня занял три дня.
Этот тест был выполнен в четырех T3A.Medium Экземпляры с той же 1 POD на рабочемоне с включенным HPA и кластерным автоскалером.
И все прошло хорошо, пока мы не добрались до 8000 одновременных пользователей — см. Время ответа:
И стручки перестали на масштабирование:
Потому что они перестали создавать более 30% загрузки процессора.
Самое первое мое предположение было правильным: PHP-FPM был настроен как OnDemand
С максимум 5 рабочих FPM (см. PHP-FPM: Manager Process Manager — Dynamic vs ondemand vs статически , Рус ).
Итак, FPM начал 5 работников, которые не могут сделать больше нагрузки на ядра ЦП более 30% от запросов от Развертывание
И HPA перестал их масштабировать.
На второй день мы изменили его на Динамический
(И на третьем — к статично
Во избежание проведения времени для создания новых процессов) с максимальными 50 работниками — после этого они начали генерировать загрузку ЦП все время, поэтому HPA продолжал масштабировать наши стручки.
Хотя есть еще одно решение, как просто, чтобы добавить еще одно условие для HPA, например — LoadsAlancer Connections, а затем мы сделаем это (см. Kubernetes: мониторинг кластера с оператором PROMETHEUS ).
День 2
Исходя из испытаний JMeter, используя те же тесты, как вчера (а завтра).
Начните с одного пользователя и увеличить их до 15.000 одновременных пользователей.
Нынешняя инфраструктура на цифровой камере обрабатывается 12 000 на максимуме — но на AWS EKS мы хотим, чтобы иметь возможность не допустить до 15 000 пользователей.
Поехали:
На 3300 пользователей Pods начал масштабирование:
… 0s Normal SuccessfulRescale HorizontalPodAutoscaler New size: 5; reason: cpu resource utilization (percentage of request) above target 0s Normal ScalingReplicaSet Deployment Scaled up replica set eat-backend-b8b79574 to 5 0s Normal SuccessfulCreate ReplicaSet Created pod: eat-backend-b8b79574-l68vq 0s Warning FailedScheduling Pod 0/12 nodes are available: 12 Insufficient cpu, 8 node(s) didn't match node selector. 0s Warning FailedScheduling Pod 0/12 nodes are available: 12 Insufficient cpu, 8 node(s) didn't match node selector. 0s Normal TriggeredScaleUp Pod pod triggered scale-up: [{eksctl-bttrm-eks-dev-1-nodegroup-eat-us-east-2b-NodeGroup-1N0QUROWQ8K2Q 2->3 (max: 20)}] …
И новые узлы EC2, а также:
$ kk -n eks-dev-1-eat-backend-ns top pod NAME CPU(cores) MEMORY(bytes) eat-backend-b8b79574–8kjl4 968m 85Mi eat-backend-b8b79574–8t2pw 1386m 85Mi eat-backend-b8b79574-bq8nw 737m 71Mi eat-backend-b8b79574-l68vq 0m 0Mi eat-backend-b8b79574-swbvq 573m 71Mi eat-backend-memcached-0 20m 15Mi $ kk -n eks-dev-1-eat-backend-ns get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE eat-backend-hpa Deployment/eat-backend 36%/30% 4 40 5 37m $ kk top node -l role=eat-workers NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% ip-10–3–34–151.us-east-2.compute.internal 662m 16% 1051Mi 18% ip-10–3–39–132.us-east-2.compute.internal 811m 20% 1095Mi 19% ip-10–3–53–136.us-east-2.compute.internal 2023m 51% 567Mi 9% ip-10–3–54–32.us-east-2.compute.internal 1115m 28% 1032Mi 18% ip-10–3–56–98.us-east-2.compute.internal 1485m 37% 1040Mi 18%
5500 — все хорошо до сих пор:
NET/HTTP: запрос отменен (клиент. Тайм-аут превышен во время ожидания заголовков)
На 7 000-8.000 мы столкнулись с проблемами — PODS начала неспособность к тому, что ЛИЦИВНОЕ ИСКЛЮЧЕНИЕ И ЛИЧНОСТЬ И ЛЮБИМОСТИ ДЛЯ ЛИЧНОСТИ КЛИЕНТАМИ. Тайм-аут превышен во время ожидания заголовков » ошибка:
0s Warning Unhealthy Pod Liveness probe failed: Get [http://10.3.38.7:80/:](http://10.3.38.7:80/:) net/http: request canceled (Client.Timeout exceeded while awaiting headers) 1s Warning Unhealthy Pod Readiness probe failed: Get [http://10.3.44.96:80/:](http://10.3.44.96:80/:) net/http: request canceled (Client.Timeout exceeded while awaiting headers) 0s Normal MODIFY Ingress rule 1 modified with conditions [{ Field: "path-pattern", Values: ["/\*"] }] 0s Warning Unhealthy Pod Liveness probe failed: Get [http://10.3.44.34:80/:](http://10.3.44.34:80/:) net/http: request canceled (Client.Timeout exceeded while awaiting headers)
И с большим количеством пользователей это только хуже — 10.000:
Стручки начали терпеть неудачу почти все время, и худшее было то, что у нас даже не было никаких журналов из приложения — он продолжил писать в журнал файла внутри контейнеров, и мы исправили это только на третий день.
Нагрузка была такой:
$ kk -n eks-dev-1-eat-backend-ns get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE eat-backend-hpa Deployment/eat-backend 60%/30% 4 40 15 63m $ kk top node -l role=eat-workers NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% ip-10–3–33–155.us-east-2.compute.internal 88m 2% 951Mi 16% ip-10–3–34–151.us-east-2.compute.internal 1642m 41% 1196Mi 20% ip-10–3–39–128.us-east-2.compute.internal 67m 1% 946Mi 16% ip-10–3–39–132.us-east-2.compute.internal 73m 1% 1029Mi 18% ip-10–3–43–76.us-east-2.compute.internal 185m 4% 1008Mi 17% ip-10–3–47–243.us-east-2.compute.internal 71m 1% 959Mi 16% ip-10–3–47–61.us-east-2.compute.internal 69m 1% 945Mi 16% ip-10–3–53–124.us-east-2.compute.internal 61m 1% 955Mi 16% ip-10–3–53–136.us-east-2.compute.internal 75m 1% 946Mi 16% ip-10–3–53–143.us-east-2.compute.internal 1262m 32% 1110Mi 19% ip-10–3–54–32.us-east-2.compute.internal 117m 2% 985Mi 17% ip-10–3–55–140.us-east-2.compute.internal 992m 25% 931Mi 16% ip-10–3–55–208.us-east-2.compute.internal 76m 1% 942Mi 16% ip-10–3–56–98.us-east-2.compute.internal 1578m 40% 1152Mi 20% ip-10–3–59–239.us-east-2.compute.internal 1661m 42% 1175Mi 20% $ kk -n eks-dev-1-eat-backend-ns top pod NAME CPU(cores) MEMORY(bytes) eat-backend-b8b79574–5d6zl 0m 0Mi eat-backend-b8b79574–7n7pq 986m 184Mi eat-backend-b8b79574–8t2pw 709m 135Mi eat — backend-b8b79574-bq8nw 0m 0Mi eat-backend-b8b79574-ds68n 0m 0Mi eat-backend-b8b79574-f4qcm 0m 0Mi eat-backend-b8b79574-f6wfj 0m 0Mi eat-backend-b8b79574-g7jm7 842m 165Mi eat-backend-b8b79574-ggrdg 0m 0Mi eat-backend-b8b79574-hjcnh 0m 0Mi eat-backend-b8b79574-l68vq 0m 0Mi eat-backend-b8b79574-mlpqs 0m 0Mi eat-backend-b8b79574-nkwjc 2882m 103Mi eat-backend-b8b79574-swbvq 2091m 180Mi eat-backend-memcached-0 31m 54Mi
А стручки перезапущен бесконечно:
$ kk -n eks-dev-1-eat-backend-ns get pod NAME READY STATUS RESTARTS AGE eat-backend-b8b79574–5d6zl 0/1 CrashLoopBackOff 6 17m eat-backend-b8b79574–7n7pq 1/1 Running 5 9m13s eat-backend-b8b79574–8kjl4 0/1 CrashLoopBackOff 7 64m eat-backend-b8b79574–8t2pw 0/1 CrashLoopBackOff 6 64m eat-backend-b8b79574-bq8nw 1/1 Running 6 64m eat-backend-b8b79574-ds68n 0/1 CrashLoopBackOff 7 17m eat-backend-b8b79574-f4qcm 1/1 Running 6 9m13s eat-backend-b8b79574-f6wfj 0/1 Running 6 9m13s eat-backend-b8b79574-g7jm7 0/1 CrashLoopBackOff 5 25m eat-backend-b8b79574-ggrdg 1/1 Running 6 9m13s eat-backend-b8b79574-hjcnh 0/1 CrashLoopBackOff 6 25m eat-backend-b8b79574-l68vq 1/1 Running 7 29m eat-backend-b8b79574-mlpqs 0/1 CrashLoopBackOff 6 21m eat-backend-b8b79574-nkwjc 0/1 CrashLoopBackOff 5 9m13s eat-backend-b8b79574-swbvq 0/1 CrashLoopBackOff 6 64m eat-backend-memcached-0 1/1 Running 0 64m
После 12.000-13.000 пользователей у нас было только один POD alive:
$ kk -n eks-dev-1-eat-backend-ns top pod NAME CPU(cores) MEMORY(bytes) eat-backend-b8b79574–7n7pq 0m 0Mi eat-backend-b8b79574–8kjl4 0m 0Mi eat-backend-b8b79574–8t2pw 0m 0Mi eat — backend-b8b79574-bq8nw 0m 0Mi eat-backend-b8b79574-ds68n 0m 0Mi eat-backend-b8b79574-f4qcm 0m 0Mi eat-backend-b8b79574-f6wfj 0m 0Mi eat-backend-b8b79574-g7jm7 0m 0Mi eat-backend-b8b79574-ggrdg 0m 0Mi eat-backend-b8b79574-hjcnh 0m 0Mi eat-backend-b8b79574-l68vq 0m 0Mi eat-backend-b8b79574-mlpqs 0m 0Mi eat-backend-b8b79574-nkwjc 3269m 129Mi eat-backend-b8b79574-swbvq 0m 0Mi eat-backend-memcached-0 23m 61Mi $ kk -n eks-dev-1-eat-backend-ns get pod NAME READY STATUS RESTARTS AGE eat-backend-b8b79574–5d6zl 1/1 Running 7 20m eat-backend-b8b79574–7n7pq 0/1 CrashLoopBackOff 6 12m eat-backend-b8b79574–8kjl4 0/1 CrashLoopBackOff 7 67m eat-backend-b8b79574–8t2pw 0/1 CrashLoopBackOff 7 67m eat-backend-b8b79574-bq8nw 0/1 CrashLoopBackOff 6 67m eat-backend-b8b79574-ds68n 0/1 CrashLoopBackOff 8 20m eat-backend-b8b79574-f4qcm 0/1 CrashLoopBackOff 6 12m eat-backend-b8b79574-f6wfj 0/1 CrashLoopBackOff 6 12m eat-backend-b8b79574-g7jm7 0/1 CrashLoopBackOff 6 28m eat-backend-b8b79574-ggrdg 0/1 Running 7 12m eat-backend-b8b79574-hjcnh 0/1 CrashLoopBackOff 7 28m eat-backend-b8b79574-l68vq 0/1 CrashLoopBackOff 7 32m eat-backend-b8b79574-mlpqs 0/1 CrashLoopBackOff 7 24m eat-backend-b8b79574-nkwjc 1/1 Running 7 12m eat-backend-b8b79574-swbvq 0/1 CrashLoopBackOff 7 67m eat-backend-memcached-0 1/1 Running 0 67m
И только в этот момент я вспомнил о логических файлах в контейнерах и проверил их — я нашел, что наш сервер базы данных начал отказываться от подключения:
bash-4.4# cat ./new-eat-backend/storage/logs/laravel-2020–08–20.log [2020–08–20 16:53:25] production.ERROR: SQLSTATE[HY000] [2002] Connection refused {"exception":"[object] (Doctrine\\DBAL\\Driver\\PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused at /var/www/new-eat-backend/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:31, PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused at /var/www/new-eat-backend/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:27)
AWS RDS — «Соединение отказано»
Для баз данных мы используем RDS Aurora Mysql со своими собственными автоскализациями.
Выпуск вот в том, что сначала тестирование выполняется в среде Dev, которая имеет небольшие экземпляры базы данных — db.t2.medium С 4 ГБ ОЗУ, а через секунду — все запросы от приложения были отправлены на главный экземпляр БД, пока рабы Aurora не использовались вообще. Мастер послужил около 155 запросов в секунду.
На самом деле, одним из основных преимуществ RDS Aurora является именно главным/подчиненным разделением — все запросы на изменение данных ( обновление
, Создать
и т. Д.) ДОЛЖЕН быть отправлен в мастер, пока все Выберите
— до раба.
Во время этого рабы могут быть масштабированы своими собственными аутокалинговыми политиками:
Кстати, мы делаем это не в том порядке — лучше нас масштабировать рабов по номеру подключений, а не CPU. Изменит это позже.
AWS RDS Max Connections
На самом деле, согласно Документация — Для пределов подключений для T3.Medium должны быть 90 соединений одновременно, пока мы были отклонены после 50-60:
Я говорил с AWS Arductures, а затем спросил их о «90 соединений в документации» — но они не могли помочь нам с ответом, как « Может быть, это до _ 90_? «
И вообще, после испытаний у нас была такая картина:
52% потерпели неудачу, и это, очевидно, действительно плохо:
Но для меня главное здесь было то, что сам кластер, его самолет, и сеть работала, как ожидалось.
Проблема базы данных будет решена на третий день — обновит тип экземпляра и настроит приложение для начала работы с рабами Aurora.
3 день
Ну — самый интересный день:-)
Сначала — разработчики фиксированные Aurora Plaves, поэтому приложение будет использовать их сейчас.
Кстати, говорил с командой AWS вчера, и они рассказали мне о RDS прокси Сервис — нужно проверить это, выглядит многообещающим.
Также необходимо проверить настройку OPCAChe, поскольку он может уменьшить использование ЦП, см. PHP: Кеширование PHP-скриптов — Настройка и Тюнинг Опкаш (в рус).
В то время как разработчики делают свои изменения — давайте посмотрим на наших чувствительностях и готовности Kubernetes и готовности.
Kubernetes Livys и готовности
Нашел пару интересных постов — Kubernetes Lives и готовности зондов: как избежать стрельбы себя в ноге и Живит и готовность зондов с Laravel Отказ
Наши разработчики уже добавлены два новых конечных точка:
... $router->get('healthz', 'HealthController@phpCheck'); $router->get('readiness', 'HealthController@dbReadCheck'); ...
И HealthController
следующий:
ok == 1) { return response('ok'); } } catch (\Throwable $err) { // ignore } return response('err', 500); } }
По /Healthz
URI Мы проверим, что сам Pod запущен, а PHP работает.
По /Готовность
— Убедитесь, что приложение запущено и готово принять соединения:
ЛИЦИВНОЕ ПРОБРАЖА
: Если не удалось — kubernetes перезапустит стручокINationalDelayseconds
: должно быть длиннее максимального времени инициализации для контейнера — Сколько Larave нужно? Давайте установим его до 5 секундFailureTheReshold
: три попытки, если они все будут потерпеть неудачу — POD будет перезапущенПериоды
: значение по умолчанию составляет 15 секунд, как я помню — пусть это будет такreadishprobe
: Определяет, когда приложение готово к обслуживанию запросов. Если этот чек не пройдет неудачника — Kubernetes повернет этот POD от балансировки нагрузки/услугиINationalDelayseconds
: Давайте использовать 5 секунд здесь, чтобы начать PHP и подключиться к базе данныхПериодионные
S: Как мы ожидаем проблем с соединениями базы данных — Давайте установим его до 5 секундFailureTheReshold
: также три, как дляЛИЦИЛСПРОБА
SuccessthreShold
: После того, как насколько успешная попытка подумайте о том, что POD готов к трафик — давайте настроим его на 1Тайм-аутсекунды
: по умолчанию 1, давайте использовать его
Посмотреть Настроить зонды Отказ
Обновлять зонды в развертывании:
... livenessProbe: httpGet: path: {{ .Values.appConfig.healthcheckPath }} port: {{ .Values.appConfig.port }} initialDelaySeconds: 5 failureThreshold: 3 periodSeconds: 15 readinessProbe: httpGet: path: {{ .Values.appConfig.readycheckPath }} port: {{ .Values.appConfig.port }} initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 3 successThreshold: 1 timeoutSeconds: 1 ...
Позже переместит его к Значения.yaml
Отказ
И добавьте новую переменную для сервера базы данных ведомого:
... - name: DB\_WRITE\_HOST value: {{ .Values.appConfig.db.writeHost }} - name: DB\_READ\_HOST value: {{ .Values.appConfig.db.readHost }} ...
Kubernetes: журналы PHP от Docker
Ах, и бревно!.
Разработчики включали журналы, которые будут отправлены на /dev/stderr
Вместо того, чтобы писать в файл, а демон Docker должен получить их и отправить его в Кубернаны — но в kubectl logs
Мы можем видеть сообщения только из Nginx.
Перейти, чтобы проверить Linux: PHP-FPM, Docker, STDOUT и STDERR — Нет журналов ошибок приложения Напомним, как это работает и перейдите к проверке дескрипторов.
В POD найдите PID Master’s Php-Process:
bash-4.4# ps aux |grep php-fpm | grep master root 9 0.0 0.2 171220 20784 ? S 12:00 0:00 php-fpm: master process (/etc/php/7.1/php-fpm.conf)
И проверять его дескрипторы:
bash-4.4# ls -l /proc/9/fd/2 l-wx — — — 1 root root 64 Aug 21 12:04 /proc/9/fd/2 -> /var/log/php/7.1/php-fpm.log bash-4.4# ls -l /proc/9/fd/1 lrwx — — — 1 root root 64 Aug 21 12:04 /proc/9/fd/1 -> /dev/null
FD/2 Это Стдерр процесса, и он сопоставлен на /var/log/php/7.1/php-fpm.log
вместо /dev/stderr
— Вот почему мы ничего не видим в логах Kubectl.
REREP The «/var/log/php/7.1/php-fpm.log» рекурсивно в /etc/php/7.1
каталог и найти php-fpm.conf
какой по умолчанию есть Ошибка \ _log =/var/log/php/7.1/php-fpm.log
Отказ Исправить это к /dev/stderr
— И это сделано.
Запустите тест снова!
От 1 до 15.000 пользователей в течение 30 минут.
Первый тест
3300 пользователей — все хорошо:
Стручки:
kk -n eks-dev-1-eat-backend-ns top pod NAME CPU(cores) MEMORY(bytes) eat-backend-867b59c4dc-742vf 856m 325Mi eat-backend-867b59c4dc-bj74b 623m 316Mi eat-backend-867b59c4dc-cq5gd 891m 319Mi eat-backend-867b59c4dc-mm2ll 600m 310Mi eat-ackend-867b59c4dc-x8b8d 679m 313Mi eat-backend-memcached-0 19m 68Mi
HPA:
$ kk -n eks-dev-1-eat-backend-ns get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE eat-backend-hpa Deployment/eat-backend 30%/30% 4 40 5 20h
На 7.000 пользователей мы получили новые ошибки — « php_network_getAddresses: getAddrinfo не удалось » — мои старые «друзья», столкнулись с на aws пару раз:
[2020–08–21 14:14:59] local.ERROR: SQLSTATE[HY000] [2002] php\_network\_getaddresses: getaddrinfo failed: Try again (SQL: insert into `order_logs` (`order_id`, `action`, `data`, `updated_at`, `created_at`) values (175951, nav, "Result page: ok", 2020–08–21 14:14:54, 2020–08–21 14:14:54)) {"exception":"[object] (Illuminate\\Database\\QueryException(code: 2002): SQLSTATE[HY000] [2002] php\_network\_getaddresses: getaddrinfo failed: Try again (SQL: insert into `order_logs` (`order_id`, `action`, `data`, `updated_at`, `created_at`) values (175951, nav, \"Result page: ok\", 2020–08–21 14:14:54, 2020–08–21 14:14:54))
Короче говоря — « php_network_getaddresses: hetAddrinfo failed » ошибка в AWS может произойти на три (по крайней мере, известные мной) причины:
- Слишком много пакетов в секунду на сетевом интерфейсе AWS EC2, см. Пакеты EC2 в секунду: гарантированная пропускная способность против наилучших усилий
- Пропускная способность сети исчерпана — см. EC2 Сетевая производительность Cheat лист
- Для многих DNS-запросов отправляются в AWS VPC DNS-предел — 1024/секунду, см. ДНС квоты
Мы будем говорить о причине в нашем текущем случае немного позже в этом посте.
На 9 000+ PODS начал перезапустить:
$ kk -n eks-dev-1-eat-backend-ns get pod NAME READY STATUS RESTARTS AGE eat-backend-867b59c4dc-2m7fd 0/1 Running 2 4m17s eat-backend-867b59c4dc-742vf 0/1 CrashLoopBackOff 5 68m eat-backend-867b59c4dc-bj74b 1/1 Running 5 68m … eat-backend-867b59c4dc-w24pz 0/1 CrashLoopBackOff 5 19m eat-backend-867b59c4dc-x8b8d 0/1 CrashLoopBackOff 5 68m eat-backend-memcached-0 1/1 Running 0 21h
Потому что они наклонились ответы на Livy и готовность проверки:
0s Warning Unhealthy Pod Readiness probe failed: Get [http://10.3.62.195:80/readiness:](http://10.3.62.195:80/readiness:) net/http: request canceled (Client.Timeout exceeded while awaiting headers) 0s Warning Unhealthy Pod Liveness probe failed: Get [http://10.3.56.206:80/healthz:](http://10.3.56.206:80/healthz:) net/http: request canceled (Client.Timeout exceeded while awaiting headers)
А после 10 000 наших серверов базы данных начал отказываться от подключений:
[2020–08–21 13:05:11] production.ERROR: SQLSTATE[HY000] [2002] Connection refused {"exception":"[object] (Doctrine\\DBAL\\Driver\\PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused at /var/www/new-eat-backend/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:31, PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused
php_network_getaddresses: getAddrinfo не удалось и DNS
Итак, какие проблемы мы нашли на этот раз:
- Ошибка: sqlstate [y000] [2002] Соединение отказано
- php_network_getaddresses: hetAddrinfo не удалось
«Ошибка« »: SQLState [y000] [2002] Соединение отказалось от » — это известная проблема, и мы знаем, как иметь дело — я обновит экземпляр RDS из T3.Medium. к R5.large , но как насчет вопроса DNS?
Поскольку по причинам, упомянутых выше — пакеты в секунду на сетевом интерфейсе, пропускной способности сетевой ссылки и AWS VPC DNS, самым жизнеспособным, кажется, является сервис DNS: каждый раз, когда наша приложение хочет подключиться к серверу базы данных — это делает DNS-запрос для определения IP-сервера DB, а также все другие записи DNS и вместе они могут заполнить запросы 1024 в секунду.
Кстати, посмотрите на Графана: Loki — прометеузные счетчики logql, функции агрегации и диаграммы запросов DNSMAMSQ сообщение.
Давайте проверим настройки DNS наших стручков сейчас:
bash-4.4# cat /etc/resolv.conf nameserver 172.20.0.10 search eks-dev-1-eat-backend-ns.svc.cluster.local svc.cluster.local cluster.local us-east-2.compute.internal options ndots:5
ИНТЕРЕРВЕРС 172.20.0.10 — Должно быть наш Kube-DNS
:
bash-4.4# nslookup 172.20.0.10 10.0.20.172.in-addr.arpa name = kube-dns.kube-system.svc.cluster.local.
Да это так.
И кстати, он сказал нам в ИТ-ложках, что он не может подключиться к API-серверу:
E0805 21: 32: 40.283128 1 Reflector.go: 283] PKG/MOD/K8S.IO/ Client-go@v0.0.0 -20190620085101-78D20085101-78D2AF792BAB/Tools/Cache/Reflector.go: 98: не удалось посмотреть * V1.Namepace: Get https://172.20.0.1:443/api/v1/namepaces?Resourceversion=23502628&timeout=9m40s&timeoutseconds=580&watch=true: Наберите TCP 172.20.0.1:443: Connect: Connection отказался
Итак, что мы можем сделать, чтобы предотвратить чрезмерное использование AWS VPC DNS?
- Разорвать
dnsmasq
? Для Kubernetes, кажется, немного странно, сначала — потому что kubernetes уже есть свои DNS, а во-вторых — я уверен, что мы не самые первые, кто столкнулся с этим вопросом, и я сомневаюсь, что они решили его с помощью дополнительного контейнера сdnsmasq
(Тем не менее — проверьте dnsmasq: aws — «Временная ошибка в разрешении имени», logs, debug и dnsmasq кэш-размер ) - Другое решение может быть использовано DNS от CloudFlare ( 1.1.1.1 ) или Google ( 8.8.8.8) — Тогда мы остановлюсь использовать VPC DNS вообще, но приведут увеличение времени отклика DNS
Кубернаны dnspolicy.
Хорошо, давайте посмотрим, как DNS настроен в Kubernetes в целом:
Примечание: Вы можете управлять конфигурацией DNS вашего POD с Dnspolicy поле в спецификации стручки. Если это поле не заполнено, то ClusterFirst Политика DNS используется по умолчанию.
Итак, по умолчанию для стручек ClusterFirst
установлен, который:
Любой запрос DNS, который не соответствует настроенному суффиксу домена кластера, таких как «www.kubernetes.io», пересылается на вышестоящий имен, унаследованный от узла.
И, очевидно, AWS EC2 по умолчанию будет использовать именно AWS VPC DNS.
Смотрите также — Как устранить неполадки DNS сбои с Amazon EKS?
Узлы DNS могут быть настроены с помощью настроек кластераутоскалеров:
$ kk -n kube-system get pod cluster-autoscaler-5dddc9c9b-fstft -o yaml … spec: containers: - command: - ./cluster-autoscaler - — v=4 - — stderrthreshold=info - — cloud-provider=aws - — skip-nodes-with-local-storage=false - — expander=least-waste - — node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/bttrm-eks-dev-1 - — balance-similar-node-groups - — skip-nodes-with-system-pods=false …
Но в нашем случае здесь ничто не было изменено, все осталось со своими настройками по умолчанию.
Запуск DNS NODELOCAL в Куберате
Но идея с dnsmasq
Был правильным, но для Кубератесов есть Odelocal dns Решение, которое является именно той же службой кэширования, что и DNSMASQ, но он будет использовать Kube-DNS
захватить записи, а Kube-DNS
пойдем в VPC DNS позже.
Что нам нужно, чтобы запустить его:
- Kubedns : займет kubectl Get SVC Kube-DNS -N Kube-System -o jsonpath = {. SPEC.CLUSTERIP} команда
- Домен : Является ли наше, Cluster.local
- localdns : адрес, где будет доступно локальный кэш DNS-кэш, давайте использовать 169.254.20.10
Получить Kube-DNS
Сервис IP:
$ kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP} 172.20.0.10
Смотрите также Фиксация EKS DNS Отказ
Скачать . odelocaldns.yaml файл:
$ wget [https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml](https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml)
Обновите его с помощью SED и установленные данные, которые мы определяли выше:
$ sed -i "s/\_\_PILLAR\_\_LOCAL\_\_DNS\_\_/169.254.20.10/g; s/\_\_PILLAR\_\_DNS\_\_DOMAIN\_\_/cluster.local/g; s/\_\_PILLAR\_\_DNS\_\_SERVER\_\_/172.20.0.10/g" nodelocaldns.yaml
Проверьте содержание манифеста — что это сделает — здесь kubernetes Daemonset
Будет создан, что раскрутит стручки с DNS NODELOCAL на каждом доменоде Kubernetes:
... --- apiVersion: apps/v1 kind: DaemonSet metadata: name: node-local-dns ...
И его Configmap
:
... --- apiVersion: v1 kind: ConfigMap metadata: name: node-local-dns namespace: kube-system labels: addonmanager.kubernetes.io/mode: Reconcile data: Corefile: | cluster.local:53 { errors cache { success 9984 30 denial 9984 5 } reload loop bind 169.254.20.10 172.20.0.10 forward . \_\_PILLAR\_\_CLUSTER\_\_DNS\_\_ { force\_tcp } prometheus :9253 health 169.254.20.10:8080 } ...
Развернуть это:
$ kubectl apply -f nodelocaldns.yaml serviceaccount/node-local-dns created service/kube-dns-upstream created configmap/node-local-dns created daemonset.apps/node-local-dns created
Проверьте стручки:
$ kk -n kube-system get pod | grep local-dns node-local-dns-7cndv 1/1 Running 0 33s node-local-dns-7hrlc 1/1 Running 0 33s node-local-dns-c5bhm 1/1 Running 0 33s
Его обслуживание:
$ kk -n kube-system get svc | grep dns kube-dns ClusterIP 172.20.0.1053/UDP,53/TCP 88d kube-dns-upstream ClusterIP 172.20.245.211 53/UDP,53/TCP 107s
Kube-DNS-Upstream Clusterip 172.20.245.21 , но из наших стручков он должен быть доступен по 169.254.20.10 IP, как мы устанавливаем в localdns
Отказ
Это работает? Перейти к чеку из стручка:
bash-4.4# dig @169.254.20.10 ya.ru +short 87.250.250.242
Ага , работает, хорошо.
Следующая вещь, чтобы переконфигурировать наши стручки, чтобы они использовали 169.254.20.10 вместо Kube-DNS
Оказание услуг.
В Экктл
Файл конфигурации это можно сделать с помощью Clusterdns
:
... nodeGroups: - name: mygroup clusterDNS: 169.254.20.10 ...
Но тогда вам нужно обновить (на самом деле — воссоздать) ваши существующие рабочие узлы.
Kubernetes Pod dnsconfig
&& именные серверы
Чтобы применить изменения без создания групп на рабочихернах — мы можем указать необходимые настройки DNS в нашем развертывании, добавив dnsconfig
и именные серверы
:
... resources: requests: cpu: 2500m memory: 500m terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsConfig: nameservers: - 169.254.20.10 dnsPolicy: None imagePullSecrets: - name: gitlab-secret nodeSelector: beta.kubernetes.io/instance-type: c5.xlarge role: eat-workers ...
Развертывание, проверка:
$ kk -n eks-dev-1-eat-backend-ns exec -ti eat-backend-f7b49b4b7–4jtk5 cat /etc/resolv.conf nameserver 169.254.20.10
Хорошо…
Это работает?
Давайте проверим с копать от стручка:
$ kk -n eks-dev-1-eat-backend-ns exec -ti eat-backend-f7b49b4b7–4jtk5 dig ya.ru +short 87.250.250.242
Да, все хорошо.
Теперь мы можем выполнить второй тест.
Результаты первого теста были следующими:
Когда у нас есть ошибки после 8.000 пользователей.
Второй тест
8500 — все хорошо до сих пор:
На предыдущем тесте мы начали получать ошибки после 7.000 — около 150-200 ошибок, а в это время только 5 ошибок.
Статус Pods:
$ kk -n eks-dev-1-eat-backend-ns get pod NAME READY STATUS RESTARTS AGE eat-backend-5d8984656–2ftd6 1/1 Running 0 17m eat-backend-5d8984656–45xvk 1/1 Running 0 9m11s eat-backend-5d8984656–6v6zr 1/1 Running 0 5m10s … eat-backend-5d8984656-th2h6 1/1 Running 0 37m eat-backend-memcached-0 1/1 Running 0 24h
НРА:
$ kk -n eks-dev-1-eat-backend-ns get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE eat-backend-hpa Deployment/eat-backend 32%/30% 4 40 13 24h
10.000 — все еще хорошо:
НРА:
$ kk -n eks-dev-1-eat-backend-ns get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE eat-backend-hpa Deployment/eat-backend 30%/30% 4 40 15 24h
Стручки:
$ kk -n eks-dev-1-eat-backend-ns get pod NAME READY STATUS RESTARTS AGE eat-backend-5d8984656–2ftd6 1/1 Running 0 28m eat — backend-5d8984656–45xvk 1/1 Running 0 20m eat-backend-5d8984656–6v6zr 1/1 Running 0 16m … eat-backend-5d8984656-th2h6 1/1 Running 0 48m eat-backend-5d8984656-z2tpp 1/1 Running 0 3m51s eat-backend-memcached-0 1/1 Running 0 24h
Подключается к серверу базы данных:
Узлы:
$ kk top node -l role=eat-workers NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% ip-10–3–39–145.us-east-2.compute.internal 743m 18% 1418Mi 24% ip-10–3–44–14.us-east-2.compute.internal 822m 20% 1327Mi 23% … ip-10–3–62–143.us-east-2.compute.internal 652m 16% 1259Mi 21% ip-10–3–63–96.us-east-2.compute.internal 664m 16% 1266Mi 22% ip-10–3–63–186.us-east-2.compute.internalip-10–3–58–180.us-east-2.compute.internal … ip-10–3–51–254.us-east-2.compute.internal
Автоскалинг все еще работает, все хорошо:
В 17:45 было время отклика, а пару ошибок — но потом все пошло нормально.
Нет Pods перезагрузится:
$ kk -n eks-dev-1-eat-backend-ns get pod NAME READY STATUS RESTARTS AGE eat-backend-5d8984656–2ftd6 1/1 Running 0 44m eat-backend-5d8984656–45xvk 1/1 Running 0 36m eat-backend-5d8984656–47vp9 1/1 Running 0 6m49s eat-backend-5d8984656–6v6zr 1/1 Running 0 32m eat-backend-5d8984656–78tq9 1/1 Running 0 2m45s … eat-backend-5d8984656-th2h6 1/1 Running 0 64m eat-backend-5d8984656-vbzhr 1/1 Running 0 6m49s eat-backend-5d8984656-xzv6n 1/1 Running 0 6m49s eat-backend-5d8984656-z2tpp 1/1 Running 0 20m eat-backend-5d8984656-zfrb7 1/1 Running 0 16m eat-backend-memcached-0 1/1 Running 0 24h
30 стручек были расширены:
$ kk -n eks-dev-1-eat-backend-ns get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE eat-backend-hpa Deployment/eat-backend 1%/30% 4 40 30 24h
0% ошибок:
Apache jmeter è grafana
Наконец, я впервые увидел такое решение, и это выглядит действительно хорошо — команда QA сделала свой JMeter CTO прислать результаты тестирования в IncoluxDB, а затем Grafana использует его, чтобы нарисовать графики:
Первоначально опубликовано в RTFM: Linux, DevOps и системное управление Отказ
Оригинал: «https://dev.to/setevoy/kubernetes-load-testing-and-high-load-tuning-problems-and-solutions-2o45»