Як оптимізувати хмарну інфраструктуру: шлях DevOps-інженера від процесорів x86 до ARM (Graviton) архітектури

Усі статті, обговорення, новини про DevOps — в одному місці. Підписуйтеся на DOU | DevOps!

Галузь мікропроцесорів зазнає змін, відмовляючись від традиційного панування архітектури х86. ARM (Advanced RISC Machine) архітектура стає головним гравцем індустрії мікропроцесорів, уже завоювавши мобільний сектор, зробивши значний крок вперед завдяки Apple M SoC у ноутбуках, а також закріпивши свою присутність у серверній інфраструктурі Amazon через процесор Graviton3.

Amazon Web Services (AWS) розробила спеціальні процесори, відомі як Graviton, а також Graviton3, що є його сучасною ітерацією. Ці процесори були створені для хмарних ресурсів Amazon EC2 з метою підвищення їхньої продуктивності, енергоефективності та економічності. Розроблені на основі архітектури ARM, Graviton3 характеризується великою кількістю ядер, достатньою кеш-пам’яттю та одночасною підтримкою багатопотоковості. Інтегровані в систему AWS Nitro, процесори Graviton оптимізують загальну продуктивність системи, безпеку та керованість.

Ресурси на основі Graviton є доступними в різних модифікаціях, що задовольнять різноманітні вимоги до робочого навантаження. Завдяки потужній екосистемі та рентабельній ціні процесори Graviton стають прекрасною альтернативу традиційним процесорам x86 для хмарних робочих навантажень.

Планування

Після отримання завдання щодо міграції хмарної архітектури, першим етапом є обговорення задач з відділом розробки та оцінка сумісності коду продукту із запропонованими змінами архітектури. Нашим наступним кроком стало продовження дослідження інфраструктури проєкту для визначення тих елементів, які потребують змін, а також вивчення шляхів їхнього впровадження. Враховуючи те, що наша хмарна інфраструктура розгортається як код за допомогою Terraform, необхідно було вивчити всі нюанси та залежності.

Перш за все слід зосередитися на кластері EKS і групах вузлів, де в коді відбуваються всі розгортання та операції. Щоб уникнути переривання активних процесів розробки, дієвим підходом є створення окремої групи вузлів з архітектурою ARM і застосування до неї Taint.

workers = {
  min_capacity = 1
  max_capacity = 4
  desired_capacity = 3  
  instance_types = ["m6a.xlarge", "m5a.xlarge"]
  capacity_type  = "SPOT"
  disk_size      = 50
  k8s_labels = {
    "node.kubernetes.io/lifecycle" = "spot"
  }
}
graviton-workers = {
  min_capacity = 1
  max_capacity = 3
  desired_capacity = 2
  instance_types = ["m6g.large"]
  capacity_type  = "SPOT"
  disk_size      = 50
  taints = [
   {
     key    = "type"
     value  = "graviton-workers"
     effect = "NO_SCHEDULE"
   }
  ]
  k8s_labels = {
    "node.kubernetes.io/lifecycle" = "spot"
  }
}  

Набір типів групи вузлів х86 і ARM

Тут варто наголосити на важливості taints і olerations, а також селекторів вузлів (Nodeselectors) як ключових інструментів для розрізнення модулів між окремими архітектурами в хмарній інфраструктурі, зосередженій навколо кластера Kubernetes.

Це особливо важливо, коли компанії та розробники використовують різноманітні інструменти, і не всі з них підтримують архітектуру ARM. Ми розуміли це, тому наш наступний крок передбачав вибір тегів / версій Docker-образів для сумісності з різними ресурсами та подальше тестування продуктів з відкритим кодом, як-от Jenkins, Prometheus, Grafana, ArgoCD тощо. Останній етап у процесі планування полягав у визначенні можливостей і вимог щодо відповідності AWS CodeBuild, що давало можливість створювати та запускати тести образу Docker на архітектурі ARM.

Тестування

Імплементація технології Graviton і нової серверної архітектури робочих станцій на ранньому етапі викликало певні складнощі. Дослідження коду, особливо процесу створення програм на новій архітектурі, почалося з емуляції за допомогою buildx (docker buildx build -- platform linux/arm64...).

Основна проблема полягала в уповільненні швидкості виконання збірки через емуляцію іншої архітектури, що призвело до 2,5-кратного збільшення часу збірки порівняно зі стандартною архітектурою х86. Крім того, тестування образу після збірки на х86 для автоматизованої робочої станції з використанням емуляції зайняло в 3–4 рази більше часу, збільшивши очікуваний процес з 8–10 до 40–60 хвилин.

Стабільність машини для збирання стала критичною проблемою, оскільки збірки зависали на певних етапах, що призводило до зависання на невизначений термін. Тому необхідно було оперативно ухвалювати рішення щодо вирішення цих проблем.

