Versu basa di dati serverless - cumu è perchè

Salut à tutti ! Mi chjamu Golov Nikolay. Prima, aghju travagliatu in Avito è gestitu a piattaforma di dati per sei anni, vale à dì, aghju travagliatu in tutte e basa di dati: analitiche (Vertica, ClickHouse), streaming è OLTP (Redis, Tarantool, VoltDB, MongoDB, PostgreSQL). Duranti stu tempu, aghju trattatu un gran numaru di basa di dati - assai diffirenti è inusual, è cù casi micca standard di u so usu.

Sò attualmente travagliendu in ManyChat. In essenza, questu hè un startup - novu, ambiziosu è in rapida crescita. È quandu aghju unitu per a prima volta in a cumpagnia, hè stata una quistione classica: "Chì duverebbe un ghjovanu startup avà piglià da u mercatu di DBMS è di basa di dati?"

In questu articulu, basatu annantu à u mo rapportu at festival online RIT++ 2020, risponderaghju à sta quistione. Una versione video di u rapportu hè dispunibule à YouTube.

Versu basa di dati serverless - cumu è perchè

Basi di dati cumunimenti cunnisciute 2020

Hè 2020, aghju guardatu intornu è aghju vistu trè tippi di basa di dati.

primu tipu - basa di dati OLTP classicu: PostgreSQL, SQL Server, Oracle, MySQL. Sò stati scritti assai tempu fà, ma sò sempre pertinenti perchè sò cusì familiar à a cumunità di sviluppatori.

U sicondu tipu hè basi da "zero". Anu pruvatu à alluntanassi da i mudelli classici abbandunendu SQL, strutture tradiziunali è ACID, aghjunghjendu sharding integrati è altre caratteristiche attraenti. Per esempiu, questu hè Cassandra, MongoDB, Redis o Tarantool. Tutte queste suluzioni vulianu offre à u mercatu qualcosa di fundamentalmente novu è occupanu u so nichulu, perchè sò diventati estremamente convenienti per certi travaglii. Denoteraghju queste basa di dati cù u termu umbrella NOSQL.

I "zeri" sò finiti, avemu abituatu à basa di dati NOSQL, è u mondu, da u mo puntu di vista, hà fattu u prossimu passu - per basa di dati gestite. Queste basa di dati anu u stessu core cum'è e basa di dati OLTP classicu o novi NoSQL. Ma ùn anu micca bisognu di DBA è DevOps è eseguite nantu à hardware amministratu in i nuvuli. Per un sviluppatore, questu hè "solu una basa" chì travaglia in un locu, ma nimu ùn importa cumu hè stallatu nantu à u servitore, quale hà cunfiguratu u servitore è quale l'aghjurnà.

Esempii di tali basa di dati:

  • AWS RDS hè un wrapper gestitu per PostgreSQL/MySQL.
  • DynamoDB hè un analogu AWS di una basa di dati basata in documenti, simili à Redis è MongoDB.
  • Amazon Redshift hè una basa di dati analitica gestita.

Quessi sò basamenti basati di dati antichi, ma risuscitati in un ambiente amministratu, senza bisognu di travaglià cù hardware.

Nota. L'esempii sò pigliati per l'ambiente AWS, ma i so analoghi sò ancu in Microsoft Azure, Google Cloud, o Yandex.Cloud.

Versu basa di dati serverless - cumu è perchè

Chì ci hè di novu in questu? In 2020, nunda di questu.

Cuncepimentu senza server

Ciò chì hè veramente novu nantu à u mercatu in u 2020 hè e soluzioni serverless o serverless.

Pruvaraghju di spiegà ciò chì questu significa utilizendu l'esempiu di un serviziu regulare o applicazione backend.
Per implementà una applicazione backend regulare, cumprà o affittu un servitore, copià u codice nantu à ellu, pubblicà l'endpoint fora è paghemu regularmente per l'affittu, l'electricità è i servizii di centru di dati. Questu hè u schema standard.

Ci hè un altru modu ? Cù servizii serverless pudete.

Chì ci hè u focu di questu approcciu: ùn ci hè micca un servitore, ùn ci hè mancu affittu una istanza virtuale in u nuvulu. Per implementà u serviziu, copià u codice (funzioni) à u repository è pubblicà à l'endpoint. Allora paghemu solu per ogni chjama à sta funzione, ignorendu completamente u hardware induve hè eseguitu.

