Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Hello, nama saya Evgeniy. Saya bekerja dalam infrastruktur carian Yandex.Market. Saya ingin memberitahu komuniti Habr tentang dapur dalaman Pasar - dan saya mempunyai banyak perkara untuk diceritakan. Pertama sekali, cara carian Pasaran berfungsi, proses dan seni bina. Bagaimanakah kita menangani situasi kecemasan: apakah yang berlaku jika satu pelayan terputus? Bagaimana jika terdapat 100 pelayan sedemikian?

Anda juga akan mempelajari cara kami melaksanakan fungsi baharu pada sekumpulan pelayan sekaligus. Dan cara kami menguji perkhidmatan kompleks secara langsung dalam pengeluaran, tanpa menyebabkan sebarang kesulitan kepada pengguna. Secara umum, cara carian Pasaran berfungsi supaya semua orang berseronok.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Sedikit tentang kami: masalah apa yang kami selesaikan

Apabila anda memasukkan teks, mencari produk mengikut parameter, atau membandingkan harga di kedai yang berbeza, semua permintaan dihantar ke perkhidmatan carian. Carian ialah perkhidmatan terbesar dalam Pasaran.

Kami memproses semua permintaan carian: dari tapak market.yandex.ru, beru.ru, perkhidmatan Supercheck, Yandex.Advisor, aplikasi mudah alih. Kami juga menyertakan tawaran produk dalam hasil carian di yandex.ru.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Dengan perkhidmatan carian yang saya maksudkan bukan sahaja carian itu sendiri, tetapi juga pangkalan data dengan semua tawaran di Pasaran. Skalanya ialah: lebih daripada satu bilion permintaan carian diproses setiap hari. Dan semuanya harus berfungsi dengan cepat, tanpa gangguan dan sentiasa menghasilkan hasil yang diinginkan.

Apa itu: Seni bina pasaran

Saya akan menerangkan secara ringkas seni bina Pasaran semasa. Ia boleh digambarkan secara kasar melalui rajah di bawah:
Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal
Katakan kedai rakan kongsi datang kepada kami. Dia berkata saya ingin menjual mainan: kucing jahat ini dengan pencicit. Dan satu lagi kucing yang marah tanpa suara. Dan hanya seekor kucing. Kemudian kedai perlu menyediakan tawaran yang dicari oleh Pasaran. Kedai menjana xml istimewa dengan tawaran dan menyampaikan laluan ke xml ini melalui antara muka ahli gabungan. Pengindeks kemudian memuat turun xml ini secara berkala, menyemak ralat dan menyimpan semua maklumat ke dalam pangkalan data yang besar.

Terdapat banyak xml yang disimpan sedemikian. Indeks carian dibuat daripada pangkalan data ini. Indeks disimpan dalam format dalaman. Selepas mencipta indeks, perkhidmatan Layout memuat naiknya ke pelayan carian.

Akibatnya, kucing yang marah dengan pencicit muncul dalam pangkalan data, dan indeks kucing muncul pada pelayan.

Saya akan memberitahu anda cara kami mencari kucing dalam bahagian tentang seni bina carian.

Seni bina carian pasaran

Kami hidup dalam dunia perkhidmatan mikro: setiap permintaan yang masuk market.yandex.ru menyebabkan banyak subkueri, dan berpuluh-puluh perkhidmatan terlibat dalam pemprosesan mereka. Rajah menunjukkan hanya beberapa:

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal
Skim pemprosesan permintaan dipermudahkan

Setiap perkhidmatan mempunyai perkara yang menarik - pengimbangnya sendiri dengan nama yang unik:

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Pengimbang memberi kami lebih fleksibiliti dalam mengurus perkhidmatan: anda boleh, sebagai contoh, mematikan pelayan, yang selalunya diperlukan untuk kemas kini. Pengimbang melihat bahawa pelayan tidak tersedia dan secara automatik mengubah hala permintaan ke pelayan atau pusat data lain. Apabila menambah atau mengalih keluar pelayan, beban diagihkan semula secara automatik antara pelayan.

