Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Алексей Найденов, гүйцэтгэх захирал ITooLabs, Go (Golang) програмчлалын хэлээр харилцаа холбооны операторуудад зориулсан харилцаа холбооны платформыг хөгжүүлэх тухай ярьж байна. Алексей мөн энэхүү платформыг дуут шуудан (VoiceMail) болон Virtual PBX (Cloud PBX) үйлчилгээ үзүүлэхэд ашигласан Азийн томоохон харилцаа холбооны операторуудын нэгд уг платформыг ашиглаж, ажиллуулж байсан туршлагаа хуваалцаж байна.

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Алексей Найденов (цаашид - А.Н.): - Сайн уу! Намайг Алексей Найденов гэдэг. Би ITooLabs-ийн захирал. Юуны өмнө би энд юу хийж яваа, яаж энд ирснээ хариулмаар байна.

Хэрэв та Bitrix24 зах зээлийг ("Утас" хэсэг) харвал 14 програм, тэнд байгаа 36 (40%) нь бид байна:

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Илүү нарийвчлалтай хэлэхэд эдгээр нь бидний түнш операторууд боловч энэ бүхний ард бидний платформ (Үйлчилгээний платформ) байдаг - бид тэдэнд бага зоосоор зардаг. Ер нь энэ платформын хөгжил, Go-д хэрхэн ирсэн тухай яримаар байна.

Одоо манай платформын тоонууд:

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

MegaFon зэрэг 44 түнш оператор. Ерөнхийдөө бид адал явдалд оролцох дуртай бөгөөд Оросын 100 операторын 44 сая хэрэглэгчдэд хандах боломжтой. Тиймээс, хэн нэгэнд бизнесийн санаа байгаа бол бид түүнийг сонсохдоо үргэлж баяртай байдаг.

  • 5000 хэрэглэгч компани.
  • Нийт 20 захиалагч. Энэ бүхэн b000b - бид зөвхөн компаниудтай ажилладаг.
  • Өдөрт минутанд 300 дуудлага.
  • Өнгөрсөн жил 100 сая дуудлагын минут (бид тэмдэглэсэн). Энэ нь манай мөрийн хөтөлбөрт тусгагдсан дотоод хэлэлцээг харгалзаагүй явдал юм.

Яаж эхэлсэн бэ?

Зөв залуус хэрхэн өөрсдийн платформыг хийж эхэлдэг вэ? Бид "хатуу аж ахуйн нэгж"-ийг хөгжүүлж байсан түүхтэй, тэр ч байтугай тухайн аж ахуйн нэгжийн хувьд жилийн хамгийн зөв цагт байсныг анхаарч үзэх хэрэгтэй! Үйлчлүүлэгч дээрээ ирээд "Бидэнд дахиад хэдэн сервер хэрэгтэй байна" гэж хэлэх тэр л аз жаргалтай үе байсан. Мөн үйлчлүүлэгч: "Тийм ээ, асуулт байхгүй! Бидэнд арав байгаа.

Тиймээс бид Oracle, Java, WebSphere, Db2 гэх мэт бүгдийг хийсэн. Тиймээс бид мэдээжийн хэрэг хамгийн сайн борлуулагч шийдлүүдийг авч, тэдгээрийг нэгтгэж, үүнтэй хамт гарахыг хичээсэн. Тэд өөрсдөө тоглосон. Ийм дотоод гарааны бизнес байх болно.

Энэ бүхэн 2009 онд эхэлсэн. 2006 оноос хойш бид ямар нэг байдлаар операторын шийдвэрт ойр дотно оролцож ирсэн. Бид хэд хэдэн захиалгат виртуал PBX хийсэн (одоогоор захиалж байгаа зүйл гэх мэт): бид харж, үүнийг сайн гэж үзээд дотоод стартапыг эхлүүлэхээр шийдсэн.

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

