Как ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ свой автоскСйлСр для кластСра

ΠŸΡ€ΠΈΠ²Π΅Ρ‚! ΠœΡ‹ ΠΎΠ±ΡƒΡ‡Π°Π΅ΠΌ людСй Ρ€Π°Π±ΠΎΡ‚Π΅ с большими Π΄Π°Π½Π½Ρ‹ΠΌΠΈ. НСвозмоТно сСбС ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΏΠΎ большим Π΄Π°Π½Π½Ρ‹ΠΌ Π±Π΅Π· своСго кластСра, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ всС участники совмСстно Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚. По этой ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π΅ Π½Π° нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ ΠΎΠ½ всСгда Π΅ΡΡ‚ΡŒ πŸ™‚ ΠœΡ‹ занимаСмся Π΅Π³ΠΎ настройкой, Ρ‚ΡŽΠ½ΠΈΠ½Π³ΠΎΠΌ ΠΈ администрированиСм, Π° рСбята нСпосрСдствСнно Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽΡ‚ Ρ‚Π°ΠΌ MapReduce-Π΄ΠΆΠΎΠ±Ρ‹ ΠΈ ΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Spark’ΠΎΠΌ.

Π’ этом постС ΠΌΡ‹ расскаТСм, ΠΊΠ°ΠΊ ΠΌΡ‹ Ρ€Π΅ΡˆΠ°Π»ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ Π½Π΅Ρ€Π°Π²Π½ΠΎΠΌΠ΅Ρ€Π½ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ кластСра, написав свой автоскСйлСр, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΎΠ±Π»Π°ΠΊΠΎ Mail.ru Cloud Solutions.

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΠ°

ΠšΠ»Π°ΡΡ‚Π΅Ρ€ Ρƒ нас ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π½Π΅ совсСм Π² Ρ‚ΠΈΠΏΠΈΡ‡Π½ΠΎΠΌ Ρ€Π΅ΠΆΠΈΠΌΠ΅. Утилизация сильно нСравномСрная. НапримСр, Π΅ΡΡ‚ΡŒ практичСскиС занятия, ΠΊΠΎΠ³Π΄Π° всС 30 Ρ‡Π΅Π»ΠΎΠ²Π΅ΠΊ ΠΈ ΠΏΡ€Π΅ΠΏΠΎΠ΄Π°Π²Π°Ρ‚Π΅Π»ΡŒ заходят Π½Π° кластСр ΠΈ Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‚ ΠΈΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ. Или ΠΎΠΏΡΡ‚ΡŒ ΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π΄Π½ΠΈ ΠΏΠ΅Ρ€Π΅Π΄ Π΄Π΅Π΄Π»Π°ΠΉΠ½ΠΎΠΌ, ΠΊΠΎΠ³Π΄Π° Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° сильно возрастаСт. Π’ΠΎ всС ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠ΅ врСмя кластСр Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Π½Π΅Π΄ΠΎΠ·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ.

РСшСниС β„–1 – это Π΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ кластСр, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ ΠΏΠΈΠΊΠΎΠ²Ρ‹Π΅ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ, Π½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΡΡ‚Π°ΠΈΠ²Π°Ρ‚ΡŒ Π²ΠΎ всС ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠ΅ врСмя.

РСшСниС β„–2 – это Π΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ нСбольшой кластСр, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π½ΠΎΠ΄Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄ занятиями ΠΈ Π²ΠΎ врСмя ΠΏΠΈΠΊΠΎΠ²Ρ‹Ρ… Π½Π°Π³Ρ€ΡƒΠ·ΠΎΠΊ.

РСшСниС β„–3 – это Π΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ нСбольшой кластСр ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ автоскСйлСр, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ Π·Π° Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΎΠΉ кластСра ΠΈ сам, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ API, Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΠΈ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ Π½ΠΎΠ΄Ρ‹ ΠΈΠ· кластСра.