Nama unik pengimbang tidak bergantung pada pusat data. Apabila perkhidmatan A membuat permintaan kepada B, maka secara lalai pengimbang B mengubah hala permintaan ke pusat data semasa. Jika perkhidmatan tidak tersedia atau tidak wujud dalam pusat data semasa, maka permintaan akan diubah hala ke pusat data lain.

Satu FQDN untuk semua pusat data membolehkan perkhidmatan A mengabstraksi sepenuhnya daripada lokasi. Permintaannya untuk perkhidmatan B akan sentiasa diproses. Pengecualian adalah kes apabila perkhidmatan terletak di semua pusat data.

Tetapi tidak semuanya begitu cerah dengan pengimbang ini: kami mempunyai komponen perantaraan tambahan. Pengimbang mungkin tidak stabil, dan masalah ini diselesaikan oleh pelayan berlebihan. Terdapat juga kelewatan tambahan antara perkhidmatan A dan B. Tetapi dalam praktiknya ia kurang daripada 1 ms dan untuk kebanyakan perkhidmatan ini tidak kritikal.

Menangani Perkara yang Tidak Dijangka: Pengimbangan dan Ketahanan Perkhidmatan Carian

Bayangkan bahawa terdapat keruntuhan: anda perlu mencari kucing dengan squeaker, tetapi pelayan ranap. Atau 100 pelayan. Macam mana nak keluar? Adakah kita benar-benar akan meninggalkan pengguna tanpa kucing?

Keadaan itu menakutkan, tetapi kami bersedia untuk itu. Saya akan memberitahu anda mengikut urutan.

Infrastruktur carian terletak di beberapa pusat data:

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Semasa mereka bentuk, kami menyertakan kemungkinan menutup satu pusat data. Kehidupan penuh dengan kejutan - contohnya, jengkaut boleh memotong kabel bawah tanah (ya, itu berlaku). Kapasiti dalam pusat data yang tinggal harus mencukupi untuk menahan beban puncak.

Mari kita pertimbangkan pusat data tunggal. Setiap pusat data mempunyai skema operasi pengimbang yang sama:

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal
Satu pengimbang ialah sekurang-kurangnya tiga pelayan fizikal. Lebihan ini dibuat untuk kebolehpercayaan. Pengimbang dijalankan pada HAProx.

Kami memilih HAProx kerana prestasinya yang tinggi, keperluan sumber yang rendah dan kefungsian yang luas. Perisian carian kami berjalan di dalam setiap pelayan.

Kemungkinan satu pelayan gagal adalah rendah. Tetapi jika anda mempunyai banyak pelayan, kemungkinan sekurang-kurangnya satu akan turun meningkat.

Inilah yang berlaku dalam realiti: pelayan ranap. Oleh itu, adalah perlu untuk sentiasa memantau status semua pelayan. Jika pelayan berhenti bertindak balas, ia terputus secara automatik daripada trafik. Untuk tujuan ini, HAProxy mempunyai pemeriksaan kesihatan terbina dalam. Ia pergi ke semua pelayan sekali sesaat dengan permintaan HTTP "/ping".

Satu lagi ciri HAProxy: semakan ejen membolehkan anda memuatkan semua pelayan secara sama rata. Untuk melakukan ini, HAProxy menyambung ke semua pelayan, dan mereka mengembalikan beratnya bergantung pada beban semasa dari 1 hingga 100. Berat dikira berdasarkan bilangan permintaan dalam baris gilir untuk pemprosesan dan beban pada pemproses.

Sekarang tentang mencari kucing. Hasil carian dalam permintaan seperti: /search?text=angry+cat. Agar carian menjadi pantas, keseluruhan indeks kucing mesti dimuatkan ke dalam RAM. Malah membaca dari SSD tidak cukup pantas.

Pada suatu masa dahulu, pangkalan data tawaran adalah kecil, dan RAM satu pelayan sudah cukup untuknya. Apabila pangkalan tawaran berkembang, semuanya tidak lagi sesuai dengan RAM ini, dan data dibahagikan kepada dua bahagian: shard 1 dan shard 2.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal
Tetapi ini selalu berlaku: sebarang penyelesaian, walaupun yang baik, menimbulkan masalah lain.