VMWare-г аваарай. Бид ганцаараа алхаж байсан тул бид нэн даруй сэрүүн худалдагч Storage-г орхих хэрэгтэй болсон. Бид тэдний тухай бүгдийг мэднэ: амлалтуудыг 3-т хувааж, зардлыг 10-аар үржүүлэх ёстой. Тиймээс бид DirDB гэх мэт.

Дараа нь энэ нь өсч эхэлсэн. Платформ нь даахаа больсон тул төлбөрийн үйлчилгээг үүн дээр нэмсэн. Дараа нь MySQL-ийн тооцооны сервер Mongo руу шилжсэн. Үүний үр дүнд бид тэнд ирж буй бүх дуудлагыг боловсруулдаг ажлын шийдэлтэй болсон.

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Гэхдээ хаа нэгтээ, дотор нь ижил борлуулагч бүтээгдэхүүн эргэлдэж байна - бидний нэг удаа авч байсан цөмийн гол бүтээгдэхүүн. Ойролцоогоор 2011 оны эцэс гэхэд бидний хувьд гол бэрхшээл нь мэдээжийн хэрэг энэ бүтээгдэхүүн байх болно гэдгийг бид өөрсдөө ойлгосон - бид үүнтэй тулгарах болно. Үйлчлүүлэгчид алхаж байхад бидний урдуур гүйх хана нэмэгдэж байгааг бид харав.
Үүний дагуу бид ямар нэгэн зүйл хийх ёстой байсан. Мэдээжийн хэрэг, бид янз бүрийн бүтээгдэхүүний талаар маш их судалгаа хийсэн - нээлттэй эх сурвалж болон борлуулагчийн аль алинд нь. Би одоо энэ талаар ярихгүй - энэ бол гол зүйл биш юм. Бидний бодож байсан хамгийн сүүлчийн нөөц бол өөрсдийн платформыг хийх явдал байв.

Эцсийн эцэст бид энэ сонголт дээр ирлээ. Яагаад? Учир нь бүх борлуулагч болон нээлттэй эхийн бүтээгдэхүүнийг 10 жилийн өмнө асуудлыг шийдэхийн тулд хийсэн. За, хэрэв 10 настай бол, мөн зарим нь илүү! Сонголт нь бидний хувьд тодорхой болсон: эсвэл бид хамгийн тохиромжтой үйлчилгээний талаархи гайхалтай санаагаа баяртай гэж хэлэх (хамтрагчид, операторууд болон өөрсдөдөө) эсвэл бид өөрсдөө ямар нэг зүйл хийх болно.

Бид өөр зүйл хийхээр шийдсэн!

Платформын шаардлага