Π’ этом постС ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠΈ β„–3. Π’Π°ΠΊΠΎΠΉ автоскСйлСр сильно зависит ΠΎΡ‚ Π²Π½Π΅ΡˆΠ½ΠΈΡ… Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΎΠ², Π° Π½Π΅ ΠΎΡ‚ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΡ…, ΠΈ ΠΏΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€Ρ‹ Π΅Π³ΠΎ часто Π½Π΅ ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚. ΠœΡ‹ ΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ ΠΎΠ±Π»Π°Ρ‡Π½ΠΎΠΉ инфраструктурой Mail.ru Cloud Solutions ΠΈ написали автоскСйлСр, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ API MCS. А Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΎΠ±ΡƒΡ‡Π°Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Π΅ с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ, Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹ΠΉ автоскСйлСр для своих Ρ†Π΅Π»Π΅ΠΉ ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ со своим ΠΎΠ±Π»Π°ΠΊΠΎΠΌ

Prerequisites

Π’ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, Ρƒ вас Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ Hadoop-кластСр. ΠœΡ‹, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ дистрибутивом HDP.

Π§Ρ‚ΠΎΠ±Ρ‹ Ρƒ вас Π½ΠΎΠ΄Ρ‹ ΠΌΠΎΠ³Π»ΠΈ быстро Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒΡΡ ΠΈ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒΡΡ, Ρƒ вас Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ΅ распрСдСлСниС Ρ€ΠΎΠ»Π΅ΠΉ ΠΏΠΎ Π½ΠΎΠ΄Π°ΠΌ.

  1. ΠœΠ°ΡΡ‚Π΅Ρ€-Π½ΠΎΠ΄Π°. Ну Ρ‚ΡƒΡ‚ ΠΏΠΎΡΡΠ½ΡΡ‚ΡŒ Π½ΠΈΡ‡Π΅Π³ΠΎ особСнно Π½Π΅ Π½Π°Π΄ΠΎ: главная Π½ΠΎΠ΄Π° кластСра, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ запускаСтся, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€ Spark’Π°, Ссли Π²Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ΡΡŒ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌ Ρ€Π΅ΠΆΠΈΠΌΠΎΠΌ.
  2. Π”Π°Ρ‚Π°-Π½ΠΎΠ΄Π°. Π­Ρ‚ΠΎ Π½ΠΎΠ΄Π°, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Ρƒ вас хранятся Π΄Π°Π½Π½Ρ‹Π΅ Π½Π° HDFS ΠΈ Π½Π° Π½Π΅ΠΉ ΠΆΠ΅ происходят вычислСния.
  3. Π’Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ Π½ΠΎΠ΄Π°. Π­Ρ‚ΠΎ Π½ΠΎΠ΄Π°, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Ρƒ вас Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ хранится Π½Π° HDFS, Π½ΠΎ Π½Π° Π½Π΅ΠΉ происходят вычислСния.

Π’Π°ΠΆΠ½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚. АвтоскСйлинг Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π·Π° счСт Π½ΠΎΠ΄ Ρ‚Ρ€Π΅Ρ‚ΡŒΠ΅Π³ΠΎ Ρ‚ΠΈΠΏΠ°. Если Π²Ρ‹ Π½Π°Ρ‡Π½Π΅Ρ‚Π΅ Π·Π°Π±ΠΈΡ€Π°Ρ‚ΡŒ ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π½ΠΎΠ΄Ρ‹ Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°, Ρ‚ΠΎ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ рСагирования Π±ΡƒΠ΄Π΅Ρ‚ сильно Π½ΠΈΠ·ΠΊΠΎΠΉ – дСкомишСн ΠΈ Ρ€Π΅ΠΊΠΎΠΌΠΈΡˆΠ΅Π½ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π½ΠΈΠΌΠ°Ρ‚ΡŒ часы Π½Π° вашСм кластСрС. Π­Ρ‚ΠΎ, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π½Π΅ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ оТидаСшь ΠΎΡ‚ автоскСйлинга. Π’ΠΎ Π΅ΡΡ‚ΡŒ Π½ΠΎΠ΄Ρ‹ ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΈ Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° ΠΌΡ‹ Π½Π΅ Ρ‚Ρ€ΠΎΠ³Π°Π΅ΠΌ. Они Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ собой минимально ТизнСспособный кластСр, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° протяТСнии всСго дСйствия ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹.