Pruvaraghju di illustrà stu approcciu cù ritratti.
Versu basa di dati serverless - cumu è perchè

Impiegazione classica. Avemu un serviziu cù una certa carica. Allevamu dui casi: servitori fisici o istanze in AWS. E dumande esterne sò mandate à queste istanze è trattate quì.

Comu pudete vede in a stampa, i servitori ùn sò micca disposti ugualmente. Unu hè 100% utilizatu, ci sò duie richieste, è unu hè solu 50% - parzialmente inattivu. Se ùn arrivanu micca trè richieste, ma 30, allura tuttu u sistema ùn serà micca capaci di affruntà a carica è cumincià à rallentà.

Versu basa di dati serverless - cumu è perchè

Implementazione senza server. In un ambiente senza servitore, un tali serviziu ùn hà micca istanze o servitori. Ci hè una certa piscina di risorse riscaldate - picculi cuntenituri Docker preparati cù codice di funzione implementatu. U sistema riceve richieste esterne è per ognuna di elli u framework senza servitore suscita un picculu cuntinuu cù codice: processa sta dumanda particulare è uccide u cuntinuu.

Una dumanda - un containeru risuscitatu, 1000 richieste - 1000 containers. E implementazione nantu à i servitori di hardware hè digià u travagliu di u fornitore di nuvola. Hè cumplettamente oculatu da u framework senza servitore. In questu cuncettu paghemu per ogni chjama. Per esempiu, una chjama hè ghjunta à ghjornu - avemu pagatu per una chjama, un milione hè vinutu per minutu - avemu pagatu per un milione. O in un secondu, questu succede ancu.

U cuncettu di publicà una funzione senza servitore hè adattatu per un serviziu senza statu. È se avete bisognu di un serviziu statutu (statu), allora aghjunghjemu una basa di dati à u serviziu. In questu casu, quandu si tratta di travaglià cù u statu, ogni funzione statefull simpricimenti scrive è leghje da a basa di dati. Inoltre, da una basa di dati di qualsiasi di i trè tippi descritti à u principiu di l'articulu.

Chì ghjè a limitazione cumuna di tutte queste basa di dati? Quessi sò i costi di un servitore nuvola o hardware constantemente utilizatu (o parechji servitori). Ùn importa micca chì usemu una basa di dati classica o gestita, sia avemu Devops è un amministratore o micca, paghemu sempre per l'hardware, l'electricità è l'affittu di u centru di dati 24/7. Se avemu una basa classica, paghemu per maestru è schiavu. S'ellu hè una basa di dati sharded altamente caricata, paghemu per 10, 20 o 30 servitori, è paghemu constantemente.

A prisenza di i servitori riservati in permanenza in a struttura di u costu era prima percivata cum'è un male necessariu. E basa di dati cunvinziunali anu ancu altre difficultà, cum'è limiti in u numeru di cunnessione, restrizioni di scala, cunsensu geo-distribuitu - ponu esse risolti in certi basa di dati, ma micca tutti in una volta è micca idealmente.

basa di dati serverless - teoria

Quistione di 2020: hè pussibule ancu fà una basa di dati senza servitore? Tuttu u mondu hà intesu parlà di u backend serverless ... pruvemu di fà a basa di dati serverless ?

Questu sona stranu, perchè a basa di dati hè un serviziu statefull, micca assai adattatu per l'infrastruttura serverless. À u listessu tempu, u statu di a basa di dati hè assai grande: gigabytes, terabytes, è in basa di dati analitiche ancu petabytes. Ùn hè micca cusì faciule d'alzà in cuntenituri Docker ligeri.

Per d 'altra banda, quasi tutte e basa di dati muderni cuntenenu una quantità enorme di logica è cumpunenti: transazzione, coordinazione di integrità, prucedure, dependenzii relazionali è assai logica. Per assai di logica di basa di dati, un picculu statu hè abbastanza. Gigabytes è Terabytes sò direttamente utilizati da solu una piccula parte di a logica di basa di dati implicata in eseguisce direttamente e dumande.

In cunsiquenza, l'idea hè: se una parte di a logica permette l'esekzione senza statu, perchè micca dividite a basa in parti Stateful è Stateless.

Serverless per soluzioni OLAP

