Turbūt ne paslaptis, kad praėjusieji metai „Apache Hadoop“ buvo didelių pokyčių metai. Pernai „Cloudera“ ir „Hortonworks“ susijungė (iš esmės – pastarosios įsigijimas), o „Mapr“ dėl rimtų finansinių problemų buvo parduotas „Hewlett Packard“. Ir jei prieš kelerius metus vietinių įrenginių atveju dažnai tekdavo rinktis tarp „Cloudera“ ir „Hortonworks“, šiandien, deja, tokio pasirinkimo neturime. Kitas netikėtumas buvo tai, kad šių metų vasarį „Cloudera“ paskelbė, kad nustos platinti dvejetainius rinkinius į viešąją saugyklą, o dabar jie pasiekiami tik per mokamą prenumeratą. Žinoma, vis dar galima atsisiųsti naujausias CDH ir HDP versijas, išleistas iki 2019 metų pabaigos, o jų palaikymo tikimasi nuo vienerių iki dvejų metų. Bet ką daryti toliau? Tiems, kurie anksčiau mokėjo už abonementą, niekas nepasikeitė. O tiems, kurie nenori pereiti prie mokamos platinimo versijos, bet tuo pačiu nori gauti naujausias klasterio komponentų versijas, taip pat pataisas ir kitus atnaujinimus, parengėme šį straipsnį. Jame apsvarstysime galimas išeitis iš šios situacijos.
Straipsnis yra daugiau apžvalga. Jame nebus paskirstymų palyginimo ir išsamios jų analizės, taip pat nebus receptų, kaip juos įdiegti ir konfigūruoti. Kas nutiks? Trumpai pakalbėsime apie tokį platinimą kaip „Arenadata Hadoop“, kuris pagrįstai nusipelno mūsų dėmesio dėl jo prieinamumo, kuris šiandien yra labai retas. Ir tada kalbėsime apie Vanilla Hadoop, daugiausia apie tai, kaip ją galima „virti“ naudojant „Apache Bigtop“. Pasiruošę? Tada sveiki atvykę į katę.
Arenadata Hadoop
Tai visiškai naujas ir kol kas mažai žinomas vietinės plėtros platinimo rinkinys. Deja, šiuo metu Habré yra tik
Daugiau informacijos galite rasti oficialioje svetainėje
Informaciją apie kelio planą rasite
„Arenadata Cluster Manager“ sąsaja
Pagrindinis „Arenadata“ produktas yra
„Hadoop 3“ diegimui ir valdymui kartu su ADCM siūloma rinkinio bendruomenės versija, tačiau „Hadoop 2“ yra tik
Jei kalbėsime apie trūkumus, jie bus tokie patys kaip ir visi kiti Hadoop platinimai. Būtent:
- Vadinamasis „pardavėjo užraktas“. Pasitelkę „Cloudera“ ir „Hortonworks“ pavyzdžius, jau supratome, kad visada yra rizika keisti įmonės politiką.
- Žymiai atsilieka nuo Apache prieš srovę.
Vanilla Hadoop
Kaip žinote, „Hadoop“ nėra monolitinis produktas, o iš tikrųjų visa paslaugų galaktika aplink jos paskirstytą failų sistemą HDFS. Nedaugeliui žmonių pakaks vienos failų grupės. Vieniems reikia Hive, kitiems Presto, o dar yra HBase ir Phoenix; Spark vis dažniau naudojama. Orkestravimui ir duomenų įkėlimui kartais randami Oozie, Sqoop ir Flume. Ir jei iškyla saugumo klausimas, tada į galvą iškart ateina Kerberos kartu su Ranger.
Dvejetaines „Hadoop“ komponentų versijas galima rasti kiekvieno ekosistemos projekto svetainėje tarballų pavidalu. Galite juos atsisiųsti ir pradėti diegti, tačiau su viena sąlyga: be savarankiško paketų surinkimo iš „neapdorotų“ dvejetainių failų, kuriuos greičiausiai norite padaryti, jūs nepasitikėsite atsisiųstų komponentų versijų suderinamumu su kiekviena. kitas. Pageidautina parinktis yra kurti naudojant Apache Bigtop. „Bigtop“ leis jums kurti iš „Apache“ saugyklų, vykdyti testus ir kurti paketus. Bet kas mums labai svarbu, Bigtop surinks tas komponentų versijas, kurios bus suderinamos tarpusavyje. Toliau apie tai kalbėsime plačiau.
Apache Bigtop
„Apache Bigtop“ yra daugelio įrenginių kūrimo, pakavimo ir testavimo įrankis
atvirojo kodo projektus, tokius kaip Hadoop ir Greenplum. Bigtop turi daug
išleidžia. Rašymo metu naujausia stabili versija buvo 1.4 versija,
o meistre buvo 1.5. Skirtingose leidimų versijose naudojamos skirtingos versijos
komponentai. Pavyzdžiui, 1.4 versijos „Hadoop“ pagrindiniai komponentai turi 2.8.5 versiją ir pagrindinę versiją
2.10.0. Taip pat keičiasi palaikomų komponentų sudėtis. Kažkas pasenusio ir
neatsinaujinantis išnyksta, o jo vietoje atsiranda kažkas naujo, paklausesnio ir
tai nebūtinai kažkas iš pačios Apache šeimos.
Be to, Bigtop turi daug
Kai pradėjome susipažinti su Bigtopu, mus visų pirma nustebino kuklus, palyginti su kitais Apache projektais, paplitimas ir žinomumas bei labai maža bendruomenė. Iš to išplaukia, kad informacijos apie produktą yra minimaliai, o problemų, iškilusių forumuose ir adresų sąrašuose, sprendimų paieška gali nieko neduoti. Iš pradžių mums pasirodė sudėtinga užduotis užbaigti visą platinimo surinkimą dėl paties įrankio savybių, tačiau apie tai pakalbėsime šiek tiek vėliau.
Tiems, kurie kažkada domėjosi tokiais Linux visatos projektais kaip Gentoo ir LFS, gali būti nostalgiškai malonu dirbti su šiuo dalyku ir prisiminti tuos „epinius“ laikus, kai mes patys ieškojome (ar net rašėme) atnaujina ir reguliariai perstato „Mozilla“ su naujais pataisymais.
Didelis Bigtop privalumas – įrankių, kuriais jis pagrįstas, atvirumas ir universalumas. Jis pagrįstas „Gradle“ ir „Apache Maven“. „Gradle“ yra gana gerai žinomas kaip įrankis, kurį „Google“ naudoja kurdama „Android“. Jis yra lankstus ir, kaip sakoma, „išbandytas kovoje“. „Maven“ yra standartinis įrankis kuriant projektus pačioje „Apache“, ir kadangi dauguma jo produktų išleidžiami per „Maven“, be jo neapsieitų ir čia. Verta atkreipti dėmesį į POM (projekto objekto modelį) - „pagrindinį“ xml failą, aprašantį viską, ko reikia, kad „Maven“ galėtų dirbti su jūsų projektu, aplink kurį kuriamas visas darbas. Tiksliai prie
Maven dalis ir yra tam tikrų kliūčių, su kuriomis dažniausiai susiduria pirmą kartą „Bigtop“ naudotojai.
Praktika
Taigi nuo ko turėtumėte pradėti? Eikite į atsisiuntimo puslapį ir atsisiųskite naujausią stabilią versiją kaip archyvą. Ten taip pat galite rasti dvejetainių artefaktų, kuriuos surinko Bigtop. Beje, tarp įprastų paketų tvarkyklių palaikomos YUM ir APT.
Arba galite atsisiųsti naujausią stabilią versiją tiesiai iš
github:
$ git clone --branch branch-1.4 https://github.com/apache/bigtop.git
Klonavimas „didžiajame viršuje“…
remote: Enumerating objects: 46, done.
remote: Counting objects: 100% (46/46), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 40217 (delta 14), reused 10 (delta 1), pack-reused 40171
Получение объектов: 100% (40217/40217), 43.54 MiB | 1.05 MiB/s, готово.
Определение изменений: 100% (20503/20503), готово.
Updating files: 100% (1998/1998), готово.
Gautas ./bigtop katalogas atrodo maždaug taip:
./bigtop-bigpetstore
— demonstracinės programos, sintetiniai pavyzdžiai
./bigtop-ci
- CI įrankiai, jenkinai
./bigtop-data-generators
— duomenų generavimas, sintetika, dūmų bandymams ir kt.
./bigtop-deploy
- diegimo įrankiai
./bigtop-packages
- konfigūracijos, scenarijai, surinkimo pataisos, pagrindinė įrankio dalis
./bigtop-test-framework
— testavimo sistema
./bigtop-tests
— patys tyrimai, apkrova ir dūmai
./bigtop_toolchain
— aplinka surinkimui, aplinkos paruošimas įrankiui veikti
./build
- sukurti darbo katalogą
./dl
— atsisiųstų šaltinių katalogas
./docker
— „Docker“ vaizdų kūrimas, testavimas
./gradle
- gradle konfigūracija
./output
– katalogas, į kurį patenka kūrimo artefaktai
./provisioner
- aprūpinimas
Šiame etape mums įdomiausia yra pagrindinė konfigūracija ./bigtop/bigtop.bom
, kuriame matome visus palaikomus komponentus su versijomis. Čia galime nurodyti kitą produkto versiją (jei staiga norime pabandyti jį sukurti) arba kūrimo versiją (jei, pavyzdžiui, pridėjome reikšmingą pataisą).
Pakatalogis taip pat kelia didelį susidomėjimą ./bigtop/bigtop-packages
, kuris yra tiesiogiai susijęs su komponentų ir paketų surinkimo su jais procesu.
Taigi, atsisiuntėme archyvą, išpakavome jį arba sukūrėme kloną iš github, ar galime pradėti kurti?
Ne, pirmiausia paruošime aplinką.
Aplinkos paruošimas
Ir čia mums reikia nedidelio atsitraukimo. Norėdami sukurti beveik bet kurį daugiau ar mažiau sudėtingą produktą, jums reikia tam tikros aplinkos - mūsų atveju tai yra JDK, tos pačios bendrinamos bibliotekos, antraščių failai ir kt., Įrankiai, pavyzdžiui, ant, ivy2 ir daug daugiau. Viena iš galimybių gauti aplinką, kurios jums reikia „Bigtop“, yra įdiegti būtinus komponentus kūrimo priegloboje. Galiu klysti dėl chronologijos, bet atrodo, kad naudojant 1.0 versiją taip pat buvo galimybė įdiegti iš anksto sukonfigūruotus ir prieinamus Docker vaizdus, kuriuos galite rasti čia.
Kalbant apie aplinkos paruošimą, tam yra asistentas - Lėlė.
Galite naudoti šias komandas, paleisti iš šakninio katalogo
įrankis, ./bigtop:
./gradlew toolchain
./gradlew toolchain-devtools
./gradlew toolchain-puppetmodules
Arba tiesiogiai per lėlę:
puppet apply --modulepath=<path_to_bigtop> -e "include bigtop_toolchain::installer"
puppet apply --modulepath=<path_to_bigtop> -e "include bigtop_toolchain::deployment-tools"
puppet apply --modulepath=<path_to_bigtop> -e "include bigtop_toolchain::development-tools"
Deja, jau šiame etape gali kilti sunkumų. Bendras patarimas čia yra naudoti palaikomą platinimą, atnaujintą kūrimo priegloboje arba išbandyti doko maršrutą.
Asamblėja
Ką galime pabandyti surinkti? Atsakymą į šį klausimą pateiks komandos išvestis
./gradlew tasks
Skiltyje „Paketo užduotys“ yra keletas produktų, kurie yra galutiniai „Bigtop“ artefaktai.
Juos galima atpažinti pagal priesagą -rpm arba -pkg-ind (pastato atveju
dokeryje). Mūsų atveju įdomiausias yra „Hadoop“.
Pabandykime sukurti savo kūrimo serverio aplinkoje:
./gradlew hadoop-rpm
Pats „Bigtop“ atsisiųs reikiamus šaltinius, reikalingus konkrečiam komponentui, ir pradės surinkti. Taigi, įrankio veikimas priklauso nuo Maven saugyklų ir kitų šaltinių, tai yra, jam reikalinga interneto prieiga.
Veikimo metu sukuriama standartinė išvestis. Kartais jis ir klaidų pranešimai gali padėti suprasti, kas nutiko. Ir kartais reikia gauti papildomos informacijos. Šiuo atveju verta pridėti argumentų --info
arba --debug
, taip pat gali būti naudinga –stacktrace
. Yra patogus būdas sugeneruoti duomenų rinkinį vėlesnei prieigai prie adresų sąrašų, raktas --scan
.
Su jo pagalba bigtop surinks visą informaciją ir įdės į gradle, po to pateiks nuorodą,
ja vadovaudamasis kompetentingas asmuo galės suprasti, kodėl surinkimas nepavyko.
Atminkite, kad ši parinktis gali atskleisti informaciją, kurios nenorite, pvz., naudotojų vardus, mazgus, aplinkos kintamuosius ir kt., todėl būkite atsargūs.
Dažnai klaidos atsiranda dėl to, kad nepavyksta gauti jokių surinkimui reikalingų komponentų. Paprastai problemą galite išspręsti sukurdami pataisą, kad ką nors pataisytumėte šaltiniuose, pvz., adresus pom.xml šaltinio šakniniame kataloge. Tai atliekama sukuriant ir įdedant jį į atitinkamą katalogą ./bigtop/bigtop-packages/src/common/oozie/
pleistras, pavyzdžiui, formoje patch2-fix.diff.
--- a/pom.xml
+++ b/pom.xml
@@ -136,7 +136,7 @@
<repositories>
<repository>
<id>central</id>
- <url>http://repo1.maven.org/maven2</url>
+ <url>https://repo1.maven.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
Labiausiai tikėtina, kad skaitydami šį straipsnį jums nereikės patiems atlikti pirmiau minėtų taisymų.
Įvedant bet kokius surinkimo mechanizmo pataisymus ir pakeitimus, gali tekti „iš naujo nustatyti“ surinkimą naudojant valymo komandą:
./gradlew hadoop-clean
> Task :hadoop_vardefines
> Task :hadoop-clean
BUILD SUCCESSFUL in 5s
2 actionable tasks: 2 executed
Ši operacija atšauks visus šio komponento surinkimo pakeitimus, o po to surinkimas bus atliktas dar kartą. Šį kartą pabandysime sukurti projektą „Docker“ atvaizde:
./gradlew -POS=centos-7 -Pprefix=1.2.1 hadoop-pkg-ind
> Task :hadoop-pkg-ind
Building 1.2.1 hadoop-pkg on centos-7 in Docker...
+++ dirname ./bigtop-ci/build.sh
++ cd ./bigtop-ci/..
++ pwd
+ BIGTOP_HOME=/tmp/bigtop
+ '[' 6 -eq 0 ']'
+ [[ 6 -gt 0 ]]
+ key=--prefix
+ case $key in
+ PREFIX=1.2.1
+ shift
+ shift
+ [[ 4 -gt 0 ]]
+ key=--os
+ case $key in
+ OS=centos-7
+ shift
+ shift
+ [[ 2 -gt 0 ]]
+ key=--target
+ case $key in
+ TARGET=hadoop-pkg
+ shift
+ shift
+ [[ 0 -gt 0 ]]
+ '[' -z x ']'
+ '[' -z x ']'
+ '[' '' == true ']'
+ IMAGE_NAME=bigtop/slaves:1.2.1-centos-7
++ uname -m
+ ARCH=x86_64
+ '[' x86_64 '!=' x86_64 ']'
++ docker run -d bigtop/slaves:1.2.1-centos-7 /sbin/init
+
CONTAINER_ID=0ce5ac5ca955b822a3e6c5eb3f477f0a152cd27d5487680f77e33fbe66b5bed8
+ trap 'docker rm -f
0ce5ac5ca955b822a3e6c5eb3f477f0a152cd27d5487680f77e33fbe66b5bed8' EXIT
....
много вывода
....
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-hdfs-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-yarn-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-mapreduce-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-hdfs-namenode-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-hdfs-secondarynamenode-2.8.5-
1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-hdfs-zkfc-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-hdfs-journalnode-2.8.5-
1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-hdfs-datanode-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-httpfs-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-yarn-resourcemanager-2.8.5-
1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-yarn-nodemanager-2.8.5-
1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-yarn-proxyserver-2.8.5-
1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-yarn-timelineserver-2.8.5-
1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-mapreduce-historyserver-2.8.5-
1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-client-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-conf-pseudo-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-doc-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-libhdfs-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-libhdfs-devel-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-hdfs-fuse-2.8.5-1.el7.x86_64.rpm
Wrote: /bigtop/build/hadoop/rpm/RPMS/x86_64/hadoop-debuginfo-2.8.5-1.el7.x86_64.rpm
+ umask 022
+ cd /bigtop/build/hadoop/rpm//BUILD
+ cd hadoop-2.8.5-src
+ /usr/bin/rm -rf /bigtop/build/hadoop/rpm/BUILDROOT/hadoop-2.8.5-1.el7.x86_64
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.uQ2FCn
+ exit 0
+ umask 022
Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.CwDb22
+ cd /bigtop/build/hadoop/rpm//BUILD
+ rm -rf hadoop-2.8.5-src
+ exit 0
[ant:touch] Creating /bigtop/build/hadoop/.rpm
:hadoop-rpm (Thread[Task worker for ':',5,main]) completed. Took 38 mins 1.151 secs.
:hadoop-pkg (Thread[Task worker for ':',5,main]) started.
> Task :hadoop-pkg
Task ':hadoop-pkg' is not up-to-date because:
Task has not declared any outputs despite executing actions.
:hadoop-pkg (Thread[Task worker for ':',5,main]) completed. Took 0.0 secs.
BUILD SUCCESSFUL in 40m 37s
6 actionable tasks: 6 executed
+ RESULT=0
+ mkdir -p output
+ docker cp
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb:/bigtop/build .
+ docker cp
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb:/bigtop/output .
+ docker rm -f ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
+ '[' 0 -ne 0 ']'
+ docker rm -f ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
Error: No such container:
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
BUILD SUCCESSFUL in 41m 24s
1 actionable task: 1 executed
Konstravimas buvo atliktas naudojant „CentOS“, bet taip pat gali būti atliktas naudojant „Ubuntu“:
./gradlew -POS=ubuntu-16.04 -Pprefix=1.2.1 hadoop-pkg-ind
Be įvairių Linux platinimų paketų kūrimo, įrankis gali sukurti saugyklą su kompiliuotais paketais, pavyzdžiui:
./gradlew yum
Taip pat galite prisiminti apie dūmų bandymus ir diegimą „Docker“.
Sukurkite trijų mazgų grupę:
./gradlew -Pnum_instances=3 docker-provisioner
Atlikite dūmų testus trijų mazgų grupėje:
./gradlew -Pnum_instances=3 -Prun_smoke_tests docker-provisioner
Ištrinti grupę:
./gradlew docker-provisioner-destroy
Gaukite komandas, skirtas prijungti vidinius doko konteinerius:
./gradlew docker-provisioner-ssh
Rodyti būseną:
./gradlew docker-provisioner-status
Daugiau apie diegimo užduotis galite perskaityti dokumentacijoje.
Jei kalbėtume apie testus, jų yra gana daug, daugiausia dūmų ir integracijos. Jų analizė nepatenka į šio straipsnio taikymo sritį. Leiskite pasakyti, kad paskirstymo rinkinio surinkimas nėra toks sudėtingas uždavinys, kaip gali pasirodyti iš pirmo žvilgsnio. Pavyko surinkti ir išlaikyti visų gamyboje naudojamų komponentų testus, taip pat neturėjome problemų juos diegiant ir atliekant pagrindines operacijas bandomojoje aplinkoje.
Be esamų Bigtop komponentų, galima pridėti dar ką nors, net ir savo programinės įrangos kūrimo. Visa tai puikiai automatizuota ir tinka CI/CD koncepcijai.
išvada
Akivaizdu, kad tokiu būdu sudarytas paskirstymas neturėtų būti nedelsiant išsiųstas į gamybą. Turite suprasti, kad jei yra tikras poreikis kurti ir palaikyti savo platinimą, turite į tai investuoti pinigus ir laiką.
Tačiau kartu su tinkamu požiūriu ir profesionalia komanda visiškai įmanoma apsieiti be komercinių sprendimų.
Svarbu pažymėti, kad pats projektas „Bigtop“ turi būti tobulinamas ir, atrodo, šiandien nėra aktyviai plėtojamas. Taip pat neaiški „Hadoop 3“ pasirodymo perspektyva. Beje, jei tikrai reikia sukurti „Hadoop 3“, galite pasižiūrėti
Yra keletas papildomų komponentų (Ranger, Knox, NiFi).
Kalbant apie Rostelecom, mums Bigtop yra viena iš šiandien svarstomų variantų. Pasirinksime ar ne, parodys laikas.
Priedas
Norėdami įtraukti naują komponentą į rinkinį, turite pridėti jo aprašymą į bigtop.bom ir ./bigtop-packages. Galite pabandyti tai padaryti pagal analogiją su esamais komponentais. Pabandykite tai išsiaiškinti. Tai nėra taip sunku, kaip atrodo iš pirmo žvilgsnio.
Ką tu manai? Mums bus malonu pamatyti jūsų nuomonę komentaruose ir dėkojame už dėmesį!
Straipsnį parengė Rostelecom duomenų valdymo komanda
Šaltinis: www.habr.com