Хэрэв та ямар нэг зүйлийг удаан хугацаагаар хийвэл (өөр хэн нэгний бүтээгдэхүүнийг ашигладаг бол) таны толгойд аажмаар "би үүнийг өөрөө яаж хийх вэ?" гэсэн бодол бий болно. Бид бүгд компанид програмистууд (худалдагчаас бусад нь програмист бус хүмүүс байдаггүй) тул бидний шаардлага нэлээд удаан хугацаанд бий болсон бөгөөд тэдгээр нь тодорхой байсан:

  1. Хөгжлийн өндөр хурд. Биднийг зовоож байсан худалдагчийн бүтээгдэхүүн анхнаасаа бидэнд тохирохгүй байсан, учир нь бүх зүйл удаан, удаанаар бүтсэн. Бид хурдан хүссэн - бидэнд маш олон санаа байсан! Бидэнд маш олон санаа байгаа ч дараа нь санааны жагсаалт нь арван жилийн өмнө юм шиг санагдсан. Одоо зөвхөн нэг жил.
  2. Олон судалтай төмрийн хамгийн их хэрэглээ. Энэ нь бидний хувьд бас чухал байсан, учир нь бид зөвхөн илүү олон цөм байх болно гэдгийг харсан.
  3. Өндөр найдвартай байдал. Бид ч бас уйлсан.
  4. Гэмтлийг тэсвэрлэх чадвар өндөр.
  5. Бид өдөр бүр гаргах үйл явцыг дуусгахыг хүссэн. Үүний тулд бидэнд хэлний сонголт хэрэгтэй байсан.

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Үүний дагуу, бидний өөрсдөдөө танилцуулсан бүтээгдэхүүнд тавигдах шаардлагуудаас харахад хэлний шаардлага нь тодорхой логик хэлбэрээр өсч байна.

  1. Хэрэв бид олон цөмт системд дэмжлэг үзүүлэхийг хүсч байвал зэрэгцээ гүйцэтгэлийн дэмжлэг хэрэгтэй болно.
  2. Бидэнд хөгжлийн хурд хэрэгтэй бол өрсөлдөх чадвартай хөгжил, өрсөлдөх чадвартай програмчлалыг дэмждэг хэл хэрэгтэй. Хэрэв хэн нэгэн ялгааг олж үзээгүй бол энэ нь маш энгийн:
    • зэрэгцээ програмчлал нь хоёр өөр утас өөр цөм дээр хэрхэн ажилладаг тухай;
    • Зэрэгцээ гүйцэтгэл, тодруулбал concurrency дэмжлэг гэдэг нь хэл (эсвэл ажиллах хугацаа гэх мэт) зэрэгцээ гүйцэтгэлээс үүсэх бүх нарийн төвөгтэй байдлыг нуухад хэрхэн тусалдаг тухай юм.
  3. Өндөр тогтвортой байдал. Мэдээжийн хэрэг, бидэнд кластер хэрэгтэй байсан бөгөөд энэ нь үйлдвэрлэгчийн бүтээгдэхүүнээс илүү дээр байсан.

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Хэрэв та санаж байгаа бол бидэнд үнэхээр олон сонголт байгаагүй. Нэгдүгээрт, Эрлан - бид үүнд дуртай бөгөөд үүнийг мэддэг, энэ бол миний хувийн, хувийн дуртай зүйл байсан. Хоёрдугаарт, Java бол Java ч биш, ялангуяа Scala юм. Гуравдугаарт, тэр үед бидний огт мэддэггүй байсан хэл - Яв. Тэр үед дөнгөж гарч ирсэн, бүр тодруулбал, аль хэдийн хоёр жил орчим байсан ч хараахан гараагүй байсан.

Ялагдсан Go!

Go-ийн түүх

Бид үүн дээр тавцан хийсэн. Би яагаад гэдгийг тайлбарлахыг хичээх болно.

Go-ийн товч түүх. 2007 онд эхэлсэн, 2009 онд нээгдсэн, анхны хувилбар нь 2012 онд гарсан (өөрөөр хэлбэл бид анхны хувилбараас өмнө ажиллаж эхэлсэн). Санаачлагч нь Google байсан бөгөөд миний таамаглаж байгаагаар Java-г солихыг хүссэн.

Зохиогчид маш алдартай:

  • Unix-ийн ард байсан Кен Томсон UTF-8-ийг зохион бүтээж, Төлөвлөгөө 9 систем дээр ажилласан;
  • Кентэй хамтран UTF-8-ийг зохион бүтээсэн Роб Пайк мөн Bell Labs-д 9-р төлөвлөгөө, Inferno, Limbo дээр ажилласан;
  • Java HotSpot Compiler-ийг зохион бүтээж, V8 (Google-ийн Javascript орчуулагч) дээр ажиллаж байсан Роберт Гизмер бидний мэддэг, хайртай;
  • Мөн бидний зарим засваруудыг оруулаад 700 гаруй хувь нэмэр оруулагчид.

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Нэг харцаар яв