Videmu ciò chì taglià una basa di dati in parti Stateful è Stateless pò esse cum'è usendu esempi pratichi.

Versu basa di dati serverless - cumu è perchè

Per esempiu, avemu una basa di dati analitica: dati esterni (cilindru rossu à manca), un prucessu ETL chì carica dati in a basa di dati, è un analista chì manda dumande SQL à a basa di dati. Questu hè un schema classicu di operazione di magazzinu di dati.

In questu schema, ETL hè cundiziunatu una volta. Allora avete bisognu di pagà constantemente per i servitori nantu à quale a basa di dati corre cù dati pienu di ETL, perchè ci hè qualcosa per mandà dumande.

Fighjemu un approcciu alternativu implementatu in AWS Athena Serverless. Ùn ci hè micca un hardware dedicatu in permanenza nantu à quale i dati scaricati sò almacenati. Invece di questu:

  • L'utilizatore sottumette una dumanda SQL à Athena. L'ottimisatore Athena analizeghja a dumanda SQL è cerca in u magazinu di metadata (Metadata) per e dati specifichi necessarii per eseguisce a dumanda.
  • L'ottimisatore, basatu annantu à i dati raccolti, scarica i dati necessarii da e fonti esterne in u almacenamiento temporale (database temporale).
  • Una dumanda SQL da l'utilizatore hè eseguita in almacenamiento temporale è u risultatu hè tornatu à l'utilizatore.
  • L'almacenamiento temporale hè sbulicatu è e risorse sò liberate.

In questa architettura, paghemu solu per u prucessu di eseguisce a dumanda. Nisuna dumanda - senza costi.

Versu basa di dati serverless - cumu è perchè

Questu hè un approcciu di travagliu è hè implementatu micca solu in Athena Serverless, ma ancu in Redshift Spectrum (in AWS).

L'esempiu Athena mostra chì a basa di dati Serverless travaglia nantu à e dumande reali cù decine è centinaie di Terabytes di dati. Centinaie di Terabytes necessitanu centinaie di servitori, ma ùn avemu micca da pagà per elli - paghemu per e dumande. A rapidità di ogni dumanda hè (assai) bassa cumparatu cù basa di dati analitiche specializate cum'è Vertica, ma ùn paghemu micca per i periodi di downtime.

Una tale basa di dati hè applicabile per e dumande ad-hoc analitiche rare. Per esempiu, quandu avemu spontaneamente decide di pruvà una ipotesi nantu à una quantità gigantesca di dati. Athena hè perfetta per questi casi. Per e dumande regulare, un tali sistema hè caru. In stu casu, cache i dati in qualchi suluzione specializata.

Serverless per soluzioni OLTP

L'esempiu precedente hà guardatu i travaglii OLAP (analitici). Avà fighjemu i travaglii OLTP.

Imaginemu PostgreSQL scalable o MySQL. Elvemu una istanza gestionata regulare PostgreSQL o MySQL cù risorse minime. Quandu l'istanza riceve più carica, cunnetteremu rèpliche supplementari à quale distribuiremu una parte di a carica di lettura. Se ùn ci sò micca richieste o carica, spegnemu e repliche. U primu istanza hè u maestru, è u restu sò repliche.

Questa idea hè implementata in una basa di dati chjamata Aurora Serverless AWS. U principiu hè simplice: e dumande da applicazioni esterne sò accettate da a flotta proxy. Videndu l'aumentu di a carica, attribuisce risorse di computazione da istanze minime pre-riscaldate - a cunnessione hè fatta u più prestu pussibule. I casi di disattivazione si verificanu in u listessu modu.

Dentro Aurora ci hè u cuncettu di Aurora Capacity Unit, ACU. Questu hè (condizionalmente) una istanza (servitore). Ogni ACU specificu pò esse un maestru o un slave. Ogni Unità di Capacità hà u so propiu RAM, processore è discu minimu. In cunsiquenza, unu hè maestru, u restu sò letti solu repliche.

