ΠΡΠΈΠ²Π΅Ρ! ΠΡ ΠΎΠ±ΡΡΠ°Π΅ΠΌ Π»ΡΠ΄Π΅ΠΉ ΡΠ°Π±ΠΎΡΠ΅ Ρ Π±ΠΎΠ»ΡΡΠΈΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ. ΠΠ΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΅Π±Π΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²ΠΈΡΡ ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°ΡΠ΅Π»ΡΠ½ΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ ΠΏΠΎ Π±ΠΎΠ»ΡΡΠΈΠΌ Π΄Π°Π½Π½ΡΠΌ Π±Π΅Π· ΡΠ²ΠΎΠ΅Π³ΠΎ ΠΊΠ»Π°ΡΡΠ΅ΡΠ°, Π½Π° ΠΊΠΎΡΠΎΡΠΎΠΌ Π²ΡΠ΅ ΡΡΠ°ΡΡΠ½ΠΈΠΊΠΈ ΡΠΎΠ²ΠΌΠ΅ΡΡΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ. ΠΠΎ ΡΡΠΎΠΉ ΠΏΡΠΈΡΠΈΠ½Π΅ Π½Π° Π½Π°ΡΠ΅ΠΉ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠ΅ ΠΎΠ½ Π²ΡΠ΅Π³Π΄Π° Π΅ΡΡΡ π ΠΡ Π·Π°Π½ΠΈΠΌΠ°Π΅ΠΌΡΡ Π΅Π³ΠΎ Π½Π°ΡΡΡΠΎΠΉΠΊΠΎΠΉ, ΡΡΠ½ΠΈΠ½Π³ΠΎΠΌ ΠΈ Π°Π΄ΠΌΠΈΠ½ΠΈΡΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ, Π° ΡΠ΅Π±ΡΡΠ° Π½Π΅ΠΏΠΎΡΡΠ΅Π΄ΡΡΠ²Π΅Π½Π½ΠΎ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ ΡΠ°ΠΌ MapReduce-Π΄ΠΆΠΎΠ±Ρ ΠΈ ΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ Spark’ΠΎΠΌ.
Π ΡΡΠΎΠΌ ΠΏΠΎΡΡΠ΅ ΠΌΡ ΡΠ°ΡΡΠΊΠ°ΠΆΠ΅ΠΌ, ΠΊΠ°ΠΊ ΠΌΡ ΡΠ΅ΡΠ°Π»ΠΈ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ Π½Π΅ΡΠ°Π²Π½ΠΎΠΌΠ΅ΡΠ½ΠΎΠΉ Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΠΊΠ»Π°ΡΡΠ΅ΡΠ°, Π½Π°ΠΏΠΈΡΠ°Π² ΡΠ²ΠΎΠΉ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅Ρ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ ΠΎΠ±Π»Π°ΠΊΠΎ
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°
ΠΠ»Π°ΡΡΠ΅Ρ Ρ Π½Π°Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π½Π΅ ΡΠΎΠ²ΡΠ΅ΠΌ Π² ΡΠΈΠΏΠΈΡΠ½ΠΎΠΌ ΡΠ΅ΠΆΠΈΠΌΠ΅. Π£ΡΠΈΠ»ΠΈΠ·Π°ΡΠΈΡ ΡΠΈΠ»ΡΠ½ΠΎ Π½Π΅ΡΠ°Π²Π½ΠΎΠΌΠ΅ΡΠ½Π°Ρ. ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, Π΅ΡΡΡ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π·Π°Π½ΡΡΠΈΡ, ΠΊΠΎΠ³Π΄Π° Π²ΡΠ΅ 30 ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ ΠΈ ΠΏΡΠ΅ΠΏΠΎΠ΄Π°Π²Π°ΡΠ΅Π»Ρ Π·Π°Ρ ΠΎΠ΄ΡΡ Π½Π° ΠΊΠ»Π°ΡΡΠ΅Ρ ΠΈ Π½Π°ΡΠΈΠ½Π°ΡΡ ΠΈΠΌ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡΡΡ. ΠΠ»ΠΈ ΠΎΠΏΡΡΡ ΠΆΠ΅ Π΅ΡΡΡ Π΄Π½ΠΈ ΠΏΠ΅ΡΠ΅Π΄ Π΄Π΅Π΄Π»Π°ΠΉΠ½ΠΎΠΌ, ΠΊΠΎΠ³Π΄Π° Π·Π°Π³ΡΡΠ·ΠΊΠ° ΡΠΈΠ»ΡΠ½ΠΎ Π²ΠΎΠ·ΡΠ°ΡΡΠ°Π΅Ρ. ΠΠΎ Π²ΡΠ΅ ΠΎΡΡΠ°Π»ΡΠ½ΠΎΠ΅ Π²ΡΠ΅ΠΌΡ ΠΊΠ»Π°ΡΡΠ΅Ρ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ Π½Π΅Π΄ΠΎΠ·Π°Π³ΡΡΠ·ΠΊΠΈ.
Π Π΅ΡΠ΅Π½ΠΈΠ΅ β1 β ΡΡΠΎ Π΄Π΅ΡΠΆΠ°ΡΡ ΠΊΠ»Π°ΡΡΠ΅Ρ, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ Π²ΡΠ΄Π΅ΡΠΆΠΈΠ²Π°ΡΡ ΠΏΠΈΠΊΠΎΠ²ΡΠ΅ Π·Π°Π³ΡΡΠ·ΠΊΠΈ, Π½ΠΎ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΡΡΠ°ΠΈΠ²Π°ΡΡ Π²ΠΎ Π²ΡΠ΅ ΠΎΡΡΠ°Π»ΡΠ½ΠΎΠ΅ Π²ΡΠ΅ΠΌΡ.
Π Π΅ΡΠ΅Π½ΠΈΠ΅ β2 β ΡΡΠΎ Π΄Π΅ΡΠΆΠ°ΡΡ Π½Π΅Π±ΠΎΠ»ΡΡΠΎΠΉ ΠΊΠ»Π°ΡΡΠ΅Ρ, Π² ΠΊΠΎΡΠΎΡΡΠΉ Π²ΡΡΡΠ½ΡΡ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ Π½ΠΎΠ΄Ρ ΠΏΠ΅ΡΠ΅Π΄ Π·Π°Π½ΡΡΠΈΡΠΌΠΈ ΠΈ Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΠΏΠΈΠΊΠΎΠ²ΡΡ Π½Π°Π³ΡΡΠ·ΠΎΠΊ.
Π Π΅ΡΠ΅Π½ΠΈΠ΅ β3 β ΡΡΠΎ Π΄Π΅ΡΠΆΠ°ΡΡ Π½Π΅Π±ΠΎΠ»ΡΡΠΎΠΉ ΠΊΠ»Π°ΡΡΠ΅Ρ ΠΈ Π½Π°ΠΏΠΈΡΠ°ΡΡ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅Ρ, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΡΠ»Π΅Π΄ΠΈΡΡ Π·Π° ΡΠ΅ΠΊΡΡΠ΅ΠΉ Π·Π°Π³ΡΡΠ·ΠΊΠΎΠΉ ΠΊΠ»Π°ΡΡΠ΅ΡΠ° ΠΈ ΡΠ°ΠΌ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ ΡΠ°Π·Π»ΠΈΡΠ½ΡΠ΅ API, Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ ΠΈ ΡΠ΄Π°Π»ΡΡΡ Π½ΠΎΠ΄Ρ ΠΈΠ· ΠΊΠ»Π°ΡΡΠ΅ΡΠ°.
Π ΡΡΠΎΠΌ ΠΏΠΎΡΡΠ΅ ΠΌΡ Π±ΡΠ΄Π΅ΠΌ Π³ΠΎΠ²ΠΎΡΠΈΡΡ ΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠΈ β3. Π’Π°ΠΊΠΎΠΉ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅Ρ ΡΠΈΠ»ΡΠ½ΠΎ Π·Π°Π²ΠΈΡΠΈΡ ΠΎΡ Π²Π½Π΅ΡΠ½ΠΈΡ ΡΠ°ΠΊΡΠΎΡΠΎΠ², Π° Π½Π΅ ΠΎΡ Π²Π½ΡΡΡΠ΅Π½Π½ΠΈΡ , ΠΈ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΡ Π΅Π³ΠΎ ΡΠ°ΡΡΠΎ Π½Π΅ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΡΡ. ΠΡ ΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ ΠΎΠ±Π»Π°ΡΠ½ΠΎΠΉ ΠΈΠ½ΡΡΠ°ΡΡΡΡΠΊΡΡΡΠΎΠΉ Mail.ru Cloud Solutions ΠΈ Π½Π°ΠΏΠΈΡΠ°Π»ΠΈ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅Ρ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ API MCS. Π ΡΠ°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ ΠΎΠ±ΡΡΠ°Π΅ΠΌ ΡΠ°Π±ΠΎΡΠ΅ Ρ Π΄Π°Π½Π½ΡΠΌΠΈ, ΡΠ΅ΡΠΈΠ»ΠΈ ΠΏΠΎΠΊΠ°Π·Π°ΡΡ, ΠΊΠ°ΠΊ Π²Ρ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π½Π°ΠΏΠΈΡΠ°ΡΡ ΠΏΠΎΠ΄ΠΎΠ±Π½ΡΠΉ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅Ρ Π΄Π»Ρ ΡΠ²ΠΎΠΈΡ ΡΠ΅Π»Π΅ΠΉ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠΎ ΡΠ²ΠΎΠΈΠΌ ΠΎΠ±Π»Π°ΠΊΠΎΠΌ
Prerequisites
ΠΠΎ-ΠΏΠ΅ΡΠ²ΡΡ , Ρ Π²Π°Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±ΡΡΡ Hadoop-ΠΊΠ»Π°ΡΡΠ΅Ρ. ΠΡ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ Π΄ΠΈΡΡΡΠΈΠ±ΡΡΠΈΠ²ΠΎΠΌ HDP.
Π§ΡΠΎΠ±Ρ Ρ Π²Π°Ρ Π½ΠΎΠ΄Ρ ΠΌΠΎΠ³Π»ΠΈ Π±ΡΡΡΡΠΎ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡΡΡ ΠΈ ΡΠ΄Π°Π»ΡΡΡΡΡ, Ρ Π²Π°Ρ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ΅ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΡΠΎΠ»Π΅ΠΉ ΠΏΠΎ Π½ΠΎΠ΄Π°ΠΌ.
- ΠΠ°ΡΡΠ΅Ρ-Π½ΠΎΠ΄Π°. ΠΡ ΡΡΡ ΠΏΠΎΡΡΠ½ΡΡΡ Π½ΠΈΡΠ΅Π³ΠΎ ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎ Π½Π΅ Π½Π°Π΄ΠΎ: Π³Π»Π°Π²Π½Π°Ρ Π½ΠΎΠ΄Π° ΠΊΠ»Π°ΡΡΠ΅ΡΠ°, Π½Π° ΠΊΠΎΡΠΎΡΠΎΠΉ Π·Π°ΠΏΡΡΠΊΠ°Π΅ΡΡΡ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, Π΄ΡΠ°ΠΉΠ²Π΅Ρ Spark’Π°, Π΅ΡΠ»ΠΈ Π²Ρ ΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΠ΅ΡΡ ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π½ΡΠΌ ΡΠ΅ΠΆΠΈΠΌΠΎΠΌ.
- ΠΠ°ΡΠ°-Π½ΠΎΠ΄Π°. ΠΡΠΎ Π½ΠΎΠ΄Π°, Π½Π° ΠΊΠΎΡΠΎΡΠΎΠΉ Ρ Π²Π°Ρ Ρ ΡΠ°Π½ΡΡΡΡ Π΄Π°Π½Π½ΡΠ΅ Π½Π° HDFS ΠΈ Π½Π° Π½Π΅ΠΉ ΠΆΠ΅ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ.
- ΠΡΡΠΈΡΠ»ΠΈΡΠ΅Π»ΡΠ½Π°Ρ Π½ΠΎΠ΄Π°. ΠΡΠΎ Π½ΠΎΠ΄Π°, Π½Π° ΠΊΠΎΡΠΎΡΠΎΠΉ Ρ Π²Π°Ρ Π½ΠΈΡΠ΅Π³ΠΎ Π½Π΅ Ρ ΡΠ°Π½ΠΈΡΡΡ Π½Π° HDFS, Π½ΠΎ Π½Π° Π½Π΅ΠΉ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ.
ΠΠ°ΠΆΠ½ΡΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ. ΠΠ²ΡΠΎΡΠΊΠ΅ΠΉΠ»ΠΈΠ½Π³ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡΡ Π·Π° ΡΡΠ΅Ρ Π½ΠΎΠ΄ ΡΡΠ΅ΡΡΠ΅Π³ΠΎ ΡΠΈΠΏΠ°. ΠΡΠ»ΠΈ Π²Ρ Π½Π°ΡΠ½Π΅ΡΠ΅ Π·Π°Π±ΠΈΡΠ°ΡΡ ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ Π½ΠΎΠ΄Ρ Π²ΡΠΎΡΠΎΠ³ΠΎ ΡΠΈΠΏΠ°, ΡΠΎ ΡΠΊΠΎΡΠΎΡΡΡ ΡΠ΅Π°Π³ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π±ΡΠ΄Π΅Ρ ΡΠΈΠ»ΡΠ½ΠΎ Π½ΠΈΠ·ΠΊΠΎΠΉ β Π΄Π΅ΠΊΠΎΠΌΠΈΡΠ΅Π½ ΠΈ ΡΠ΅ΠΊΠΎΠΌΠΈΡΠ΅Π½ Π±ΡΠ΄Π΅Ρ Π·Π°Π½ΠΈΠΌΠ°ΡΡ ΡΠ°ΡΡ Π½Π° Π²Π°ΡΠ΅ΠΌ ΠΊΠ»Π°ΡΡΠ΅ΡΠ΅. ΠΡΠΎ, ΠΊΠΎΠ½Π΅ΡΠ½ΠΎ, Π½Π΅ ΡΠΎ, ΡΡΠΎ ΠΎΠΆΠΈΠ΄Π°Π΅ΡΡ ΠΎΡ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»ΠΈΠ½Π³Π°. Π’ΠΎ Π΅ΡΡΡ Π½ΠΎΠ΄Ρ ΠΏΠ΅ΡΠ²ΠΎΠ³ΠΎ ΠΈ Π²ΡΠΎΡΠΎΠ³ΠΎ ΡΠΈΠΏΠ° ΠΌΡ Π½Π΅ ΡΡΠΎΠ³Π°Π΅ΠΌ. ΠΠ½ΠΈ Π±ΡΠ΄ΡΡ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΡΡ ΡΠΎΠ±ΠΎΠΉ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΠΎ ΠΆΠΈΠ·Π½Π΅ΡΠΏΠΎΡΠΎΠ±Π½ΡΠΉ ΠΊΠ»Π°ΡΡΠ΅Ρ, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΡΡΡΠ΅ΡΡΠ²ΠΎΠ²Π°ΡΡ Π½Π° ΠΏΡΠΎΡΡΠΆΠ΅Π½ΠΈΠΈ Π²ΡΠ΅Π³ΠΎ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ.
ΠΡΠ°ΠΊ, Π½Π°Ρ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅Ρ Π½Π°ΠΏΠΈΡΠ°Π½ Π½Π° Python 3, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ Ambari API Π΄Π»Ρ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΡΠ΅ΡΠ²ΠΈΡΠ°ΠΌΠΈ ΠΊΠ»Π°ΡΡΠ΅ΡΠ°, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ
ΠΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° ΡΠ΅ΡΠ΅Π½ΠΈΡ
- ΠΠΎΠ΄ΡΠ»Ρ
autoscaler.py
. Π Π½Π΅ΠΌ ΠΏΡΠΎΠΏΠΈΡΠ°Π½Ρ ΡΡΠΈ ΠΊΠ»Π°ΡΡΠ°: 1) ΡΡΠ½ΠΊΡΠΈΠΈ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ Ambari, 2) ΡΡΠ½ΠΊΡΠΈΠΈ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ MCS, 3) ΡΡΠ½ΠΊΡΠΈΠΈ, ΡΠ²ΡΠ·Π°Π½Π½ΡΠ΅ Π½Π΅ΠΏΠΎΡΡΠ΅Π΄ΡΡΠ²Π΅Π½Π½ΠΎ Ρ Π»ΠΎΠ³ΠΈΠΊΠΎΠΉ ΡΠ°Π±ΠΎΡΡ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅ΡΠ°. - Π‘ΠΊΡΠΈΠΏΡ
observer.py
. ΠΠΎ ΡΡΡΠΈ ΡΠΎΡΡΠΎΠΈΡ ΠΈΠ· ΡΠ°Π·Π½ΡΡ ΠΏΡΠ°Π²ΠΈΠ»: ΠΊΠΎΠ³Π΄Π° ΠΈ Π² ΠΊΠ°ΠΊΠΈΠ΅ ΠΌΠΎΠΌΠ΅Π½ΡΡ Π²ΡΠ·ΡΠ²Π°ΡΡ ΡΡΠ½ΠΊΡΠΈΠΈ Π°Π²ΡΠΎΡΠΊΠ΅ΠΉΠ»Π΅ΡΠ°. - Π€Π°ΠΉΠ» Ρ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΎΠ½Π½ΡΠΌΠΈ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠ°ΠΌΠΈ
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