Зважаючи на проблеми, описані вище, гарною ідеєю стало рішення запустити сервер збірки на примірнику Graviton EC2. Для первинного аналізу та тестування простіше використовувати окремі екземпляри, на яких можна створити код та одразу налаштувати збірку, передаючи зміни, наприклад, у файл Docker або бібліотеку, які використовує ваша програма, оскільки не всі бібліотеки й пакети стабільно працюють на ARM.

Після створення всіх необхідних образів Docker необхідно з’ясувати, де саме вони повинні розташовуватися та як розгорнути їх у тестовому середовищі. На цьому етапі потрібно підняти групу Graviton вузлів у кластері. У проєкті ми використовували Helm Chart для розгортання мікросервісів у кластері, але для інших типів розгортання основні дії будуть аналогічними. У файлі values.yaml helm потрібно розмістити nodeselector і tolerations. Там, де kubernetes.io/arch:arm64 є стандартною міткою, tolerations відповідатимуть тегу, який зображено на секції з кодом вище.

Ще один важливий момент полягає в тому, що вам доведеться комбінувати архітектури для використання в різних середовищах, тестах тощо. Для цього потрібно відрізняти назву образу ARM від х86. Найпростіший варіант — це додати -arm- або будь-яке інше слово до тегу образу, щоб воно відрізнялося від застарілих х86. Для цього ми можемо використовувати функцію regexMatch у Helmchart.

{{- if .Chart.AppVersion | regexMatch "-arm-" -}}
{{- with .Values.nodeSelector }}
nodeSelector:
  {{- toYaml . | nindent 8 }}
{{- else -}}
nodeSelector: {}
{{- end }}
{{- end }}
{{- if .Chart.AppVersion | regexMatch "-arm-" -}}
{{- with .Values.tolerations }}
tolerations:
  {{- toYaml . | nindent 8 }}
{{- else -}}
tolerations: []
{{- end }}
{{- end }}

Логіка розрізнення архітектур у Helm deployment.yaml

За допомогою цієї функції ми можемо контролювати, які tolearations і nodeselectors будуть записані під час розгортання. Якщо функція знайде -arm- у тезі образу, їй буде призначене значення, прописане у Values.yaml.

nodeSelector:
  kubernetes.io/arch: arm64
tolerations:
  - key: "type"
    value: "graviton-workers"
    operator: "Equal"
    effect: "NoSchedule"

Приклад значень nodeselector і tolerations в Helm values.yaml

У іншому разі буде прописане порожнє значення, що спрямовує розгортання до будь-якого вільного вузла. Така гнучкість дозволяє вам передавати будь-які значення, які ви вважаєте необхідними.

Не варто також забувати про інструменти, які використовуються під час міграції. Окрім допоміжних інструментів, в кожному проєкті будуть використовуватися бази даних.

Під час тестування наші бази даних продемонстрували надійну роботу. Мікросервіси на архітектурі ARM без проблем взаємодіють з базою даних на х86. Їх перенесення на нову архітектуру не є простим завданням, оскільки потрібно обов’язково зберігати всі дані. Проте якщо ви регулярно оновлюєте та використовуєте продукти від офіційних провайдерів, то проблем не буде. Лише перевірте, чи ваша версія образу підтримує архітектуру ARM. Якщо так, то вам слід додати nodeselector і tolerations у файлі значень Helm вашої бази даних і обов’язково зробити бекап перед міграцією. Якщо у вас застаріла або специфічна версія бази даних, яка не підтримує архітектуру ARM, тоді необхідно оновити версію бази даних та переконатися, що всі ваші застосунки працюють належно. Тільки після цього ви зможете переходити на архітектуру ARM.

Міграція

Після успішно проведеного локального тестування ви можете переходити до міграції на нове середовище. На цьому етапі вкрай важливо вибрати момент, коли розпочати міграцію. Якщо це проєкт, який постійно оновлюється (релізиться), зупинка такого процесу може спровокувати втрату значних коштів. Найкращим моментом тут буде етап циклу, коли код із середовища production переходить у stage, щоб QA-команда мала час його протестувати, а ви — внести відповідні виправлення. У нашому випадку інтеграція в CI/CD виглядала так: Dev repo > AWS CodeBuild > ECR & Helm repo > ArgoCD > EKS).

Першим кроком є передача оновлених файлів Docker із залежностями (наприклад, встановлення пакетів тощо) до репозиторіїв розробників, де розташований програмний код. Оскільки AWS CodeBuild використовується для створення образів Docker, вам потрібно внести зміни до buildspec файлу. Зверніть увагу, що команди для взаємодії з новим образом ARM aws/codebuild/amazonlinux2-aarch64-standard:3.0 відрізнятимуться від стандартного типу образу aws/codebuild/standard:5.0..