Π˜Ρ‚Π°ΠΊ, наш автоскСйлСр написан Π½Π° Python 3, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ambari API для управлСния сСрвисами кластСра, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ API ΠΎΡ‚ Mail.ru Cloud Solutions (MCS) для запуска ΠΈ остановки машин.

АрхитСктура Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ

  1. ΠœΠΎΠ΄ΡƒΠ»ΡŒ autoscaler.py. Π’ Π½Π΅ΠΌ прописаны Ρ‚Ρ€ΠΈ класса: 1) Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Ambari, 2) Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с MCS, 3) Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, связанныС нСпосрСдствСнно с Π»ΠΎΠ³ΠΈΠΊΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚Ρ‹ автоскСйлСра.
  2. Π‘ΠΊΡ€ΠΈΠΏΡ‚ observer.py. По сути состоит ΠΈΠ· Ρ€Π°Π·Π½Ρ‹Ρ… ΠΏΡ€Π°Π²ΠΈΠ»: ΠΊΠΎΠ³Π΄Π° ΠΈ Π² ΠΊΠ°ΠΊΠΈΠ΅ ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρ‹ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ автоскСйлСра.
  3. Π€Π°ΠΉΠ» с ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΌΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ config.py. Π’Π°ΠΌ содСрТится, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, список Π½ΠΎΠ΄, Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½Π½Ρ‹Ρ… для автоскСйлинга ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, Π²Π»ΠΈΡΡŽΡ‰ΠΈΠ΅, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π½Π° Ρ‚ΠΎ, сколько Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΏΠΎΠ΄ΠΎΠΆΠ΄Π°Ρ‚ΡŒ с Ρ‚ΠΎΠ³ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°, ΠΊΠΎΠ³Π΄Π° Π±Ρ‹Π»Π° Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π° новая Π½ΠΎΠ΄Π°. Π’Π°ΠΌ ΠΆΠ΅ находятся Π΅Ρ‰Π΅ ΠΈ таймстСмпы Π½Π°Ρ‡Π°Π»Π° занятий, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄ занятиСм Π±Ρ‹Π»Π° Π·Π°ΠΏΡƒΡ‰Π΅Π½Π° максимальная Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½Π½Π°Ρ конфигурация кластСра.

Π”Π°Π²Π°ΠΉΡ‚Π΅ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ посмотрим Π½Π° куски ΠΊΠΎΠ΄Π°, находящиСся Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΠ΅Ρ€Π²Ρ‹Ρ… Π΄Π²ΡƒΡ… Ρ„Π°ΠΉΠ»ΠΎΠ².

1. ΠœΠΎΠ΄ΡƒΠ»ΡŒ autoscaler.py

Класс Ambari

Π’Π°ΠΊ выглядит кусочСк ΠΊΠΎΠ΄Π°, содСрТащий класс Ambari:

class Ambari:
    def __init__(self, ambari_url, cluster_name, headers, auth):
        self.ambari_url = ambari_url
        self.cluster_name = cluster_name
        self.headers = headers
        self.auth = auth

    def stop_all_services(self, hostname):
        url = self.ambari_url + self.cluster_name + '/hosts/' + hostname + '/host_components/'
        url2 = self.ambari_url + self.cluster_name + '/hosts/' + hostname
        req0 = requests.get(url2, headers=self.headers, auth=self.auth)
        services = req0.json()['host_components']
        services_list = list(map(lambda x: x['HostRoles']['component_name'], services))
        data = {
            "RequestInfo": {
                "context":"Stop All Host Components",
                "operation_level": {
                    "level":"HOST",
                    "cluster_name": self.cluster_name,
                    "host_names": hostname
                },
                "query":"HostRoles/component_name.in({0})".format(",".join(services_list))
            },
            "Body": {
                "HostRoles": {
                    "state":"INSTALLED"
                }
            }
        }
        req = requests.put(url, data=json.dumps(data), headers=self.headers, auth=self.auth)
        if req.status_code in [200, 201, 202]:
            message = 'Request accepted'
        else:
            message = req.status_code
        return message