Pengimbang masih pergi ke mana-mana pelayan. Tetapi pada mesin di mana permintaan itu datang, hanya terdapat separuh daripada indeks. Selebihnya berada di pelayan lain. Oleh itu, pelayan terpaksa pergi ke beberapa mesin jiran. Selepas menerima data daripada kedua-dua pelayan, keputusan telah digabungkan dan disusun semula.

Memandangkan pengimbang mengagihkan permintaan secara sama rata, semua pelayan terlibat dalam penarafan semula, dan bukan hanya menghantar data.

Masalah berlaku jika pelayan jiran tidak tersedia. Penyelesaiannya adalah untuk menentukan beberapa pelayan dengan keutamaan berbeza sebagai pelayan "jiran". Mula-mula, permintaan itu dihantar kepada pelayan dalam rak semasa. Jika tiada respons, permintaan telah dihantar ke semua pelayan di pusat data ini. Dan terakhir, permintaan itu pergi ke pusat data lain.
Apabila bilangan cadangan bertambah, data dibahagikan kepada empat bahagian. Tetapi ini bukan hadnya.

Pada masa ini, konfigurasi lapan serpihan digunakan. Di samping itu, untuk menjimatkan lebih banyak memori, indeks dibahagikan kepada bahagian carian (yang digunakan untuk mencari) dan bahagian coretan (yang tidak terlibat dalam carian).

Satu pelayan mengandungi maklumat untuk hanya satu serpihan. Oleh itu, untuk mencari indeks penuh, anda perlu mencari pada lapan pelayan yang mengandungi serpihan yang berbeza.

Pelayan dikumpulkan ke dalam kelompok. Setiap kelompok mengandungi lapan enjin carian dan satu pelayan coretan.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal
Pelayan coretan menjalankan pangkalan data nilai kunci dengan data statik. Mereka diperlukan untuk mengeluarkan dokumen, sebagai contoh, perihalan kucing dengan squeaker. Data dipindahkan khas ke pelayan yang berasingan supaya tidak memuatkan memori pelayan carian.

Memandangkan ID dokumen adalah unik hanya dalam satu indeks, situasi boleh timbul apabila tiada dokumen dalam coretan. Nah, atau bahawa untuk satu ID akan ada kandungan yang berbeza. Oleh itu, agar carian berfungsi dan hasil dapat dikembalikan, terdapat keperluan untuk konsistensi merentas keseluruhan kluster. Saya akan memberitahu anda di bawah cara kami memantau konsistensi.

Carian itu sendiri berstruktur seperti berikut: permintaan carian boleh datang ke mana-mana daripada lapan pelayan. Katakan dia datang ke pelayan 1. Pelayan ini memproses semua hujah dan memahami apa dan bagaimana untuk mencari. Bergantung pada permintaan masuk, pelayan boleh membuat permintaan tambahan kepada perkhidmatan luaran untuk maklumat yang diperlukan. Satu permintaan boleh diikuti sehingga sepuluh permintaan kepada perkhidmatan luaran.

Selepas mengumpul maklumat yang diperlukan, carian bermula dalam pangkalan data tawaran. Untuk melakukan ini, subqueries dibuat kepada semua lapan pelayan dalam kelompok.

Setelah maklum balas diterima, hasilnya digabungkan. Akhirnya, beberapa lagi subkueri kepada pelayan coretan mungkin diperlukan untuk menjana hasil.

Pertanyaan carian dalam kluster kelihatan seperti: /shard1?text=marah+kucing. Di samping itu, subkueri borang sentiasa dibuat antara semua pelayan dalam kelompok sekali sesaat: /status.

Permintaan /status mengesan situasi di mana pelayan tidak tersedia.

Ia juga mengawal bahawa versi enjin carian dan versi indeks adalah sama pada semua pelayan, jika tidak, akan terdapat data yang tidak konsisten dalam kelompok.

