Vyrovnávání zátěže v Openstacku

Ve velkých cloudových systémech je otázka automatického vyrovnávání nebo vyrovnávání zátěže výpočetních zdrojů obzvláště akutní. O tento problém se postaral také Tionix (vývojář a provozovatel cloudových služeb, součást skupiny společností Rostelecom).

A protože naší hlavní vývojovou platformou je Openstack a my jsme jako všichni líní, bylo rozhodnuto vybrat nějaký hotový modul, který je již součástí platformy. Naše volba padla na Watcher, který jsme se rozhodli využít pro naše potřeby.
Vyrovnávání zátěže v Openstacku
Nejprve se podívejme na pojmy a definice.

Pojmy a definice

terč je člověkem čitelný, pozorovatelný a měřitelný konečný výsledek, kterého musí být dosaženo. Pro dosažení každého cíle existuje jedna nebo více strategií. Strategie je implementace algoritmu, který je schopen najít řešení pro daný cíl.

Akce je základní úloha, která mění aktuální stav cílového spravovaného prostředku clusteru OpenStack, jako je: migrace virtuálního počítače (migrace), změna stavu napájení uzlu (change_node_power_state), změna stavu služby nova (change_nova_service_state ), změna chuti (resize), registrace zpráv NOP (nop), nečinnost po určitou dobu - pauza (uspání), přenos disku (volume_migrate).

Akční plán - specifický tok akcí prováděných v určitém pořadí k dosažení konkrétního Cíle. Akční plán také obsahuje měřenou globální výkonnost se souborem výkonnostních ukazatelů. Watcher po úspěšném auditu vygeneruje akční plán, v jehož důsledku použitá strategie najde řešení k dosažení cíle. Akční plán se skládá ze seznamu po sobě jdoucích akcí.

Audit je požadavek na optimalizaci clusteru. Optimalizace se provádí za účelem dosažení jednoho Cíle v daném clusteru. Pro každý úspěšný audit vygeneruje Watcher akční plán.

Rozsah auditu je sada zdrojů, v rámci kterých se provádí audit (zóny dostupnosti, agregátory uzlů, jednotlivé výpočetní uzly nebo uzly úložiště atd.). Rozsah auditu je definován v každé šabloně. Pokud není zadán žádný rozsah auditu, bude auditován celý cluster.

Šablona auditu — uložená sada nastavení pro spuštění auditu. Šablony jsou potřebné k opakovanému spouštění auditů se stejným nastavením. Šablona musí nutně obsahovat účel auditu, pokud nejsou specifikovány strategie, pak jsou vybrány nejvhodnější existující strategie.

Cluster je kolekce fyzických strojů, které poskytují výpočetní, úložné a síťové zdroje a jsou spravovány stejným uzlem správy OpenStack.

Cluster Data Model (CDM) je logickou reprezentací aktuálního stavu a topologie zdrojů spravovaných clusterem.

Ukazatel účinnosti - indikátor, který udává, jak se provádí řešení vytvořené pomocí této strategie. Ukazatele výkonnosti jsou specifické pro konkrétní cíl a obvykle se používají k výpočtu celkové účinnosti výsledného akčního plánu.

Specifikace účinnosti je soubor specifických vlastností spojených s každým cílem, který definuje různé výkonnostní ukazatele, kterých musí strategie k dosažení odpovídajícího Cíle při svém řešení dosáhnout. Každé řešení navržené strategií bude skutečně před výpočtem jeho globální účinnosti zkontrolováno podle specifikace.

Bodovací motor je spustitelný soubor, který má dobře definované vstupy, dobře definované výstupy a provádí čistě matematický úkol. Tímto způsobem je výpočet nezávislý na prostředí, ve kterém se provádí – kdekoli poskytne stejný výsledek.

Watcher Planner - součást rozhodovacího motoru Watcher. Tento modul provádí sadu akcí generovaných strategií a vytváří plán pracovního postupu, který specifikuje, jak naplánovat tyto různé akce v čase a pro každou akci, jaké jsou předpoklady.

Cíle a strategie pozorovatele

terč
strategie

Falešný gól
Dummy strategie 

Dummy strategie pomocí vzorových vyhodnocovacích motorů

Falešná strategie se změnou velikosti

Úspory energie
Strategie úspory energie

Konsolidace serverů
Základní konsolidace offline serveru