Π’Ρ‹ΡˆΠ΅ для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ stop_all_services, которая останавливаСт всС сСрвисы Π½Π° Π½ΡƒΠΆΠ½ΠΎΠΉ Π½ΠΎΠ΄Π΅ кластСра.

На Π²Ρ…ΠΎΠ΄ классу Ambari Π²Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚Π΅:

  • ambari_url, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π²ΠΈΠ΄Π° 'http://localhost:8080/api/v1/clusters/',
  • cluster_name – Π½Π°Π·Π²Π°Π½ΠΈΠ΅ вашСго кластСра Π² Ambari,
  • headers = {'X-Requested-By': 'ambari'}
  • ΠΈ Π²Π½ΡƒΡ‚Ρ€ΠΈ auth Π»Π΅ΠΆΠΈΡ‚ ваш Π»ΠΎΠ³ΠΈΠ½ ΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ ΠΎΡ‚ Ambari: auth = ('login', 'password').

Π‘Π°ΠΌΠ° функция прСдставляСт ΠΈΠ· сСбя Π½Π΅ Π±ΠΎΠ»Π΅Π΅ Ρ‡Π΅ΠΌ ΠΏΠ°Ρ€ΠΎΡ‡ΠΊΡƒ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΉ Ρ‡Π΅Ρ€Π΅Π· REST API ΠΊ Ambari. Π‘ Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния Π»ΠΎΠ³ΠΈΠΊΠΈ ΠΌΡ‹ Π²Π½Π°Ρ‡Π°Π»Π΅ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ список Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½Ρ‹Ρ… сСрвисов Π½Π° Π½ΠΎΠ΄Π΅, Π° Π·Π°Ρ‚Π΅ΠΌ просим Π½Π° Π΄Π°Π½Π½ΠΎΠΌ кластСрС, Π½Π° Π΄Π°Π½Π½ΠΎΠΉ Π½ΠΎΠ΄Π΅ пСрСвСсти сСрвисы ΠΈΠ· списка Π² состояниС INSTALLED. Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠΎ запуску всС сСрвисов, ΠΏΠΎ ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Ρƒ Π½ΠΎΠ΄ Π² состояниС Maintenance ΠΈ Π΄Ρ€. выглядят ΠΏΠΎΡ…ΠΎΠΆΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ – это просто нСсколько запросов Ρ‡Π΅Ρ€Π΅Π· API.

Класс Mcs

Π’Π°ΠΊ выглядит кусочСк ΠΊΠΎΠ΄Π°, содСрТащий класс Mcs:

class Mcs:
    def __init__(self, id1, id2, password):
        self.id1 = id1
        self.id2 = id2
        self.password = password
        self.mcs_host = 'https://infra.mail.ru:8774/v2.1'

    def vm_turn_on(self, hostname):
        self.token = self.get_mcs_token()
        host = self.hostname_to_vmname(hostname)
        vm_id = self.get_vm_id(host)
        mcs_url1 = self.mcs_host + '/servers/' + self.vm_id + '/action'
        headers = {
            'X-Auth-Token': '{0}'.format(self.token),
            'Content-Type': 'application/json'
        }
        data = {'os-start' : 'null'}
        mcs = requests.post(mcs_url1, data=json.dumps(data), headers=headers)
        return mcs.status_code