Walaupun fakta bahawa satu pelayan coretan memproses permintaan daripada lapan enjin carian, pemprosesnya dimuatkan dengan sangat ringan. Oleh itu, kami kini memindahkan data coretan ke perkhidmatan yang berasingan.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Untuk memindahkan data, kami memperkenalkan kunci universal untuk dokumen. Sekarang adalah mustahil untuk situasi di mana kandungan daripada dokumen lain dikembalikan menggunakan satu kunci.

Tetapi peralihan kepada seni bina lain masih belum lengkap. Sekarang kami mahu menyingkirkan pelayan coretan khusus. Dan kemudian beralih dari struktur kelompok sama sekali. Ini akan membolehkan kami meneruskan skala dengan mudah. Bonus tambahan ialah penjimatan besi yang ketara.

Dan kini kepada cerita menakutkan dengan pengakhiran yang menggembirakan. Mari kita pertimbangkan beberapa kes ketiadaan pelayan.

Sesuatu yang buruk berlaku: satu pelayan tidak tersedia

Katakan satu pelayan tidak tersedia. Kemudian pelayan yang tinggal dalam kelompok boleh terus bertindak balas, tetapi hasil carian tidak akan lengkap.

Melalui semakan status /status pelayan jiran memahami bahawa pelayan tidak tersedia. Oleh itu, untuk mengekalkan kesempurnaan, semua pelayan dalam kluster setiap permintaan /ping mereka mula bertindak balas kepada pengimbang bahawa mereka juga tidak tersedia. Ternyata semua pelayan dalam kluster mati (yang tidak benar). Ini adalah kelemahan utama skim kluster kami - itulah sebabnya kami ingin menjauhinya.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Permintaan yang gagal dengan ralat dihantar semula oleh pengimbang pada pelayan lain.
Pengimbang juga berhenti menghantar trafik pengguna ke pelayan yang mati, tetapi terus menyemak status mereka.

Apabila pelayan tersedia, ia mula bertindak balas /ping. Sebaik sahaja respons biasa kepada ping daripada pelayan mati mula tiba, pengimbang mula menghantar trafik pengguna ke sana. Operasi kluster dipulihkan, hore.

Lebih teruk lagi: banyak pelayan tidak tersedia

Sebahagian besar pelayan di pusat data dipotong. Apa yang perlu dilakukan, ke mana hendak lari? Pengimbang datang untuk menyelamatkan lagi. Setiap pengimbang sentiasa menyimpan dalam ingatan bilangan pelayan langsung semasa. Ia sentiasa mengira jumlah maksimum trafik yang boleh diproses oleh pusat data semasa.

Apabila banyak pelayan di pusat data terputus, pengimbang menyedari bahawa pusat data ini tidak dapat memproses semua lalu lintas.

Kemudian lebihan trafik mula diedarkan secara rawak ke pusat data lain. Semuanya berfungsi, semua orang gembira.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Bagaimana kami melakukannya: menerbitkan keluaran

Sekarang mari kita bincangkan tentang cara kami menerbitkan perubahan yang dibuat pada perkhidmatan. Di sini kami telah mengambil jalan untuk memudahkan proses: melancarkan keluaran baharu hampir automatik sepenuhnya.
Apabila bilangan perubahan tertentu terkumpul dalam projek, keluaran baharu dibuat secara automatik dan binaannya bermula.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Kemudian perkhidmatan itu dilancarkan untuk ujian, di mana kestabilan operasi diperiksa.

Pada masa yang sama, ujian prestasi automatik dilancarkan. Ini dikendalikan oleh perkhidmatan khas. Saya tidak akan bercakap mengenainya sekarang - penerangannya layak untuk artikel berasingan.

Jika penerbitan dalam ujian berjaya, penerbitan keluaran dalam prestable dimulakan secara automatik. Prestable ialah kluster khas di mana trafik pengguna biasa diarahkan. Jika ia mengembalikan ralat, pengimbang membuat permintaan semula kepada pengeluaran.

Dalam prastabil, masa tindak balas diukur dan dibandingkan dengan keluaran sebelumnya dalam pengeluaran. Jika semuanya baik-baik saja, maka seseorang menyambung: menyemak graf dan keputusan ujian beban dan kemudian mula melancarkan pengeluaran.