U numaru di sti Unità di Capacità Aurora in esecuzione hè un paràmetru configurabile. A quantità minima pò esse unu o cero (in questu casu, a basa di dati ùn viaghja micca s'ellu ùn ci hè micca dumande).

Versu basa di dati serverless - cumu è perchè

Quandu a basa riceve richieste, a flotta proxy aumenta Aurora CapacityUnits, aumentendu e risorse di rendiment di u sistema. L'abilità di aumentà è diminuite e risorse permette à u sistema di "juggle" risorse: visualizà automaticamente l'ACU individuali (sustituitu cù novi) è sparghje tutte l'aghjurnamenti attuali à e risorse ritirate.

A basa di Aurora Serverless pò scala a carica di lettura. Ma a documentazione ùn dice micca direttamente. Puderia sentu chì ponu elevà un multi-maestru. Ùn ci hè micca magia.

Questa basa di dati hè adattata per evità di spende enormi quantità di soldi in sistemi cù accessu imprevisible. Per esempiu, quandu creanu MVP o siti di carte di cummerciale di marketing, di solitu ùn aspittemu micca una carica stabile. Dunque, s'ellu ùn ci hè micca accessu, ùn paghemu micca per istanze. Quandu si trova una carica inespettata, per esempiu dopu una cunferenza o una campagna di publicità, una folla di persone visitate u situ è ​​a carica aumenta dramaticamente, Aurora Serverless piglia automaticamente sta carica è cunnetta rapidamente e risorse mancanti (ACU). Allora a cunferenza passa, tutti si scurdanu di u prototipu, i servitori (ACU) si scurdanu, è i costi scendenu à zero - cunvene.

Sta suluzione ùn hè micca adattatu per una carica alta stabile perchè ùn scala micca a carica di scrittura. Tutte queste cunnessione è disconnections di risorse sò in u chjamatu "scale point" - un puntu in u tempu quandu a basa di dati ùn hè micca supportata da una transazzione o tavule temporale. Per esempiu, in una settimana u puntu di scala ùn pò micca accade, è a basa travaglia nantu à i stessi risorse è simpricimenti ùn pò micca espansione o cuntrattu.

Ùn ci hè micca magia - hè un PostgreSQL regular. Ma u prucessu di aghjunghje macchine è disconnecting elli hè parzialmente automatizatu.

Serverless da u disignu

Aurora Serverless hè una vechja basa di dati riscritta per u nuvulu per prufittà di alcuni di i benefici di Serverless. È avà vi dicu nantu à a basa, chì hè stata scritta originalmente per u nuvulu, per l'approcciu serverless - Serverless-by-design. Hè statu subitu sviluppatu senza l'assunzione chì correrà nantu à i servitori fisichi.

Sta basa hè chjamata Snowflake. Havi trè blocchi chjave.

Versu basa di dati serverless - cumu è perchè

U primu hè un bloccu di metadata. Questu hè un serviziu veloce in memoria chì risolve i prublemi cù a sicurità, i metadati, e transazzione è l'ottimisazione di e dumande (mostra in l'illustrazione à manca).