На Π²Ρ…ΠΎΠ΄ классу Mcs ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ id ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠ±Π»Π°ΠΊΠ° ΠΈ id ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π΅Π³ΠΎ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ. Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ vm_turn_on ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠΎΠ΄Π½Ρƒ ΠΈΠ· машин. Π›ΠΎΠ³ΠΈΠΊΠ° здСсь Ρ‡ΡƒΡ‚ΡŒ слоТнСС. Π’ Π½Π°Ρ‡Π°Π»Π΅ ΠΊΠΎΠ΄Π° ΠΈΠ΄Π΅Ρ‚ Π²Ρ‹Π·ΠΎΠ² Ρ‚Ρ€Π΅Ρ… Π΄Ρ€ΡƒΠ³ΠΈΡ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ: 1) Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ‚ΠΎΠΊΠ΅Π½, 2) Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ hostname Π² Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΌΠ°ΡˆΠΈΠ½Ρ‹ Π² MCS, 3) ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ id этой ΠΌΠ°ΡˆΠΈΠ½Ρ‹. Π”Π°Π»Π΅Π΅ ΠΌΡ‹ Π΄Π΅Π»Π°Π΅ΠΌ просто post-запрос ΠΈ запускаСм эту ΠΌΠ°ΡˆΠΈΠ½Ρƒ.

Π’Π°ΠΊ выглядит сама функция ΠΏΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΡŽ Ρ‚ΠΎΠΊΠ΅Π½Π°:

def get_mcs_token(self):
        url = 'https://infra.mail.ru:35357/v3/auth/tokens?nocatalog'
        headers = {'Content-Type': 'application/json'}
        data = {
            'auth': {
                'identity': {
                    'methods': ['password'],
                    'password': {
                        'user': {
                            'id': self.id1,
                            'password': self.password
                        }
                    }
                },
                'scope': {
                    'project': {
                        'id': self.id2
                    }
                }
            }
        }
        params = (('nocatalog', ''),)
        req = requests.post(url, data=json.dumps(data), headers=headers, params=params)
        self.token = req.headers['X-Subject-Token']
        return self.token

Класс Autoscaler

Π’ этом классС содСрТатся Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, относящиСся ΠΊ самой Π»ΠΎΠ³ΠΈΠΊΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹.

Π’Π°ΠΊ выглядит кусок ΠΊΠΎΠ΄Π° этого класса:

class Autoscaler:
    def __init__(self, ambari, mcs, scaling_hosts, yarn_ram_per_node, yarn_cpu_per_node):
        self.scaling_hosts = scaling_hosts
        self.ambari = ambari
        self.mcs = mcs
        self.q_ram = deque()
        self.q_cpu = deque()
        self.num = 0
        self.yarn_ram_per_node = yarn_ram_per_node
        self.yarn_cpu_per_node = yarn_cpu_per_node

    def scale_down(self, hostname):
        flag1 = flag2 = flag3 = flag4 = flag5 = False
        if hostname in self.scaling_hosts:
            while True:
                time.sleep(5)
                status1 = self.ambari.decommission_nodemanager(hostname)
                if status1 == 'Request accepted' or status1 == 500:
                    flag1 = True
                    logging.info('Decomission request accepted: {0}'.format(flag1))
                    break
            while True:
                time.sleep(5)
                status3 = self.ambari.check_service(hostname, 'NODEMANAGER')
                if status3 == 'INSTALLED':
                    flag3 = True
                    logging.info('Nodemaneger decommissioned: {0}'.format(flag3))
                    break
            while True:
                time.sleep(5)
                status2 = self.ambari.maintenance_on(hostname)
                if status2 == 'Request accepted' or status2 == 500:
                    flag2 = True
                    logging.info('Maintenance request accepted: {0}'.format(flag2))
                    break
            while True:
                time.sleep(5)
                status4 = self.ambari.check_maintenance(hostname, 'NODEMANAGER')
                if status4 == 'ON' or status4 == 'IMPLIED_FROM_HOST':
                    flag4 = True
                    self.ambari.stop_all_services(hostname)
                    logging.info('Maintenance is on: {0}'.format(flag4))
                    logging.info('Stopping services')
                    break
            time.sleep(90)
            status5 = self.mcs.vm_turn_off(hostname)
            while True:
                time.sleep(5)
                status5 = self.mcs.get_vm_info(hostname)['server']['status']
                if status5 == 'SHUTOFF':
                    flag5 = True
                    logging.info('VM is turned off: {0}'.format(flag5))
                    break
            if flag1 and flag2 and flag3 and flag4 and flag5:
                message = 'Success'
                logging.info('Scale-down finished')
                logging.info('Cooldown period has started. Wait for several minutes')
        return message