Segala yang terbaik diberikan kepada pengguna: Ujian A/B

Ia tidak selalunya jelas sama ada perubahan pada perkhidmatan akan membawa faedah sebenar. Untuk mengukur kegunaan perubahan, orang datang dengan ujian A/B. Saya akan memberitahu anda sedikit tentang cara ia berfungsi dalam carian Yandex.Market.

Semuanya bermula dengan menambah parameter CGI baharu yang membolehkan fungsi baharu. Biarkan parameter kami ialah: market_new_functionality=1. Kemudian dalam kod kami membolehkan fungsi ini jika bendera hadir:

If (cgi.experiments.market_new_functionality) {
// enable new functionality
}

Fungsi baharu sedang dilancarkan untuk pengeluaran.

Untuk mengautomasikan ujian A/B, terdapat perkhidmatan khusus yang menyediakan maklumat terperinci diterangkan di sini. Percubaan dibuat dalam perkhidmatan. Bahagian trafik ditetapkan, sebagai contoh, 15%. Peratusan ditetapkan bukan untuk pertanyaan, tetapi untuk pengguna. Tempoh percubaan juga ditunjukkan, sebagai contoh, seminggu.

Beberapa eksperimen boleh dijalankan serentak. Dalam tetapan anda boleh menentukan sama ada persimpangan dengan percubaan lain boleh dilakukan.

Akibatnya, perkhidmatan menambah hujah secara automatik market_new_functionality=1 kepada 15% pengguna. Ia juga secara automatik mengira metrik yang dipilih. Selepas eksperimen selesai, penganalisis melihat keputusan dan membuat kesimpulan. Berdasarkan penemuan, keputusan dibuat untuk melancarkan pengeluaran atau penghalusan.

Tangan cekatan pasaran: ujian dalam pengeluaran

Ia sering berlaku bahawa anda perlu menguji operasi fungsi baru dalam pengeluaran, tetapi anda tidak pasti bagaimana ia akan bertindak dalam keadaan "pertempuran" di bawah beban berat.

Terdapat penyelesaian: bendera dalam parameter CGI boleh digunakan bukan sahaja untuk ujian A/B, tetapi juga untuk menguji fungsi baharu.

Kami membuat alat yang membolehkan anda menukar konfigurasi dengan serta-merta pada ribuan pelayan tanpa mendedahkan perkhidmatan kepada risiko. Ia dipanggil Stop Tap. Idea asal adalah untuk dapat melumpuhkan beberapa fungsi dengan cepat tanpa susun atur. Kemudian alat itu berkembang dan menjadi lebih kompleks.

Rajah aliran perkhidmatan dibentangkan di bawah:

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Nilai bendera ditetapkan melalui API. Perkhidmatan pengurusan menyimpan nilai ini dalam pangkalan data. Semua pelayan pergi ke pangkalan data sekali setiap sepuluh saat, pam keluar nilai bendera dan gunakan nilai ini untuk setiap permintaan.

Dalam ketik Henti anda boleh menetapkan dua jenis nilai:

1) Ungkapan bersyarat. Gunakan apabila salah satu nilai adalah benar. Sebagai contoh:

{
	"condition":"IS_DC1",
	"value":"3",
}, 
{
	"condition": "CLUSTER==2 and IS_BERU", 
	"value": "4!" 
}

Nilai "3" akan digunakan apabila permintaan diproses di lokasi DC1. Dan nilainya ialah "4" apabila permintaan diproses pada kelompok kedua untuk tapak beru.ru.

2) Nilai tanpa syarat. Mohon secara lalai jika tiada syarat yang dipenuhi. Sebagai contoh:

nilai, nilai!

Jika nilai berakhir dengan tanda seru, ia diberi keutamaan yang lebih tinggi.

Penghurai parameter CGI menghuraikan URL. Kemudian gunakan nilai dari Stop Tap.

Nilai dengan keutamaan berikut digunakan:

  1. Dengan peningkatan keutamaan daripada Ketik Henti (tanda seru).
  2. Nilai daripada permintaan.
  3. Nilai lalai daripada Stop tap.
  4. Nilai lalai dalam kod.