Крім того, щоб створити ці збірки за допомогою Terraform, вам доведеться оновлювати код. Щоб не повторювати цей код для створення кожної окремої збірки, варто використати Terragrunt, що дозволяє автоматизовано вставляти змінні.

inputs = {
  name                           = local.name
  aws_region                     = "us-east-1"
  codebuild_role_policy_arn      = dependency.infra.outputs.codebuild_role_policy_arn
  codebuild_vpc_id               = dependency.infra.outputs.vpc_id
  codebuild_subnet_ids           = dependency.infra.outputs.vpc_private_subnet_ids
  codebuild_security_group_ids   = [dependency.infra.outputs.codebuild_security_group_id]
  codebuild_source_location_name = local.name
  codebuild_environment_type     = "ARM_CONTAINER"
  codebuild_image_type           = "aws/codebuild/amazonlinux2-aarch64-standard:3.0"
}

Приклад змінних в Terragrunt

Після того, як ви успішно створили та налаштували ресурси в AWS CodeBuild, постає питання, як одночасно підтримувати розробку на новій та старій х86 архітектурі, яка все ще використовується в середовищах stage і production. Для цього варто зберегти застарілі збірки x86. В AWS CodeBuild можна скористатися зручною функцією — використання файлів buildspec для різних місць розташування. Ці файли можна брати як з репозиторію, так і з консолі AWS, інтегрувавши їх в конфігурації збірки.

Важливо залучити всі залежності образу для тестування збірки в новий файл buildspec. Це дозволить ефективно керувати збірками з єдиного репозиторію. Для цього потрібно додати умову if у специфікацію збірки для ARM. Ця умова буде застосовується лише тоді, коли буде зроблено коміт до гілки розробника. Водночас у застарілому файлі buildspec, який розташованій на консолі AWS, можна дозволити збірки з комітів, що надходять на stage і до основної гілки. Разом із розробкою, нова архітектура розширюватиметься на додаткові середовища. Умова if коригуватиметься, допоки остаточно не буде скасована, коли зникне потреба підтримувати середовище x86.

version: 0.2
env:
  shell: bash