На Π²Ρ…ΠΎΠ΄ ΠΌΡ‹ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅ΠΌ классы Ambari ΠΈ Mcs, список Π½ΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½Ρ‹ для скСйлинга, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π½ΠΎΠ΄: ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΈ cpu, Π²Ρ‹Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ Π½Π° Π½ΠΎΠ΄Ρƒ Π² YARN. Π’Π°ΠΊΠΆΠ΅ Π΅ΡΡ‚ΡŒ 2 Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΡ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° q_ram, q_cpu, ΡΠ²Π»ΡΡŽΡ‰ΠΈΡ…ΡΡ очСрСдями. ΠŸΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Π½ΠΈΡ… ΠΌΡ‹ Ρ…Ρ€Π°Π½ΠΈΠΌ значСния Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ кластСра. Если ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ послСдних 5 ΠΌΠΈΠ½ΡƒΡ‚ ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎ Π±Ρ‹Π»Π° ΠΏΠΎΠ²Ρ‹ΡˆΠ΅Π½Π½Π°Ρ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠ°, Ρ‚ΠΎ ΠΌΡ‹ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅ΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ +1 Π½ΠΎΠ΄Ρƒ Π² кластСр. Π’ΠΎ ΠΆΠ΅ самоС справСдливо ΠΈ для состояния Π½Π΅Π΄ΠΎΠ·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ кластСра.

Π’ ΠΊΠΎΠ΄Π΅ Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, которая удаляСт ΠΌΠ°ΡˆΠΈΠ½Ρƒ ΠΈΠ· кластСра ΠΈ останавливаСт Π΅Π΅ Π² ΠΎΠ±Π»Π°ΠΊΠ΅. Π’Π½Π°Ρ‡Π°Π»Π΅ происходит дСкомишСн YARN Nodemanager, дальшС Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Ρ€Π΅ΠΆΠΈΠΌ Maintenance, дальшС ΠΌΡ‹ останавливаСм всС сСрвисы Π½Π° машинС ΠΈ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ ΠΌΠ°ΡˆΠΈΠ½Ρƒ Π² ΠΎΠ±Π»Π°ΠΊΠ΅.

2. Π‘ΠΊΡ€ΠΈΠΏΡ‚ observer.py

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π° ΠΎΡ‚Ρ‚ΡƒΠ΄Π°:

if scaler.assert_up(config.scale_up_thresholds) == True:
        hostname = cloud.get_vm_to_up(config.scaling_hosts)
        if hostname != None:
            status1 = scaler.scale_up(hostname)
            if status1 == 'Success':
                text = {"text": "{0} has been successfully scaled-up".format(hostname)}
                post = {"text": "{0}".format(text)}
                json_data = json.dumps(post)
                req = requests.post(webhook, data=json_data.encode('ascii'), headers={'Content-Type': 'application/json'})
                time.sleep(config.cooldown_period*60)