U sicondu bloccu hè un inseme di clusters di computing virtuale per i calculi (in l'illustrazione ci hè un inseme di circles blu).

U terzu bloccu hè un sistema di almacenamiento di dati basatu in S3. S3 hè un almacenamentu di oggetti senza dimensioni in AWS, una sorta di Dropbox senza dimensioni per l'affari.

Videmu cumu travaglia Snowflake, assumendu un principiu friddu. Vale à dì, ci hè una basa di dati, i dati sò caricati in questu, ùn ci sò micca dumande in esecuzione. Dunque, s'ellu ùn ci hè micca dumande à a basa di dati, allora avemu risuscitatu u serviziu di Metadata in memoria veloce (primu bloccu). E avemu l'almacenamiento S3, induve i dati di a tavula sò almacenati, divisu in i micropartizioni chjamati. Per simplicità: se a tavula cuntene transazzione, allora i micropartizioni sò i ghjorni di transazzione. Ogni ghjornu hè una micropartizione separata, un schedariu separatu. È quandu a basa di dati opera in questu modu, paghete solu per u spaziu occupatu da e dati. Inoltre, a tarifa per sediu hè assai bassu (in particulare in cunsiderà a cumpressione significativa). U serviziu di metadata travaglia ancu constantemente, ma ùn avete micca bisognu di assai risorse per ottimisà e dumande, è u serviziu pò esse cunsideratu shareware.

Avà imaginemu chì un utilizatore hè ghjuntu à a nostra basa di dati è hà mandatu una dumanda SQL. A dumanda SQL hè immediatamente mandata à u serviziu di Metadata per u processu. In cunsiquenza, quandu riceve una dumanda, stu serviziu analizeghja a dumanda, i dati dispunibili, i permessi di l'utilizatori è, se tuttu hè bè, elaburà un pianu per trattà a dumanda.

Dopu, u serviziu inizia u lanciamentu di u cluster di computing. Un cluster di computing hè un cluster di servitori chì facenu calculi. Questu hè, questu hè un cluster chì pò cuntene 1 servitore, 2 servitori, 4, 8, 16, 32 - quanti vulete. Fate una dumanda è u lanciamentu di stu cluster principia immediatamente. Ci vole veramente seconde.

Versu basa di dati serverless - cumu è perchè

Dopu, dopu chì u cluster hà iniziatu, i micropartizioni necessarii per processà a vostra dumanda cumincianu à esse copiati in u cluster da S3. Questu hè, imaginemu chì per eseguisce una dumanda SQL avete bisognu di duie partizioni da una tavola è una da a seconda. In questu casu, solu i trè partizioni necessarii seranu copiati à u cluster, è micca tutte e tavule interamente. Hè per quessa, è precisamente perchè tuttu hè situatu in un centru di dati è cunnessu da canali assai veloci, tuttu u prucessu di trasferimentu si faci assai rapidamente: in seconde, assai raramenti in minuti, salvu chì ùn parlemu di alcune richieste monstruose. In cunsiquenza, i micropartizioni sò copiati à u cluster di computing, è, dopu à a fine, a dumanda SQL hè eseguita nantu à stu cluster di computing. U risultatu di sta dumanda pò esse una linea, parechje linee o una tavola - sò mandati esternamente à l'utilizatore per ch'ellu pò scaricà, vede in u so strumentu BI, o aduprà in un altru modu.

Ogni dumanda SQL ùn pò micca solu leghje aggregati da dati caricati prima, ma ancu carica / generà novi dati in a basa di dati. Questu hè, pò esse una dumanda chì, per esempiu, inserisce novi registri in un altru tavulu, chì porta à l'apparizione di una nova partizione nantu à u cluster di l'informatica, chì, à u turnu, hè automaticamente salvatu in un unicu almacenamiento S3.

U scenariu descrittu sopra, da l'arrivu di l'utilizatore à l'elevazione di u cluster, a carica di dati, l'esecuzione di dumande, l'ottenimentu di risultati, hè pagatu à a tarifa per minuti di usu di u cluster di computer virtuale elevatu, magazzinu virtuale. A tarifa varieghja secondu a zona AWS è a dimensione di u cluster, ma in media hè uni pochi di dollari per ora. Un cluster di quattru machini hè duie volte più caru chì un cluster di dui machini, è un cluster di ottu machini hè sempre duie volte più caru. Opzioni di 16, 32 macchine sò dispunibili, secondu a cumplessità di e dumande. Ma paghete solu per quelli minuti quandu u cluster hè veramente in esecuzione, perchè quandu ùn ci sò micca richieste, ti caccià e mani, è dopu à 5-10 minuti d'attesa (un paràmetru configurabile) esce da sè stessu, liberate risorse è diventate liberi.

Un scenariu cumplettamente realistu hè quandu mandate una dumanda, u cluster si apre, relativamente parlante, in un minutu, conta un altru minutu, dopu cinque minuti per chjude, è finisci per pagà per sette minuti di operazione di stu cluster, è micca per mesi è anni.

U primu scenariu descrittu utilizendu Snowflake in un paràmetru unicu utilizatore. Avà imaginemu chì ci sò parechji utilizatori, chì hè più vicinu à u scenariu reale.

Diciamu chì avemu assai analisti è rapporti di Tableau chì bombardanu constantemente a nostra basa di dati cù un gran numaru di dumande SQL analitiche simplici.

Inoltre, dicemu chì avemu inventivu Data Scientists chì prova di fà cose monstruose cù dati, operanu cù decine di Terabytes, analizà miliardi è trilioni di file di dati.

Per i dui tipi di carichi di travagliu descritti sopra, Snowflake permette di elevà parechji clusters di computer indipendenti di diverse capacità. Inoltre, questi clusters di computing funzionanu indipindentamente, ma cù dati coerenti cumuni.

Per un gran numaru di dumande di luce, pudete elevà 2-3 picculi clusters, circa 2 machini ognunu. Stu cumpurtamentu pò esse implementatu, frà altri cose, usendu paràmetri automatici. Allora dite: "Snowflake, alzate un picculu cluster. Se a carica nantu à questu aumenta sopra à un certu paràmetru, alzà un secondu simili, terzu. Quandu a carica principia à calà, estingue l'eccessu. Cusì chì ùn importa quanti analisti venenu è cumincianu à guardà i rapporti, ognunu hà abbastanza risorse.

À u listessu tempu, se l'analisti dormenu è nimu guarda à i rapporti, i raggruppamenti ponu scurissi cumplettamente, è si ferma di pagà per elli.

À u listessu tempu, per e dumande pisanti (da i Data Scientists), pudete elevà un cluster assai grande per 32 macchine. Stu cluster serà ancu pagatu solu per quelli minuti è l'ore quandu a vostra dumanda gigante hè in esecuzione.

L'uppurtunità descritta sopra permette di dividisce micca solu 2, ma ancu più tippi di carichi di travagliu in clusters (ETL, surviglianza, materializazione di rapportu, ...).

Riassumemu Snowflake. A basa combina una bella idea è una implementazione praticabile. À ManyChat, avemu aduprà Snowflake per analizà tutte e dati chì avemu. Ùn avemu micca trè gruppi, cum'è in l'esempiu, ma da 5 à 9, di diverse dimensioni. Avemu cunvinziunali 16-machine, 2-machine, è ancu super-picculi 1-machine per certi travaglii. Distribuiscenu bè a carica è ci permettenu di salvà assai.

A basa di dati scala cù successu a carica di lettura è scrittura. Questa hè una grande diferenza è un grande avanzu cumparatu cù a stessa "Aurora", chì hà purtatu solu a carica di lettura. Snowflake vi permette di scala a vostra carica di scrittura cù questi clusters di informatica. Questu hè, cum'è l'aghju dettu, avemu usatu parechji clusters in ManyChat, clusters chjuchi è super-picculi sò principarmenti utilizati per ETL, per carica dati. È l'analisti sò digià campatu nantu à clusters mediu, chì ùn sò assolutamente micca affettati da a carica ETL, cusì travaglianu assai rapidamente.

In cunsiquenza, a basa di dati hè bè adattatu per i travaglii OLAP. Tuttavia, sfurtunatamenti, ùn hè ancu applicabile per i carichi di travagliu OLTP. Prima, sta basa di dati hè colonnare, cù tutte e cunsequenze chì seguitanu. Siconda, l'approcciu stessu, quandu per ogni dumanda, se ne necessariu, alzate un cluster di computing è inundate di dati, sfurtunatamenti, ùn hè ancu abbastanza veloce per carichi OLTP. Aspittà seconde per i travaglii OLAP hè normale, ma per i travaglii OLTP hè inacceptable; 100 ms saria megliu, o 10 ms saria ancu megliu.

U risultatu

Una basa di dati senza servitore hè pussibule dividendu a basa di dati in parti Stateless è Stateful. Puderete avè nutatu chì in tutti l'esempii sopra, a parte Stateful hè, relativamente parlante, almacenà micro-partizioni in S3, è Stateless hè l'ottimisatore, travagliendu cù metadati, gestione di prublemi di sicurezza chì ponu esse suscitati cum'è servizii indipindenti senza stati.

L'esecuzione di e dumande SQL pò ancu esse percepite cum'è servizii di u statu di luce chì ponu spuntà in modu senza servitore, cum'è clusters di computing Snowflake, scaricate solu i dati necessarii, eseguite a dumanda è "esce".

E basa di dati di livellu di produzzione senza server sò digià dispunibili per l'usu, sò travagliendu. Queste basa di dati senza servitore sò digià pronte per trattà i travaglii OLAP. Sfurtunatamente, per i travaglii OLTP sò usati... cù sfumature, postu chì ci sò limitazioni. Da una banda, questu hè un minus. Ma, d'altra parte, questu hè una opportunità. Forsi unu di i lettori truverà un modu per fà una basa di dati OLTP completamente senza servitore, senza e limitazioni di Aurora.

Spergu chì avete trovu interessante. Serverless hè u futuru :)

Source: www.habr.com

Add a comment