Strategie konsolidace pracovní zátěže VM

Vyrovnávání pracovní zátěže
Strategie migrace vyvážení pracovní zátěže

Strategie bilance skladovací kapacity

Stabilizace pracovní zátěže

Hlučný soused
Hlučný soused

Tepelná optimalizace
Strategie založená na výstupní teplotě

Optimalizace proudění vzduchu
Jednotná strategie migrace proudění vzduchu

Údržba hardwaru
Zónová migrace

nezařazená
Pohon

Falešný gól — vyhrazený cíl, který se používá pro účely testování.

Související strategie: Dummy Strategy, Dummy Strategy využívající ukázkové Scoring Engines a Dummy strategie se změnou velikosti. Dummy strategie je fiktivní strategie používaná pro testování integrace prostřednictvím Tempest. Tato strategie neposkytuje žádnou užitečnou optimalizaci, jejím jediným účelem je použití testů Tempest.

Dummy strategie využívající vzorové Scoring Engines – strategie je podobná předchozí, rozdíl je pouze v použití vzorového „scoring engine“, který provádí výpočty pomocí metod strojového učení.

Dummy strategie s resize - strategie je podobná předchozí, rozdíl je pouze v použití změny příchuti (migrace a resize).

Ve výrobě se nepoužívá.

Úspory energie — minimalizovat spotřebu energie. Strategie úspory energie tohoto cíle spolu se strategií konsolidace pracovní zátěže VM (Konsolidace serverů) umožňuje funkce dynamické správy napájení (DPM), které šetří energii dynamickou konsolidací pracovních zátěží i v obdobích nízkého využití zdrojů: virtuální stroje se přesouvají do menšího počtu uzlů. a nepotřebné uzly jsou zakázány. Po konsolidaci strategie nabízí rozhodnutí o zapnutí/vypnutí uzlů v souladu se zadanými parametry: „min_free_hosts_num“ – počet volných povolených uzlů, které čekají na načtení, a „free_used_percent“ – procento volných povolených hostitelů k počet uzlů, které jsou obsazeny stroji. Aby strategie fungovala, musí existovat povoleno a nakonfigurováno Ironic tak, aby zvládlo cyklování napájení na uzlech.

Parametry strategie

parametr
Typ
ve výchozím nastavení
описание

free_used_procent
Číslo
10.0
poměr počtu volných výpočetních uzlů k počtu výpočetních uzlů s virtuálními stroji

min_free_hosts_num
Int
1
minimální počet volných výpočetních uzlů

Cloud musí mít alespoň dva uzly. Použitá metoda je změna stavu napájení uzlu (change_node_power_state). Strategie nevyžaduje shromažďování metrik.

Konsolidace serverů – minimalizace počtu výpočetních uzlů (konsolidace). Má dvě strategie: Basic Offline Server Consolidation a VM Workload Consolidation Strategy.

Strategie Basic Offline Server Consolidation minimalizuje celkový počet použitých serverů a také minimalizuje počet migrací.

Základní strategie vyžaduje následující metriky:

metriky
servis
pluginy
komentář

compute.node.cpu.procent
ceilometr
žádný
 

cpu_util
ceilometr
žádný
 

Parametry strategie: migrace_pokusy - počet kombinací pro hledání potenciálních kandidátů na vypnutí (výchozí, 0, bez omezení), perioda - časový interval v sekundách pro získání statické agregace ze zdroje metrických dat (výchozí, 700).

Použité metody: migrace, změna stavu služby nova (change_nova_service_state).

Strategie konsolidace pracovní zátěže virtuálních počítačů je založena na heuristice prvního přizpůsobení, která se zaměřuje na měřené zatížení CPU a pokouší se minimalizovat uzly, které mají příliš velké nebo příliš malé zatížení s ohledem na omezení kapacity zdrojů. Tato strategie poskytuje řešení, jehož výsledkem je efektivnější využití klastrových prostředků pomocí následujících čtyř kroků:

  1. Fáze vykládání - zpracování nadměrně spotřebovaných zdrojů;
  2. Fáze konsolidace – nakládání s nedostatečně využívanými zdroji;
  3. Optimalizace řešení – snížení počtu migrací;
  4. Zakázání nepoužívaných výpočetních uzlů.

Strategie vyžaduje následující metriky:

metriky
servis
pluginy
komentář

paměť
ceilometr
žádný
 

velikost.kořenového.disku
ceilometr
žádný
 

Následující metriky jsou volitelné, ale pokud jsou k dispozici, zlepší přesnost strategie:

metriky
servis
pluginy
komentář

paměť.rezident
ceilometr
žádný
 

cpu_util
ceilometr
žádný
 

Parametry strategie: perioda — časový interval v sekundách pro získání statické agregace ze zdroje metrických dat (výchozí, 3600).

Používá stejné metody jako předchozí strategie. Více informací zde.

Vyrovnávání pracovní zátěže — vyvážení pracovní zátěže mezi výpočetními uzly. Cíl má tři strategie: Strategie migrace vyvážení pracovní zátěže, Stabilizace pracovní zátěže, Strategie vyvážení kapacity úložiště.

Strategie migrace rovnováhy pracovní zátěže spouští migrace virtuálních strojů na základě pracovní zátěže hostitelského virtuálního stroje. Rozhodnutí o migraci se provede vždy, když % využití CPU nebo RAM uzlu překročí zadanou prahovou hodnotu. V tomto případě by přesunutý virtuální stroj měl přiblížit uzel průměrnému zatížení všech uzlů.

Požadavky

  • Použití fyzických procesorů;
  • Alespoň dva fyzické výpočetní uzly;
  • Nainstalovali a nakonfigurovali komponentu Ceilometer – ceilometer-agent-compute, běžící na každém výpočetním uzlu, a rozhraní API Ceilometer a také shromažďovali následující metriky:

metriky
servis
pluginy
komentář

cpu_util
ceilometr
žádný
 

paměť.rezident
ceilometr
žádný
 

Parametry strategie:

parametr
Typ
ve výchozím nastavení
описание

metriky
Řetězec
'cpu_util'
Základní metriky jsou: 'cpu_util', 'memory.resident'.

práh
Číslo
25.0
Práh zátěže pro migraci.

období
Číslo
300
Kumulativní časové období Ceilometr.

Použitá metoda je migrace.

Stabilizace pracovní zátěže je strategie zaměřená na stabilizaci pracovní zátěže pomocí živé migrace. Strategie je založena na algoritmu směrodatné odchylky a určuje, zda v clusteru dochází k přetížení, a reaguje na to spuštěním migrace stroje, aby se cluster stabilizoval.

Požadavky

  • Použití fyzických procesorů;
  • Alespoň dva fyzické výpočetní uzly;
  • Nainstalovali a nakonfigurovali komponentu Ceilometer – ceilometer-agent-compute, běžící na každém výpočetním uzlu, a rozhraní API Ceilometer a také shromažďovali následující metriky:

metriky
servis
pluginy
komentář

cpu_util
ceilometr
žádný
 

paměť.rezident
ceilometr
žádný
 

Storage Capacity Balance Strategy (strategie implementovaná počínaje Queens) - strategie přenáší disky v závislosti na zatížení fondů Cinder. Rozhodnutí o převodu je učiněno vždy, když míra využití fondu překročí zadanou prahovou hodnotu. Přesouvaný disk by měl fond přiblížit průměrnému zatížení všech fondů Cinder.

Požadavky a omezení

  • Minimálně dva bazény Cinder;
  • Možnost migrace disku.
  • Cluster datový model - Cinder cluster datový model kolektoru.

Parametry strategie:

parametr
Typ
ve výchozím nastavení
описание

volume_threshold
Číslo
80.0
Prahová hodnota disků pro vyrovnávání svazků.

Použitá metoda je migrace disku (volume_migrate).