Хэл нь багагүй энгийн, ойлгомжтой гэдгийг бид харж байна. Бидэнд тодорхой төрлүүд бий: зарим тохиолдолд тэдгээрийг зарлах шаардлагатай байдаг, зарим тохиолдолд зарладаггүй (төрлүүд нь ямар ч байсан дүгнэлт хийдэг гэсэн үг).

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Бүтцийг дүрслэх нь моод болсон нь харагдаж байна. Эндээс харахад бидэнд заагч (од тэмдэг хаана байгаа) гэсэн ойлголт байдаг. Массив болон ассоциатив массивуудын эхлэлийг зарлахад тусгай дэмжлэг байгаа нь харагдаж байна.

Ойролцоогоор ойлгомжтой - та амьдарч чадна. Сайн уу, дэлхий ертөнцийг бичих гэж оролдож байна:

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Бид юу харж байна вэ? Энэ нь C-тэй төстэй синтакс бөгөөд цэг таслал нь сонголттой. Энэ нь хоёр мөрийг тусгаарлах боломжтой, гэхдээ эдгээр нь яг нэг мөрөнд байгаа хоёр бүтэц байвал л болно.

Хяналтын бүтэц дэх хаалтууд (14-р мөрөнд) заавал байх ёстой боловч буржгар нь үргэлж шаардлагатай байдаг гэдгийг бид харж байна. Бид бичих нь хөдөлгөөнгүй байгааг харж байна. Ихэнх тохиолдолд Тим харагдана. Энэ жишээ нь ердийн "Сайн уу, ертөнц"-ээс арай илүү төвөгтэй юм - зүгээр л номын сан байгаа гэдгийг харуулахын тулд.

Бид өөр юу чухал гэж харж байна вэ? Кодыг багц болгон зохион байгуулдаг. Багцыг өөрийн кодоор ашиглахын тулд та импортын удирдамжийг ашиглан импортлох хэрэгтэй - энэ нь бас чухал юм. Бид эхэлдэг - энэ нь ажилладаг. Агуу их!

Илүү төвөгтэй зүйлийг туршиж үзье: Сайн уу, дэлхий, гэхдээ энэ нь http сервер юм. Эндээс бид юу сонирхолтой байна вэ?

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Нэгдүгээрт, функц нь параметрийн үүрэг гүйцэтгэдэг. Энэ нь бидэнд байгаа функц нь "нэгдүгээр зэрэглэлийн иргэн" бөгөөд та үүнтэй хамт олон сонирхолтой зүйлийг функциональ хэв маягаар хийж чадна гэсэн үг юм. Дараа нь бид гэнэтийн зүйлийг харж байна: импортын заавар нь GitHub репозиторыг шууд хэлдэг. Энэ нь зөв, ийм байна - үүнээс гадна, үүнийг хийх ёстой.

Go-д багцын бүх нийтийн танигч нь түүний агуулахын URL юм. Бүх хамаарал дээр очиж, татаж аваад суулгаж, эмхэтгэж, шаардлагатай бол ашиглахад бэлтгэдэг тусгай Goget хэрэгсэл байдаг. Үүний зэрэгцээ, Гогет html-meta-ийн талаар мэддэг. Үүний дагуу та http лавлахыг хадгалах боломжтой бөгөөд энэ нь таны тусгай репозиторын холбоосыг агуулсан байх болно (жишээлбэл, бидний хийдэг шиг).

Бид өөр юу харж байна вэ? Энгийн номын сан дахь Http болон Json. Мэдээжийн хэрэг, дотогшоо харах - тусгал байдаг бөгөөд үүнийг кодчилол / json-д ашиглах ёстой, учир нь бид зүгээр л дурын объектыг орлуулдаг.

Бид үүнийг ажиллуулаад машины одоогийн дундаж ачааллыг (ажиллаж байгаа машин дээр) эмхэтгэж, ажиллуулж, өгдөг 20 мөр хэрэгтэй код байгааг харж байна.
Эндээс нэн даруй харж чадах зүйлээс өөр юу чухал вэ? Энэ нь нэг статик хоёртын файлд (buinary) хөрвүүлдэг. Энэ хоёртын файлд ямар ч хамаарал байхгүй, номын сан байхгүй! Үүнийг ямар ч системд хуулж, шууд ажиллуулж болно, энэ нь ажиллах болно.