Π’ Π½Π΅ΠΌ ΠΌΡ‹ провСряСм, слоТились Π»ΠΈ условия для увСличСния мощностСй кластСра ΠΈ Π΅ΡΡ‚ΡŒ Π»ΠΈ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π² Ρ€Π΅Π·Π΅Ρ€Π²Π΅ ΠΌΠ°ΡˆΠΈΠ½Ρ‹, ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ хостнСйм ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· Π½ΠΈΡ…, добавляСм Π΅Π΅ Π² кластСр ΠΈ ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠ΅ΠΌ ΠΎΠ± этом сообщСниС Π² Slack нашСй ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹. ПослС Ρ‡Π΅Π³ΠΎ запускаСтся cooldown_period, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ добавляСм ΠΈ Π½Π΅ ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΈΠ· кластСра, Π° просто ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠΌ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ. Если ΠΎΠ½Π° ΡΡ‚Π°Π±ΠΈΠ»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π»Π°ΡΡŒ ΠΈ находится Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΡ€ΠΈΠ΄ΠΎΡ€Π° ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Ρ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ, Ρ‚ΠΎ ΠΌΡ‹ просто ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅ΠΌ ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³. Если ΠΆΠ΅ ΠΎΠ΄Π½ΠΎΠΉ Π½ΠΎΠ΄Ρ‹ Π½Π΅ Ρ…Π²Π°Ρ‚ΠΈΠ»ΠΎ, Ρ‚ΠΎ добавляСм Π΅Ρ‰Π΅ ΠΎΠ΄Π½Ρƒ.

Для случаСв ΠΊΠΎΠ³Π΄Π° Ρƒ нас Π²ΠΏΠ΅Ρ€Π΅Π΄ΠΈ занятиС, ΠΌΡ‹ ΡƒΠΆΠ΅ Π·Π½Π°Π΅ΠΌ навСрняка, Ρ‡Ρ‚ΠΎ ΠΎΠ΄Π½ΠΎΠΉ Π½ΠΎΠ΄Ρ‹ Π½Π΅ Ρ…Π²Π°Ρ‚ΠΈΡ‚, поэтому ΠΌΡ‹ сразу стартуСм всС свободныС Π½ΠΎΠ΄Ρ‹ ΠΈ Π΄Π΅Ρ€ΠΆΠΈΠΌ ΠΈΡ… Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌΠΈ Π΄ΠΎ ΠΊΠΎΠ½Ρ†Π° занятия. Π­Ρ‚ΠΎ происходит ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ списка таймстСмпов занятий.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

АвтоскСйлСр – это Ρ…ΠΎΡ€ΠΎΡˆΠ΅Π΅ ΠΈ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ для Ρ‚Π΅Ρ… случаСв, ΠΊΠΎΠ³Π΄Π° Ρƒ вас Π½Π°Π±Π»ΡŽΠ΄Π°Π΅Ρ‚ΡΡ нСравномСрная Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° кластСра. Π’Ρ‹ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π΄ΠΎΠ±ΠΈΠ²Π°Π΅Ρ‚Π΅ΡΡŒ Π½ΡƒΠΆΠ½ΠΎΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ кластСра ΠΏΠΎΠ΄ ΠΏΠΈΠΊΠΎΠ²Ρ‹Π΅ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΈ ΠΏΡ€ΠΈ этом Π½Π΅ Π΄Π΅Ρ€ΠΆΠΈΡ‚Π΅ этот кластСр Π²ΠΎ врСмя Π½Π΅Π΄ΠΎΠ·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ, экономя срСдства. Ну ΠΈ плюс это всС происходит Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎ Π±Π΅Π· вашСго участия. Π‘Π°ΠΌ автоскСйлСр – это Π½Π΅ Π±ΠΎΠ»Π΅Π΅, Ρ‡Π΅ΠΌ Π½Π°Π±ΠΎΡ€ запросов ΠΊ API кластСр-ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° ΠΈ API ΠΎΠ±Π»Π°Ρ‡Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€Π°, прописанных ΠΏΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ Π»ΠΎΠ³ΠΈΠΊΠ΅. О Ρ‡Π΅ΠΌ Ρ‚ΠΎΡ‡Π½ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ – это ΠΎ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠΈ Π½ΠΎΠ΄ Π½Π° 3 Ρ‚ΠΈΠΏΠ°, ΠΊΠ°ΠΊ ΠΌΡ‹ писали Ρ€Π°Π½Π΅Π΅. И Π±ΡƒΠ΄Π΅Ρ‚ Π²Π°ΠΌ ΡΡ‡Π°ΡΡ‚ΡŒΠ΅.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com