Noisy Neighbor – Identifikujte a migrujte „hlučného souseda“ – virtuální stroj s nízkou prioritou, který nadměrným používáním mezipaměti poslední úrovně negativně ovlivňuje výkon virtuálního stroje s vysokou prioritou z hlediska IPC. Vlastní strategie: Noisy Neighbor (použitý parametr strategie je cache_threshold (výchozí hodnota je 35), když výkon klesne na zadanou hodnotu, spustí se migrace. Aby strategie fungovala, povoleno metriky LLC (Last Level Cache), nejnovější server Intel s podporou CMTa také shromažďování následujících metrik:

metriky
servis
pluginy
komentář

cpu_l3_cache
ceilometr
žádný
Vyžaduje Intel CMT.

Datový model clusteru (výchozí): Kolektor datového modelu clusteru Nova. Použitá metoda je migrace.

Práce s tímto cílem prostřednictvím Dashboardu není v Queens plně implementována.

Tepelná optimalizace — optimalizovat teplotní režim. Výstupní teplota (výfukového vzduchu) je jedním z důležitých tepelných telemetrických systémů pro měření tepelného/pracovního stavu serveru. Cíl má jednu strategii, strategii založenou na výstupní teplotě, která se rozhodne přenést pracovní zátěž na tepelně příznivé hostitele (nejnižší výstupní teplota), když výstupní teplota hostitelských zdrojů dosáhne konfigurovatelné prahové hodnoty.

Aby strategie fungovala, potřebujete server s nainstalovaným a nakonfigurovaným Intel Power Node Manager 3.0 nebo pozdějia také shromažďování následujících metrik:

metriky
servis
pluginy
komentář

hardware.ipmi.node.outlet_temperature
ceilometr
IPMI
 

Parametry strategie:

parametr
Typ
ve výchozím nastavení
описание

práh
Číslo
35.0
Teplotní práh pro migraci.

období
Číslo
30
Časový interval v sekundách pro získání statistické agregace ze zdroje metrických dat.

Použitá metoda je migrace.

Optimalizace proudění vzduchu — optimalizovat režim ventilace. Vlastní strategie - Jednotné proudění vzduchu pomocí živé migrace. Tato strategie spouští migraci virtuálního počítače, kdykoli proudění vzduchu z ventilátoru serveru překročí zadanou prahovou hodnotu.

Aby strategie fungovala, potřebujete:

  • Hardware: výpočetní uzly < podporující NodeManager 3.0;
  • Alespoň dva výpočetní uzly;
  • Komponenta ceilometer-agent-compute a Ceilometer API nainstalovaná a nakonfigurovaná na každém výpočetním uzlu, který může úspěšně hlásit metriky, jako je průtok vzduchu, výkon systému, teplota na vstupu:

metriky
servis
pluginy
komentář

hardwarový.uzel.ipmi.proud vzduchu
ceilometr
IPMI
 

hardware.ipmi.node.temperature
ceilometr
IPMI
 

hardware.ipmi.node.power
ceilometr
IPMI
 

Aby strategie fungovala, potřebujete server s nainstalovaným a nakonfigurovaným Intel Power Node Manager 3.0 nebo novějším.

Omezení: Koncept není určen pro výrobu.

Navrhuje se používat tento algoritmus s nepřetržitými audity, protože se plánuje migrace pouze jednoho virtuálního stroje na iteraci.

Živá migrace je možná.

Parametry strategie:

parametr
Typ
ve výchozím nastavení
описание

prahový_průtok vzduchu
Číslo
400.0
Prahová hodnota průtoku vzduchu pro migrační jednotku je 0.1 CFM

prahový_vstup_t
Číslo
28.0
Práh vstupní teploty pro rozhodnutí o migraci

prahová_výkon
Číslo
350.0
Práh výkonu systému pro rozhodnutí o migraci

období
Číslo
30
Časový interval v sekundách pro získání statistické agregace ze zdroje metrických dat.

Použitá metoda je migrace.

Údržba hardwaru — údržba hardwaru. Strategie související s tímto cílem je migrace zón. Strategie je nástrojem pro efektivní automatickou a minimální migraci virtuálních strojů a disků v případě potřeby údržby hardwaru. Strategie vytváří akční plán v souladu s váhami: sada akcí, která má větší váhu, bude naplánována před ostatními. Existují dvě možnosti konfigurace: action_weights a paralelizace.

Omezení: je třeba nakonfigurovat akční váhy a paralelizaci.

Parametry strategie:

parametr
Typ
ve výchozím nastavení
описание

výpočetní_uzly
řada
Nevyplněno
Výpočet uzlů pro migraci.

storage_pools
řada
Nevyplněno
Úložné uzly pro migraci.

paralelní_celkem
celé číslo
6
Celkový počet činností, které je třeba provést paralelně.

paralelní_na_uzel
celé číslo
2
Počet akcí provedených paralelně pro každý výpočetní uzel.

parallel_per_pool
celé číslo
2
Počet akcí provedených paralelně pro každý fond úložiště.

priorita
objekt
Nevyplněno
Seznam priorit pro virtuální počítače a disky.

with_attached_volume
boolean
Falešný
False – virtuální počítače budou migrovány po migraci všech disků. Pravda – virtuální počítače budou migrovány po migraci všech připojených disků.

Prvky pole výpočetních uzlů:

parametr
Typ
ve výchozím nastavení
описание

src_node
šňůra
Nevyplněno
Výpočetní uzel, ze kterého se migrují virtuální počítače (povinné).

dst_node
šňůra
Nevyplněno
Vypočítejte uzel, do kterého virtuální počítače migrují.

Prvky pole uzlů úložiště:

parametr
Typ
ve výchozím nastavení
описание

src_pool
šňůra
Nevyplněno
Úložný fond, ze kterého jsou disky migrovány (povinné).

dst_pool
šňůra
Nevyplněno
Úložný fond, do kterého jsou disky migrovány.

typ_src
šňůra
Nevyplněno
Původní typ disku (vyžadováno).

dst_type
šňůra
Nevyplněno
Výsledný typ disku (povinné).

Prvky priority objektu:

parametr
Typ
ve výchozím nastavení
описание

projekt
řada
Nevyplněno
Názvy projektů.

výpočetní_uzel
řada
Nevyplněno
Vypočítejte názvy uzlů.

storage_pool
řada
Nevyplněno
Názvy fondu úložiště.

vypočítat
výčet
Nevyplněno
Parametry virtuálního počítače [“vcpu_num”, “mem_size”, “disk_size”, “created_at”].

skladování
výčet
Nevyplněno
Parametry disku ["velikost", "vytvořeno_at"].

Používané metody jsou migrace virtuálního stroje, migrace disku.

nezařazená - pomocný cíl používaný k usnadnění procesu rozvoje strategie. Neobsahuje žádné specifikace a lze ji použít, kdykoli strategie ještě není spojena s existujícím cílem. Tento cíl lze také použít jako přechodový bod. Strategie související s tímto cílem je Actuator.   

Vytvoření nového cíle

Watcher Decision Engine má rozhraní pluginu „externí cíl“, které umožňuje integrovat externí cíl, kterého lze dosáhnout pomocí strategie.

Než vytvoříte nový cíl, měli byste se ujistit, že žádné existující cíle nesplňují vaše potřeby.

Vytvoření nového pluginu

Chcete-li vytvořit nový cíl, musíte: rozšířit cílovou třídu, implementovat metodu třídy get_name() vrátit jedinečné ID nového cíle, který chcete vytvořit. Tento jedinečný identifikátor se musí shodovat s názvem vstupního bodu, který deklarujete později.

Dále musíte implementovat metodu třídy get_display_name() vrátit přeložený zobrazovaný název cíle, který chcete vytvořit (nepoužívejte proměnnou k vrácení přeloženého řetězce, aby jej mohl překladový nástroj automaticky shromáždit.).

Implementujte metodu třídy get_translatable_display_name()vrátit překladový klíč (ve skutečnosti anglický zobrazovaný název) vašeho nového cíle. Vrácená hodnota musí odpovídat řetězci přeloženému do get_display_name().

Implementujte jeho metodu get_efficacy_specification()vrátit specifikaci účinnosti pro váš cíl. Metoda get_efficacy_specification() vrací instanci Unclassified() poskytovanou Watcherem. Tato specifikace výkonu je užitečná v procesu vývoje vašeho cíle, protože odpovídá prázdné specifikaci.

Více informací zde

Architektura Watcher (další podrobnosti) zde).