Бид цаашаа.

Go: аргууд ба интерфейсүүд

Go-д аргууд бий. Та ямар ч захиалгат төрлийн аргыг зарлаж болно. Түүнээс гадна, энэ нь бүтэц байх албагүй, гэхдээ зарим төрлийн нэр байж болно. Та N32-д өөр нэр зарлаж, түүнд хэрэгтэй зүйл хийх аргуудыг бичиж болно.

Эндээс бид анх удаа тэнэгтэж байна ... Го-д ийм хичээл байдаггүй нь харагдаж байна. Go-г мэддэг хүмүүс төрөл оруулах гэж хэлж болох ч энэ нь огт өөр юм. Хөгжүүлэгч үүнийг өв залгамжлал гэж үзэхээ аль болох хурдан зогсоох тусам сайн. Go-д анги байхгүй, өв залгамжлал ч байхгүй.

Асуулт! Google тэргүүтэй зохиолчдын компани дэлхийн нарийн төвөгтэй байдлыг харуулахын тулд бидэнд юу өгсөн бэ? Бидэнд интерфэйс өгсөн!

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

Интерфэйс нь энгийн аргууд, аргын гарын үсэг бичих боломжийг олгодог тусгай төрөл юм. Цаашилбал, эдгээр аргууд байдаг (гүйцсэн) ямар ч төрөл энэ интерфейстэй тохирно. Энэ нь та зүгээр л нэг төрөлд, нөгөө төрөлд (тэр интерфэйсийн төрөлд тохирох) тохирох функцийг бичиж болно гэсэн үг юм. Дараа нь энэ интерфэйсийн төрлийн хувьсагчийг зарлаж, эдгээр объектуудын аль нэгийг түүнд онооно.

Хардкор фэнүүдийн хувьд энэ хувьсагч нь үнэндээ хоёр заагчийг агуулна гэж би хэлж чадна: нэг нь өгөгдөл, нөгөө нь энэ төрлийн тусгай тодорхойлогч хүснэгт, энэ төрлийн интерфейс. Өөрөөр хэлбэл, хөрвүүлэгч нь холбох үед ийм тодорхойлогчдын хүснэгтүүдийг хийдэг.

Мэдээжийн хэрэг, Go-д хүчингүй болгох заалтууд байдаг. Интерфейс {} (хоёр буржгар хаалттай) гэдэг үг нь зарчмын хувьд ямар ч объект руу чиглүүлэх боломжийг олгодог хувьсагч юм.
Одоогоор бүх зүйл эмх цэгцтэй, бүх зүйл танил болсон. Гайхах зүйл алга.

Яв: горутинууд

Одоо бид сонирхож буй зүйл рүүгээ орлоо: хөнгөн процессууд - Go-ийн нэр томъёонд goroutines (goroutines).

Алексей Найденов. ITooLabs. Go (Golang) утасны платформ дээрх хөгжүүлэлтийн хэрэг. 1-р хэсэг

  1. Нэгдүгээрт, тэд үнэхээр хөнгөн жинтэй (2 Кб-аас бага).
  2. Хоёрдугаарт, ийм гороутин бүтээх зардал нь өчүүхэн юм: та секундэд мянга мянган ширхэгийг үүсгэж болно - юу ч болохгүй.
  3. Тэдэнд өөрсдийн хуваарь гаргагчаар үйлчилдэг бөгөөд энэ нь удирдлагыг нэг горотинээс нөгөөд шилжүүлдэг.
  4. Энэ тохиолдолд хяналтыг дараахь тохиолдолд шилжүүлнэ.
    • хэрэв go мэдэгдэлтэй тулгарвал (хэрэв горутин дараагийн горутиныг эхлүүлбэл);
    • хаах оролт/гаралтын дуудлагыг идэвхжүүлсэн бол;
    • хэрэв хог цуглуулах ажиллагаа идэвхжсэн бол;
    • хэрэв сувагтай зарим үйл ажиллагаа эхэлсэн бол.