phases:
  install:
    commands:
      - export BRANCH_NAME="${CODEBUILD_WEBHOOK_HEAD_REF:11:100}"
      - |
        if [[ "${BRANCH_NAME}" == hotfix/* || "${BRANCH_NAME}" == "stage"|| "${BRANCH_NAME}" == "main" ]]; then
          exit 1 
        fi

Блокування збірки на ARM в обраних гілках (buildspec.yaml)

Моніторинг і стабілізація

Моніторинг і стабілізація розгортання середовища Graviton вимагає ретельного підходу, зосередженого на розподілі ресурсів, оптимізації продуктивності та виявленні аномалій. Після процесу розгортання обов’язковим є розв’язання потенційних проблем, зокрема ризику уповільнення роботи модулів через неправильний розподіл ресурсів.

За умов реального навантаження також можуть виникати незначні проблеми, що потребують швидкого усунення. Щоб уміло контролювати продуктивність машин Graviton, рекомендуємо використовувати такі інструменти, як Amazon CloudWatch або Prometheus. Вони дозволяють здійснювати моніторинг у реальному часі, сприяючи швидкому реагуванню на будь-які порушення і відхилення в системі.

Важливим аспектом цього етапу є також точне налаштування параметрів ресурсів вузлів на робочій станції. Така оптимізація є ключовою для встановлення базової лінії, що забезпечуватиме стабільну та ефективну роботу програми. DevOps-інженерам та системним адміністраторам необхідно глибше занурюватися в деталі роботи центрального процесора та розподілу пам’яті і прагнути досягти оптимального балансу, який зменшить ризик уповільнення та ефективно використовуватиме доступні EC2-ресурси.

Amazon CloudWatch — це комплексна служба моніторингу, що дає змогу адміністраторам отримати цілісну картину використання ресурсів і дозволяє завчасно виявляти та усувати проблемні моменти. Використовуючи показники CloudWatch, користувачі можуть налаштувати сигнали сповіщення для випадків, коли попередньо визначені порогові значення перевищено.

Prometheus — ще один популярний набір інструментів для моніторингу та попередження з відкритим кодом, що вирізняється здатністю збирати та зберігати дані, забезпечуючи надійну основу для поглибленого аналізу. Його гнучкість дозволяє створювати спеціальні показники та запити, підвищуючи деталізацію моніторингу. У поєднанні з Grafana, Prometheus дозволяє створювати інтуїтивно зрозумілі інформаційні панелі, що оптимізує інтерпретацію великої кількості інформації про продуктивність системи.

У пошуках оптимальних налаштувань ресурсів адміністраторам варто проводити безперервне тестування продуктивності під змінним навантаженням. Такі інструменти, як Apache JMeter або K6, можуть симулювати різні робочі навантаження, визначаючи потенційні точки конфлікту ресурсів. Цей підхід до ітераційного тестування є важливим для уточнення параметрів розподілу ресурсів і завчасного усунення проблемних місць продуктивності.

Висновок

Перехід з архітектури x86 на ARM у хмарній інфраструктурі — це шлях трансформації, який вимагає ретельного планування, тестування та стратегічного підходу до міграції. Коли ми починаємо використовувати ARM-процесори, зокрема AWS Graviton3, вкрай важливим є застосування таких інструментів, як Terraform, Helm і AWS CodeBuild.

Інтеграція в наявні CI/CD, адаптація файлів buildspec і одночасне керування ARM і x86 збірками є ключовими компонентами успішної стратегії міграції. Використання функції if у buildspec забезпечує співіснування обох архітектур протягом перехідного періоду.

Після міграції основну увагу слід приділити моніторингу та стабілізації. Використання Amazon CloudWatch і Prometheus забезпечить отримання інформацію про використання ресурсів у режимі реального часу та дасть можливість адміністраторам оперативно вирішувати проблемні моменти і підтримувати оптимальну продуктивність. Безперервне тестування продуктивності за змінних навантажень має важливе значення для вдосконалення розподілу ресурсів і усунення потенційних конфліктів.

Загалом, архітектура ARM, особливо з процесорами AWS Graviton, є прекрасною альтернативою традиційним процесорам x86. Міграція, описана в цій статті, демонструє складнощі та нюанси такого переходу і наголошує на важливості стратегічного планування, тестування та ретельного моніторингу. Оскільки хмарні технології постійно розвиваються, адаптивність, продемонстрована DevOps-інженерами в моєму кейсі, стає основою для впровадження нових рішень і оптимізації продуктивності.

👍ПодобаєтьсяСподобалось6
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Той момент коли стаття не відповідає заголовку: де ж обіцяна оптимізація? Які профіти для компанії? А для спеціалістів? Що по грошах? Де порівняння перформанс x86 vs ARM... Як писав Митець «І знов двійка Носенко»
P.s. Взагалі читаючи це таке враження, що реально ніхто нічого не робив, так твір на задану тему 😅

Також хотів побачити якісь числа, бенчмарки, відсотки економії. Те, що я знаю — то Graviton дешевше, але його продуктивність залежить від задач. В середньому він відстає від Intel та AMD приблизно на стільки ж, на скільки дешевше і коштує. Як на мене, то по співвідношенню швидкість/ціна зараз найкраще AMD.

Так і то в тексті так ще плавно обійшли питання «стабільність додатків на ARM, які оригінально розробляються на х86»! І що по часу та грошам це коштує...

У нашому проекті нам пощастило використовувати мову програмування Python на бекенді, що призвело до відсутності проблем у цьому компоненті системи. Однак у фронтенд-додатках, розроблених на React, були внесені певні зміни, а саме заміни багатьох бібліотек на ті, які є сумісними з АРМ. Щодо продуктивності, ми не виявили суттєвого втрати швидкодії. Навпаки, мікросервіси тепер ефективніше використовують ресурси ЦП на близько 10-15%, що свідчить про їх оптимізацію. Важливо відзначити, що хоча споживання процесора зменшилося, спостерігається збільшення обсягу використовуваної пам’яті, а саме на 25-27%. Стосовно питання грошей, хоча наразі не можна точно визначити ефект на фінансовий аспект, але, враховуючи динаміку, можна припустити, що економія складе приблизно 6-8% у порівнянні з витратами минулого місяця.

Хм, цікаво, чому пам’ять збільшилася? В теорії, не повинно бути суттєвої різниці.
P.S. Дякую, що поділилися. Можливо зробите ще одну статтю вже по досягнутим результатам?

Вибачте за непорозуміння і враження від статті. Раджу розглянути додаткові ресурси для отримання більш детальної інформації про перформанс ARM в порівнянні з x86. Є багато джерел, де це питання розглядається більш глибоко та докладно. Одним із таких ресурсів може бути [redpanda.com/...​n-2-arm-vs-x86-comparison], або [filia-aleks.medium.com/...​-perfromance-3581aaef75d9], де обговорюється питання профітів для компаній і спеціалістів при використанні ARM, а також проведено порівняння перформансу з x86.

Долучаючи такі посилання, сподіваюся, що ви знайдете більше інформації, яка вас задовольнить щодо оптимізації та переваг використання ARM.

Ось ще бенчмарк Amazon Graviton3 vs. Intel Xeon vs. AMD EPYC, може кому цікаво буде: www.phoronix.com/...​eview/graviton3-amd-intel

Підписатись на коментарі