Vyrovnávání zátěže v Openstacku

Komponenty

Vyrovnávání zátěže v Openstacku

Watcher API - komponenta, která implementuje REST API poskytované Watcherem. Interakční mechanismy: CLI, Horizon plugin, Python SDK.

Watcher DB — Databáze pozorovatelů.

Watcher Applier — komponenta, která implementuje provádění akčního plánu vytvořeného komponentou Watcher Decision Engine.

Watcher Decision Engine - Komponenta odpovědná za výpočet sady potenciálních optimalizačních akcí k dosažení cíle auditu. Pokud není strategie specifikována, komponenta nezávisle vybere tu nejvhodnější.

Vydavatel metrik Watcher - Komponenta, která shromažďuje a vypočítává některé metriky nebo události a publikuje je do koncového bodu CEP. Funkčnost komponenty může zajistit i vydavatel Ceilometer.

Modul komplexního zpracování událostí (CEP). — engine pro komplexní zpracování událostí. Z důvodů výkonu může být souběžně spuštěno více instancí CEP Engine, z nichž každá zpracovává specifický typ metriky/události. V systému Watcher CEP spouští dva typy akcí: - zaznamenat odpovídající události / metriky do databáze časových řad; - odeslat příslušné události do nástroje Watcher Decision Engine, pokud tato událost může ovlivnit výsledek aktuální strategie optimalizace, protože cluster Openstack není statický systém.