Өөрөөр хэлбэл, Go програмыг компьютер дээр ажиллуулах бүрд энэ нь систем дэх цөмүүдийн тоог илрүүлж, шаардлагатай тооны хэлхээг эхлүүлдэг (системд хэдэн цөм байгаа эсвэл та хэд гэж хэлсэн). Үүний дагуу хуваарь гаргагч нь эдгээр бүх үйлдлийн системийн хэлхээнүүд дээр эдгээр хөнгөн жингийн гүйцэтгэлийн хэлхээг цөм тус бүр дээр ажиллуулна.

Энэ нь төмрийг ашиглах хамгийн үр дүнтэй арга гэдгийг тэмдэглэх нь зүйтэй. Бидний үзүүлсэн зүйлээс гадна бид маш их зүйлийг хийдэг. Жишээлбэл, бид нэг нэгжид 40 гигабит үйлчлэх боломжийг олгодог DPI системийг (эдгээр мөрөнд юу болж байгаагаас хамаарч) хийдэг.

Тэнд, Go-ээс өмнө ч гэсэн бид яг ийм схемийг яг ийм шалтгаанаар ашигласан: учир нь энэ нь процессорын кэшийн байршлыг хадгалах, үйлдлийн системийн контекст шилжүүлэгчийн тоог мэдэгдэхүйц багасгах боломжийг олгодог (энэ нь маш удаан хугацаа шаарддаг). Би давтан хэлэхэд энэ бол төмрийг ашиглах хамгийн үр дүнтэй арга юм.

Энэхүү энгийн 21 мөрийн жишээ нь зүгээр л цуурай сервер хийдэг жишээ юм. Үүний зэрэгцээ, үйлчлэх функц нь маш энгийн, шугаман гэдгийг анхаарна уу. Эргээд залгах гэж байхгүй, санаа зоволтгүй, бодох ч хэрэггүй... Та зүгээр л уншиж бичээрэй!

Үүний зэрэгцээ, хэрэв та уншиж, бичиж байвал энэ нь үнэхээр хаагдах ёстой - энэ gooutine-г зүгээр л дараалалд оруулж, гүйцэтгэл дахин боломжтой болсон үед төлөвлөгч авдаг. Өөрөөр хэлбэл, энэ энгийн код нь энэ машин дээрх үйлдлийн систем зөвшөөрөгдсөн олон холболтын цуурай серверийн үүрэг гүйцэтгэдэг.

Үргэлжлэл тун удахгүй...

Зарим зар 🙂

Бидэнтэй хамт байсанд баярлалаа. Манай нийтлэл танд таалагдаж байна уу? Илүү сонирхолтой контент үзэхийг хүсч байна уу? Захиалга өгөх эсвэл найзууддаа санал болгох замаар биднийг дэмжээрэй, 4.99 доллараас эхлэн хөгжүүлэгчдэд зориулсан үүлэн VPS, Бидний танд зориулж бүтээсэн анхны түвшний серверүүдийн өвөрмөц аналоги: VPS (KVM) E5-2697 v3 (6 цөм) 10GB DDR4 480GB SSD 1Gbps-ийн 19 ам.долларын үнэ эсвэл серверийг хэрхэн хуваалцах тухай бүх үнэн үү? (RAID1 болон RAID10, 24 хүртэлх цөм, 40 ГБ хүртэл DDR4-тэй байх боломжтой).

Амстердам дахь Equinix Tier IV дата төвд Dell R730xd 2 дахин хямд байна уу? Зөвхөн энд 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ 199 доллараас Нидерландад! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - 99 доллараас! тухай уншина уу Дэд бүтцийн корпорацийг хэрхэн барих вэ. нэг пенни нь 730 еврогийн үнэтэй Dell R5xd E2650-4 v9000 сервер ашиглах анги?

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх