Naon anu urang terang ngeunaan microservices

Halo! Nami abdi Vadim Madison, abdi nuju ngembangkeun Avito System Platform. Kumaha urang di parusahaan nu pindah ti arsitéktur monolithic kana microservice geus ngadawuh leuwih ti sakali. Waktosna pikeun ngabagi kumaha urang ngarobih infrastruktur urang pikeun ngamangpaatkeun microservices sareng henteu leungit di dinya. Kumaha PaaS ngabantosan kami di dieu, kumaha urang nyederhanakeun panyebaran sareng ngirangan nyiptakeun microservice kana hiji klik - baca deui. Henteu sadayana anu kuring nyerat di handap ieu dilaksanakeun pinuh di Avito, bagian tina éta kumaha urang ngembangkeun platform kami.

(Jeung di ahir artikel ieu, kuring bakal ngobrol ngeunaan kasempetan pikeun meunang ka seminar tilu poé ti ahli dina arsitektur microservice, Chris Richardson).

Naon anu urang terang ngeunaan microservices

Kumaha urang sumping ka microservices

Avito mangrupakeun salah sahiji classifieds pangbadagna di dunya, eta publishes leuwih ti 15 juta Iklan anyar per poé. Backend kami nampi langkung ti 20 rébu pamundut per detik. Ayeuna urang gaduh sababaraha ratus microservices.

Kami parantos ngawangun arsitéktur microservice langkung ti sataun. Kumaha kahayang - kolega urang di jéntré ngawartosan di bagian kami di RIT ++ 2017. Di CodeFest 2017 (tingali видео), Sergey Orlov sareng Mikhail Prokopchuk ngajelaskeun sacara rinci naha urang peryogi transisi ka microservices sareng naon peran Kubernetes di dieu. Nya, ayeuna urang ngalakukeun sadayana pikeun ngaminimalkeun biaya skala anu aya dina arsitektur sapertos kitu.

Mimitina, kami henteu nyiptakeun ékosistem anu sacara komprehensif bakal ngabantosan kami dina pamekaran sareng peluncuran jasa mikro. Aranjeunna kakara ngumpulkeun solusi open source pinter, ngaluncurkeunana di bumi sareng nawiskeun pamekar pikeun nungkulanana. Hasilna, manéhna indit ka belasan tempat (dashboards, jasa internal), nu satutasna anjeunna strengthened kahayang pikeun motong kode dina cara heubeul, dina monolith a. Warna héjo dina diagram di handap ieu nunjukkeun naon pamekar teu salah sahiji cara atawa sejen kalawan leungeun-Na sorangan, warna konéng nunjukkeun automation.

Naon anu urang terang ngeunaan microservices

Ayeuna, dina utilitas PaaS CLI, hiji tim nyiptakeun layanan énggal, sareng dua deui nambihan pangkalan data énggal sareng nyebarkeun ka Stage.

Naon anu urang terang ngeunaan microservices

Kumaha carana nungkulan era "fragméntasi microservice"

Kalayan arsitéktur monolithic, demi konsistensi parobahan dina produk, pamekar kapaksa terang naon anu lumangsung sareng tatanggana. Nalika damel dina arsitéktur énggal, kontéks jasa henteu gumantung deui.

Sajaba ti éta, pikeun arsitéktur microservice éféktif, perlu pikeun ngadegkeun loba prosés, nyaéta:

• logging;
• nyukcruk pamundut (Jaeger);
• aggregation kasalahan (Sentry);
• status, talatah, kajadian ti Kubernetes (Proses Aliran Acara);
• wates lomba / circuit breaker (Anjeun tiasa make Hystrix);
• kontrol konektipitas jasa (urang make Netramesh);
• ngawaskeun (Grafana);
• assembly (TeamCity);
• komunikasi jeung bewara (Slack, email);
• tracking tugas; (Jira)
• persiapan dokuméntasi.

Pikeun mastikeun yén sistem henteu leungit integritas sareng tetep épisién nalika skala, urang mikirkeun deui organisasi microservices di Avito.

Kumaha urang ngatur microservices

Avito ngabantosan ngalaksanakeun "kabijakan pihak" tunggal di antara seueur jasa mikro:

  • ngabagi infrastruktur kana lapisan;
  • konsép Platform salaku Service (PaaS);
  • mantau sagalana yén kajadian kalawan microservices.

Tingkat abstraksi infrastruktur ngawengku tilu lapisan. Hayu urang balik ti luhur ka handap.

A. Top - jasa bolong. Mimiti urang nyobian Istio, tapi tétéla éta ngagunakeun seueur teuing sumber daya, anu mahal teuing pikeun jilid urang. Ku alatan éta, insinyur senior di tim arsitéktur Alexander Lukyanchenko dimekarkeun solusi sorangan - Netramesh (sadia dina Open Source), nu ayeuna urang ngagunakeun dina produksi jeung nu meakeun sababaraha kali kirang sumberdaya ti Istio (tapi teu ngalakukeun sagalana nu Istio bisa boast).
B. Sedeng - Kubernetes. Di dinya, urang nyebarkeun sareng ngoperasikeun jasa mikro.
C. Handap - logam bulistir. Urang teu make awan jeung hal kawas OpenStack, tapi diuk sagemblengna dina logam bulistir.

Sadaya lapisan digabungkeun PaaS. Sareng platform ieu, kahareupna diwangun ku tilu bagian.

I. Generators, dikokolakeun ngaliwatan utilitas CLI. Éta anjeunna anu ngabantosan pamekar nyiptakeun microservice dina cara anu leres sareng usaha minimal.

II. kolektor konsolidasi kalawan kadali sadaya instrumen ngaliwatan dasbor umum.

III. neundeun. Nyambung sareng penjadwal anu otomatis nyetél pemicu pikeun tindakan anu bermakna. Hatur nuhun kana sistem sapertos kitu, teu aya tugas anu luput ngan kusabab aya anu hilap nempatkeun tugas di Jira. Kami nganggo alat internal anu disebut Atlas pikeun ieu.

Naon anu urang terang ngeunaan microservices

Palaksanaan microservices di Avito ogé dilumangsungkeun dina skéma tunggal, nu simplifies kontrol leuwih aranjeunna dina unggal tahapan ngembangkeun sarta release.

Kumaha jalanna pipa pangembangan microservice standar

Sacara umum, ranté nyiptakeun microservice sapertos kieu:

CLI-push → Integrasi Kontinyu → Panggang → Nyebarkeun → Tés jieunan → tés Kanaria → Squeeze Tés → Produksi → Pangropéa.

Hayu urang ngaliwat eta persis dina urutan ieu.

CLI-nyorong

• Nyieun microservice a.
Urang bajoang pikeun lila pikeun ngajarkeun unggal pamekar kumaha nyieun microservices. Kaasup wrote parentah lengkep dina Confluence. Tapi skéma éta robih sareng ditambah. Hasilna - bottleneck kabentuk dina awal perjalanan: peryogi langkung seueur waktos pikeun ngajalankeun microservices ti anu diidinan, sareng masih sering aya masalah nalika nyiptakeunana.

Tungtungna, kami ngawangun utilitas CLI saderhana anu ngajadikeun otomatis léngkah dasar pikeun nyiptakeun microservice. Nyatana, éta ngagentos git push munggaran. Ieu kahayang manehna ngalakukeun.

- Nyiptakeun jasa dumasar kana citakan - léngkah-léngkah, dina modeu "wizard". Kami ngagaduhan témplat pikeun basa pamrograman utama dina Avito backend: PHP, Golang sareng Python.

- Hiji paréntah dina hiji waktu deploys hiji lingkungan pikeun ngembangkeun lokal dina mesin husus - Minikube naék, grafik Helm otomatis dihasilkeun tur ngajalankeun di kubernetes lokal.

- Nyambungkeun database diperlukeun. Pamekar henteu kedah terang IP, login sareng kecap konci pikeun aksés kana pangkalan data anu diperyogikeun - sahenteuna sacara lokal, sahenteuna dina Tahap, sahenteuna dina produksi. Leuwih ti éta, database ieu deployed geuwat dina konfigurasi lepat-toleran sarta kalawan balancing.

- Ieu ngalakukeun live-assembly sorangan. Hayu urang nyebutkeun pamekar dilereskeun hal di microservice ngaliwatan IDE na. Utiliti ningali parobihan dina sistem file sareng, dumasar kana éta, ngawangun deui aplikasi (pikeun Golang) sareng ngamimitian deui. Pikeun PHP, urang ngan saukur neraskeun diréktori di jero kubus sareng aya live-reload dicandak "otomatis".