Komponenty interagují pomocí protokolu AMQP.

Konfigurace Watcheru

Schéma interakce s Watcherem

Vyrovnávání zátěže v Openstacku

Výsledky testu pozorovatele

  1. Na stránce Optimalizace - Akční plány 500 (jak na čistých Queenech, tak na stojanu s moduly Tionix) se objeví až po spuštění auditu a vygenerování akčního plánu, prázdný se normálně otevře.
  2. Na záložce Detaily akce jsou chyby, nelze získat cíl a strategii auditu (jak na čistých Queenech, tak na stojanu s moduly Tionix).
  3. Audity za účelem Dummy (test) se vytvářejí a spouštějí normálně, generují se akční plány.
  4. Audity pro cíl Nezařazeno se nevytvářejí, protože cíl není funkční a je určen pro mezikonfiguraci při vytváření nových strategií.
  5. Audity pro účely vyrovnávání pracovní zátěže (strategie vyvážení kapacity úložiště) jsou úspěšně vytvořeny, ale není vygenerován akční plán. Není nutná žádná optimalizace úložiště.
  6. Audity pro cíl Workload Balancing (Workload Balance Migration Strategy) jsou úspěšně vytvořeny, ale není vygenerován akční plán.
  7. Audity pro vyrovnávání pracovní zátěže (strategie stabilizace pracovní zátěže) se nezdařily.
  8. Audity pro cíl Hlučný soused jsou úspěšně vytvořeny, ale nevygeneruje se akční plán.
  9. Audity pro účely údržby hardwaru jsou úspěšně vytvořeny, plán akcí není generován celý (generují se ukazatele výkonu, ale negeneruje se samotný seznam akcí).
  10. Úpravy v konfiguračních souborech nova.conf (ve výchozí sekci compute_monitors = cpu.virt_driver) na výpočetních a řídicích uzlech chyby neopraví.
  11. Audity zaměřené na konsolidaci serverů (základní strategie) také selžou.
  12. Audity pro účely konsolidace serverů (strategie konsolidace zátěže virtuálních počítačů) se nezdaří s chybou. V protokolech je chyba při získávání zdrojových dat. Diskuse o chybě, zejména zde.
    Pokusili jsme se zadat Watcher v konfiguračním souboru (nepomohlo - v důsledku chyby na všech stránkách Optimalizace návrat k původnímu obsahu konfiguračního souboru situaci neopraví):

    [watcher_strategies.basic] zdroj dat = ceilometr, noky
  13. Audity pro úsporu energie selžou. Soudě podle logů je problém stále v absenci Ironicu, bez baremetalového servisu to nepůjde.
  14. Audity tepelné optimalizace se nezdařily. Zpětné sledování je stejné jako u konsolidace serveru (strategie konsolidace zátěže virtuálního počítače) (chyba zdrojových dat)
  15. Audity pro účely optimalizace proudění vzduchu se nezdaří s chybou.

Jsou také zjištěny následující chyby při dokončení auditu. Zpětné sledování v protokolech decision-engine.log (stav clusteru není definován).

→ Diskuse o chybě zde

Závěr

Výsledkem našeho dvouměsíčního výzkumu byl jednoznačný závěr, že abychom získali plnohodnotný systém vyrovnávání pracovní zátěže, budeme muset v této části úzce spolupracovat na dolaďování nástrojů pro platformu Openstack.

Watcher se ukázal jako seriózní a rychle se rozvíjející produkt s obrovským potenciálem, jehož plné využití bude vyžadovat hodně seriózní práce.

Ale o tom více v dalších článcích série.

Zdroj: www.habr.com

Přidat komentář