Terdapat banyak bendera yang ditunjukkan dalam nilai bersyarat - ia cukup untuk semua senario yang kami ketahui:

  • Pusat data.
  • Persekitaran: pengeluaran, ujian, bayang-bayang.
  • Tempat: pasar, beru.
  • Nombor kluster.

Dengan alat ini, anda boleh mendayakan fungsi baharu pada kumpulan pelayan tertentu (contohnya, hanya dalam satu pusat data) dan menguji pengendalian fungsi ini tanpa sebarang risiko tertentu kepada keseluruhan perkhidmatan. Walaupun anda membuat kesilapan yang serius di suatu tempat, semuanya mula jatuh dan keseluruhan pusat data turun, pengimbang akan mengubah hala permintaan ke pusat data lain. Pengguna akhir tidak akan perasan apa-apa.

Jika anda melihat masalah, anda boleh segera mengembalikan bendera kepada nilai sebelumnya dan perubahan akan digulung semula.

Perkhidmatan ini juga mempunyai kelemahannya: pembangun sangat menyukainya dan sering cuba untuk menolak semua perubahan ke dalam Stop Tap. Kami cuba memerangi penyalahgunaan.

Pendekatan Stop Tap berfungsi dengan baik apabila anda sudah mempunyai kod stabil sedia untuk dilancarkan ke pengeluaran. Pada masa yang sama, anda masih mempunyai keraguan, dan anda ingin menyemak kod dalam keadaan "pertempuran".

Walau bagaimanapun, Stop Tap tidak sesuai untuk ujian semasa pembangunan. Terdapat gugusan berasingan untuk pembangun yang dipanggil "kelompok bayangan".

Ujian Rahsia: Kluster Bayangan

Permintaan daripada salah satu kluster diduplikasi kepada kluster bayang-bayang. Tetapi pengimbang mengabaikan sama sekali respons daripada kluster ini. Gambar rajah operasinya dibentangkan di bawah.

Cara carian Yandex.Market berfungsi dan apa yang berlaku jika salah satu pelayan gagal

Kami mendapat kluster ujian yang berada dalam keadaan "pertempuran" sebenar. Trafik pengguna biasa pergi ke sana. Perkakasan dalam kedua-dua kelompok adalah sama, jadi prestasi dan ralat boleh dibandingkan.

Dan oleh kerana pengimbang mengabaikan respons sepenuhnya, pengguna akhir tidak akan melihat respons daripada gugusan bayang-bayang. Oleh itu, ia tidak menakutkan untuk membuat kesilapan.

Penemuan

Jadi, bagaimanakah kami membina carian Pasaran?

Untuk menjadikan semuanya berjalan lancar, kami mengasingkan fungsi kepada perkhidmatan yang berasingan. Dengan cara ini kita boleh menskalakan hanya komponen yang kita perlukan dan menjadikan komponen lebih mudah. Mudah untuk menetapkan komponen berasingan kepada pasukan lain dan berkongsi tanggungjawab untuk mengusahakannya. Dan penjimatan yang ketara dalam besi dengan pendekatan ini adalah tambahan yang jelas.

Kelompok bayangan juga membantu kami: kami boleh membangunkan perkhidmatan, mengujinya dalam proses dan tidak mengganggu pengguna.

Sudah tentu, ujian dalam pengeluaran. Perlu menukar konfigurasi pada beribu-ribu pelayan? Mudah, gunakan Stop Tap. Dengan cara ini, anda boleh segera melancarkan penyelesaian kompleks siap pakai dan melancarkan semula kepada versi yang stabil jika masalah timbul.

Saya harap saya dapat menunjukkan cara kami menjadikan Pasaran pantas dan stabil dengan asas tawaran yang sentiasa berkembang. Bagaimana kami menyelesaikan masalah pelayan, menangani sejumlah besar permintaan, meningkatkan fleksibiliti perkhidmatan dan melakukan ini tanpa mengganggu proses kerja.

Sumber: www.habr.com

Tambah komen