- Ngahasilkeun autotests. Dina bentuk blanks, tapi rada bisa dipaké.

• Nyebarkeun microservice.

Biasana rada suram pikeun nyebarkeun microservice sareng kami. Wajib wajib:

I. Dockerfile.

II. Konfigurasi.
III. Helm-bagan, nu pajeujeut sorangan sarta ngawengku:

- grafik sorangan;
- témplat;
- nilai spésifik nyokot kana akun lingkungan béda.

Kami parantos ngaleungitkeun nyeri tina ngerjakeun ulang manifes Kubernetes sareng ayeuna aranjeunna didamel otomatis. Tapi anu paling penting, urang nyederhanakeun panyebaran kana watesna. Ti ayeuna, urang gaduh Dockerfile, sareng pamekar nyerat sadayana konfigurasi dina file app.toml pondok tunggal.

Naon anu urang terang ngeunaan microservices

Leres, sareng dina app.toml sorangan, ayeuna aya masalah sakedap. Kami resep dimana sabaraha salinan jasa pikeun dibangkitkeun (dina dev-server, dina pementasan, dina produksi), nunjukkeun katergantungan na. Perhatikeun ukuran garis = "leutik" dina blok [mesin]. Ieu mangrupikeun wates anu bakal dialokasikeun kana jasa liwat Kubernetes.

Salajengna, dina dasar config nu, sadaya Helm-bagan perlu otomatis dihasilkeun sarta sambungan kana database dijieun.

• validasi dasar. Cék sapertos kitu ogé otomatis.
Perlu ngalacak:
- aya Dockerfile;
- aya app.toml;
- Dupi aya dokuméntasi?
- naha dina urutan gumantungna;
- naha aturan waspada diatur.
Nepi ka titik anu terakhir: pamilik jasa nyalira netepkeun métrik produk mana anu kedah dipantau.

• Persiapan dokuméntasi.
Masih wewengkon masalah. Sigana nu paling atra, tapi dina waktos anu sareng catetan "mindeng poho", sarta ku kituna link rentan dina ranté nu.
Perlu yén dokuméntasi pikeun unggal microservice. Ieu ngawengku blok handap.

I. pedaran ringkes jasa. Ngan sababaraha kalimat ngeunaan naon anu dilakukeun sareng kanggo naon éta.

II. Tumbu ka diagram arsitéktur. Kadé sakedapan éta gampang kahartos, contona, naha anjeun nganggo Redis pikeun cache atanapi salaku toko data utama dina modeu pengkuh. Di Avito, ayeuna, ieu mangrupikeun tautan ka Confluence.

III. runbook. Pitunjuk pondok pikeun ngaluncurkeun jasa sareng seluk-beluk nanganan éta.

IV. FAQ, Di mana éta hadé pikeun ngantisipasi masalah anu tiasa dipendakan ku kolega anjeun nalika damel sareng jasa éta.

V. Pedaran titik tungtung API. Upami ujug-ujug anjeun henteu netepkeun tujuan, kolega anu microservices disambungkeun ka anjeun ampir pasti bakal mayar eta. Ayeuna kami nganggo Swagger pikeun ieu sareng solusi kami anu disebut ringkes.

VI. Labels. Atanapi spidol anu nunjukkeun produk mana, fungsionalitas, divisi struktural perusahaan jasa éta. Aranjeunna ngabantosan gancang ngartos, contona, naha anjeun ningali fungsionalitas anu digulung ku kolega anjeun pikeun unit usaha anu sami saminggu ka tukang.

VII. Pamilik jasa atanapi pamilik. Dina kalolobaan kasus, éta - atanapi aranjeunna - tiasa sacara otomatis ditangtukeun nganggo PaaS, tapi pikeun asuransi, kami meryogikeun pamekar pikeun netepkeunana sacara manual ogé.

Tungtungna, éta prakték anu saé pikeun ngalaksanakeun ulasan dokuméntasi, sami sareng ulasan kode.

Pamaduan kontinyu

  • Nyiapkeun repositories.
  • Nyiptakeun pipa di TeamCity.
  • Pemberian hak.
  • Pilarian nu boga jasa. Ieu mangrupikeun skéma hibrida - nyirian manual sareng otomatisasi minimal tina PaaS. Skéma otomatis sapinuhna gagal nalika ladenan dialihkeun ka rojongan di tim pamekar séjén atawa, contona, lamun pamekar jasa kaluar.
  • Pendaptaran jasa di Atlas (tingali luhureun). Kalawan sakabeh boga sarta kagumantungan.
  • Mariksa migrasi. Kami pariksa naha aya anu berpotensi bahaya di antarana. Contona, dina salah sahijina, hiji méja robah pop up atawa hal sejenna nu bisa megatkeun kasaluyuan skéma data antara versi béda tina jasa. Lajeng migrasi henteu dilaksanakeun, tapi nempatkeun kana langganan - PaaS kedah sinyal nu boga jasa nalika janten aman nerapkeun eta.

Panggang

Tahap salajengna nyaéta jasa bungkusan sateuacan nyebarkeun.

  • Majelis aplikasi. Nurutkeun kana klasik - dina gambar Docker.
  • Generasi grafik Helm pikeun layanan sorangan jeung sumber patali. Kaasup pikeun pangkalan data sareng cache. Éta dijieun otomatis luyu jeung app.toml config nu dihasilkeun dina tahap CLI-push.
  • Nyiptakeun tiket pikeun admin pikeun muka palabuhan (lamun diperlukeun).
  • Ngajalankeun tés unit sareng ngitung sinyalna kode. Upami sinyalna kode sahandapeun nilai bangbarung anu ditangtukeun, teras, paling dipikaresep, jasa éta moal langkung jauh - pikeun panyebaran. Upami éta dina ambang anu tiasa ditampi, maka jasa bakal dipasihan koefisien "pessimizing": teras, upami teu aya perbaikan dina indikator kana waktosna, pamekar bakal nampi béwara yén teu aya kamajuan dina hal tés ( sareng hal anu kedah dilakukeun ngeunaan éta).
  • Akunting pikeun memori sareng watesan CPU. Dasarna, kami nyerat microservices di Golang sareng ngajalankeunana di Kubernetes. Lantaran kitu, hiji subtlety pakait sareng fitur basa Golang: sacara standar, sadaya cores dina mesin dipaké dina ngamimitian, lamun anjeun teu eksplisit nyetel variabel GOMAXPROCS, sarta lamun sababaraha layanan sapertos diluncurkeun dina mesin nu sami, aranjeunna dimimitian. bersaing pikeun sumber daya, silih interfering. Grafik di handap ieu nunjukkeun kumaha waktos palaksanaan robih upami aplikasi dijalankeun tanpa perdebatan sareng dina modeu lomba sumberdaya. (Sumber tina bagan nyaéta di dieu).

Naon anu urang terang ngeunaan microservices

Waktu palaksanaan, kirang langkung saé. Maksimum: 643ms, minimum: 42ms. Poto tiasa diklik.

Naon anu urang terang ngeunaan microservices

Waktos pikeun dioperasi, kirang langkung saé. Maksimum: 14091 ns, minimum: 151 ns. Poto tiasa diklik.

Dina tahap persiapan assembly, anjeun tiasa nyetél variabel ieu sacara eksplisit atanapi anjeun tiasa nganggo perpustakaan automaxprocs ti guys di Uber.

Nyebarkeun

• Mariksa konvénsi. Sateuacan anjeun ngamimitian ngirimkeun jasa ngawangun ka lingkungan anu dituju, anjeun kedah pariksa ieu:
- titik tungtung API.
- Korespondensi titik tungtung API réspon kana skéma.
- Format log.
- Nyetel header pikeun pamundut ka jasa (ayeuna ieu dilakukeun ku netramesh)
- Nyetel spidol juragan nalika ngirim pesen ka beus (beus acara). Ieu diperlukeun pikeun ngalacak konektipitas jasa ngaliwatan beus. Anjeun tiasa ngirim duanana data idempotent ka beus anu henteu ningkatkeun konektipitas jasa (anu saé), sareng data bisnis anu ningkatkeun konektipitas jasa (anu goréng pisan!). Sareng nalika konektipitas ieu janten masalah, pamahaman anu nyerat sareng maca beus ngabantosan leres-leres misahkeun jasa.

Sajauh ieu, teu seueur pisan konvénsi di Avito, tapi kolam renangna ngembang. Beuki perjanjian sapertos dina bentuk anu kaharti sareng merenah pikeun tim, langkung gampang pikeun ngajaga konsistensi antara jasa mikro.

Tés sintétis

• nguji loop Closed. Pikeun éta, urang ayeuna nganggo open source hoverfly.io. Mimiti, éta ngarékam beban nyata dina jasa, teras - ngan dina loop katutup - éta ditiru.

• Stress Testing. Urang nyobian mawa sagala jasa kana kinerja optimal. Sareng sadaya vérsi unggal jasa kedah diuji beban - ku kituna urang tiasa ngartos kinerja jasa ayeuna sareng bédana sareng versi sateuacana tina jasa anu sami. Upami, saatos pembaruan jasa, prestasina turun satengah kali, ieu mangrupikeun sinyal anu jelas pikeun anu gaduhna: anjeun kedah ngagali kodeu sareng ngabenerkeun kaayaan.
Urang mimitian ti data dikumpulkeun, contona, dina raraga leres nerapkeun skala otomatis tur, tungtungna, ngartos sacara umum kumaha scalable jasa.

Salila tés beban, urang pariksa naha konsumsi sumberdaya minuhan wates anu disetél. Sarta kami museurkeun utamana dina extremes.

a) Urang nempo total beban.
- Leutik teuing - paling dipikaresep hal teu dianggo lamun beban dumadakan turun sababaraha kali.
- Badag teuing - optimasi diperlukeun.

b) Tingali cutoff RPS.
Di dieu urang tingali bédana antara versi ayeuna sareng anu sateuacana sareng jumlah total. Salaku conto, upami jasa masihan 100 rps, maka éta tulisanna kirang, atanapi ieu spésifikna, tapi dina sagala hal, ieu mangrupikeun alesan pikeun ningali jasa éta pisan.
Upami, sabalikna, seueur teuing RPS, maka, sigana, sababaraha jinis bug sareng sababaraha titik tungtung lirén ngalaksanakeun payload, tapi ngan ukur sababaraha. return true;

tés Kanaria

Saatos tés sintétik parantos lulus, kami ngajalankeun microservice dina sajumlah leutik pangguna. Urang mimitian taliti, kalayan pangsa leutik tina panongton dimaksudkeun tina jasa - kirang ti 0,1%. Dina tahap ieu, penting pisan yén métrik téknis sareng produk anu leres diasupkeun dina ngawaskeun supados aranjeunna nunjukkeun masalah dina jasa gancang-gancang. Waktu uji kanaria minimum nyaéta 5 menit, anu utama nyaéta 2 jam. Pikeun ladenan kompléks, setel waktos dina modeu manual.
Urang analisa:
- metrics husus basa, hususna, pagawe php-fpm;
- kasalahan dina Sentry;
- status respon;
- waktos respon (waktos respon), pasti tur rata;
- latency;
- iwal, diatur sarta unhandled;
- métrik produk.

Nguji Squeeze

Squeeze Testing disebut oge "squeeze" testing. Ngaran téknik ieu diwanohkeun kana Netflix. Intina nyaéta yén mimitina urang ngeusian hiji conto kalayan lalu lintas nyata kana kaayaan gagal sahingga nyetél watesna. Teras we tambahkeun conto anu sanés sareng beban pasangan ieu - deui maksimal; urang tingali siling jeung délta maranéhanana jeung squeeze munggaran. Janten urang sambungkeun hiji conto per léngkah sareng ngitung pola dina parobihan.
Data dina tés ngaliwatan "squeezing" ogé ngalir kana database umum tina metrics, dimana urang boh enrich hasil beban jieunan sareng maranehna, atawa malah ngaganti "synthetics" sareng maranehna.

Produksi

• Skala. Rolling kaluar jasa pikeun produksi, urang ngawas kumaha éta skala. Dina waktos anu sami, ngan ukur ngawaskeun indikator CPU, dina pangalaman urang, henteu cekap. Skala otomatis sareng patokan RPS tiasa dianggo dina bentuk anu paling murni, tapi ngan ukur pikeun jasa anu tangtu, sapertos streaming online. Janten urang tingali utamina dina métrik produk khusus aplikasi.

Hasilna, nalika skala, urang nganalisis:
- Indikator CPU sareng RAM,
- jumlah pamundut dina antrian,
- waktos respon,
- ramalan dumasar kana akumulasi data sajarah.

Nalika skala jasa, éta ogé penting pikeun ngalacak katergantunganna supados henteu kajantenan yén urang ngaskalakeun jasa anu munggaran dina ranté éta, sareng anu diaksésna aya dina beban. Pikeun ngadamel beban anu tiasa ditampi pikeun sadaya kolam renang jasa, urang ningali data sajarah ngeunaan jasa anu gumantung "pangcaketna" (dina hal CPU sareng RAM, ditambah ku métrik khusus aplikasi) sareng ngabandingkeunana sareng data sajarah initializing jasa, jeung saterusna sapanjang sakabéh "rantai kagumantungan" ", ti luhur ka handap.

palayanan

Saatos jasa mikro dioperasikeun, urang tiasa ngagantungkeun pemicu.

Di dieu aya kaayaan has nu micu jalan.
- Migrasi anu berpotensi bahaya dideteksi.
- Pembaruan kaamanan parantos dileupaskeun.
- Ladenan sorangan teu acan diropéa pikeun lila.
- Beban dina jasa parantos nyata turun atanapi sababaraha métrik produkna kaluar tina norma.
- Ladenan henteu deui nyumponan sarat anyar platform éta.

Sababaraha pemicu tanggung jawab pikeun stabilitas karya, sababaraha - salaku fungsi pangropéa sistem - contona, sababaraha layanan teu acan deployed pikeun lila sarta gambar dasarna geus ceased lulus cék kaamanan.

Dasbor

Pondokna, dasbor nyaéta panel kontrol sakabéh PaaS urang.

  • Hiji titik inpormasi ngeunaan jasa éta, kalayan data ngeunaan sinyalna tés, jumlah gambarna, jumlah salinan produksi, versi, jsb.
  • Alat pikeun nyaring data ku jasa sareng labél (token milik unit bisnis, fungsionalitas produk, jsb.)
  • Alat integrasi sareng alat infrastruktur pikeun ngalacak, logging, ngawaskeun.
  • Titik tunggal dokuméntasi pikeun jasa.
  • Hiji sudut pandang tunggal sadaya acara ku jasa.

Naon anu urang terang ngeunaan microservices
Naon anu urang terang ngeunaan microservices
Naon anu urang terang ngeunaan microservices
Naon anu urang terang ngeunaan microservices

dina total

Sateuacan ngenalkeun PaaS, pamekar anyar tiasa nyéépkeun sababaraha minggu pikeun ngartos sadaya alat anu diperyogikeun pikeun ngaluncurkeun microservice dina produksi: Kubernetes, Helm, fitur TeamCity internal urang, nyetél sambungan kana pangkalan data sareng cache dina cara anu gagal-aman, jsb. Ayeuna butuh sababaraha jam pikeun maca ngamimitian gancang sareng ngadamel jasa éta sorangan.

Kuring nyieun laporan dina topik ieu HighLoad ++ 2018, anjeun tiasa ningali видео и presentasi.

Bonus lagu pikeun maranéhanana anu maca nepi ka ahir

Kami di Avito ngatur latihan internal tilu dinten pikeun pamekar ti Chris Richardson, ahli dina arsitektur microservice. Simkuring hoyong masihan kasempetan pikeun ilubiung dina eta ka salah sahiji pamiarsa pos ieu. Ieu téh program latihan geus dipasang.

Latihan bakal dilaksanakeun ti 5 nepi ka 7 Agustus di Moscow. Ieu mangrupikeun dinten damel anu bakal pinuh dijajah. Dahar beurang sareng latihan bakal aya di kantor kami, sareng pamilon anu dipilih mayar kanggo perjalanan sareng akomodasi nyalira.

Anjeun tiasa nerapkeun pikeun ilubiung dina formulir google ieu. Ti anjeun - jawaban kana patarosan naha anjeun kedah hadir pelatihan sareng inpormasi ngeunaan cara ngahubungi anjeun. Jawab dina basa Inggris, sabab pamilon anu meunang latihan bakal dipilih ku Chris sorangan.
Kami bakal ngumumkeun nami pamilon pelatihan kalayan pembaruan pikeun pos ieu sareng dina jaringan sosial Avito pikeun pamekar (AvitoTech di Facebook, VKontakte, Twitter) teu langkung ti 19 Juli.

sumber: www.habr.com

Tambahkeun komentar