HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Konferensi HighLoad++ berikutnya akan diadakan pada tanggal 6 dan 7 April 2020 di St.
Detail dan tiket по ссылке. HighLoad++ Siberia 2019. Aula "Krasnoyarsk". 25 Juni, 12:00. Tesis dan presentasi.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Kebetulan persyaratan praktis bertentangan dengan teori, di mana aspek-aspek penting untuk produk komersial tidak diperhitungkan. Pembicaraan ini menyajikan proses untuk memilih dan menggabungkan pendekatan yang berbeda untuk menciptakan komponen konsistensi kausal berdasarkan penelitian akademis berdasarkan persyaratan produk komersial. Pendengar akan belajar tentang pendekatan teoretis yang ada terhadap jam logis, pelacakan ketergantungan, keamanan sistem, sinkronisasi jam, dan mengapa MongoDB memilih solusi tertentu.

Mikhail Tyulenev (selanjutnya disebut MT): – Saya akan berbicara tentang konsistensi kausal - ini adalah fitur yang kami kerjakan di MongoDB. Saya bekerja di sekelompok sistem terdistribusi, kami melakukannya sekitar dua tahun lalu.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Dalam prosesnya, saya harus membiasakan diri dengan banyak penelitian akademis, karena fitur ini telah dipelajari dengan cukup baik. Ternyata tidak ada satu artikel pun yang sesuai dengan apa yang dibutuhkan dalam database produksi karena persyaratan yang sangat spesifik yang mungkin ada dalam aplikasi produksi mana pun.

Saya akan berbicara tentang bagaimana kita, sebagai konsumen Riset akademis, menyiapkan sesuatu dari penelitian tersebut yang kemudian dapat kita sajikan kepada pengguna sebagai hidangan siap pakai yang nyaman dan aman untuk digunakan.

Konsistensi kausal. Mari kita definisikan konsepnya

Untuk memulainya, saya ingin mengatakan secara umum apa itu konsistensi kausal. Ada dua karakter - Leonard dan Penny (serial TV "The Big Bang Theory"):

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Katakanlah Penny berada di Eropa dan Leonard ingin mengadakan pesta kejutan untuknya. Dan dia tidak bisa memikirkan hal yang lebih baik selain membuangnya dari daftar temannya, mengirimkan kabar terbaru ke semua temannya di feed: “Ayo buat Penny bahagia!” (dia berada di Eropa, ketika dia tidur, dia tidak melihat semua ini dan tidak dapat melihatnya, karena dia tidak ada di sana). Pada akhirnya, dia menghapus postingan ini, menghapusnya dari Feed dan memulihkan akses sehingga dia tidak melihat apa pun dan tidak ada skandal.
Ini semua baik dan bagus, tapi mari kita asumsikan bahwa sistemnya terdistribusi dan ada yang tidak beres. Misalnya, mungkin saja pembatasan akses Penny terjadi setelah postingan ini muncul, jika kejadian tersebut tidak ada hubungannya dengan sebab dan akibat. Sebenarnya, ini adalah contoh ketika konsistensi kausal diperlukan untuk menjalankan fungsi bisnis (dalam hal ini).

Faktanya, ini adalah properti database yang tidak sepele - sangat sedikit orang yang mendukungnya. Mari beralih ke modelnya.

Model Konsistensi

Apa sebenarnya model konsistensi dalam database? Ini adalah beberapa jaminan yang diberikan sistem terdistribusi mengenai data apa yang dapat diterima klien dan dalam urutan apa.

Pada prinsipnya, semua model konsistensi bermuara pada seberapa mirip sistem terdistribusi dengan sistem yang berjalan, misalnya, pada satu node di laptop. Dan betapa miripnya sistem yang berjalan pada ribuan “Node” yang terdistribusi secara geografis dengan laptop, di mana pada prinsipnya semua properti ini dijalankan secara otomatis.

Oleh karena itu, model konsistensi hanya diterapkan pada sistem terdistribusi. Semua sistem yang sebelumnya ada dan beroperasi pada skala vertikal yang sama tidak mengalami permasalahan seperti itu. Ada satu Buffer Cache, dan semuanya selalu dibaca darinya.

Model Kuat

Sebenarnya model pertama adalah Strong (atau sering disebut dengan garis kemampuan naik). Ini adalah model konsistensi yang memastikan bahwa setiap perubahan, setelah dipastikan telah terjadi, dapat dilihat oleh semua pengguna sistem.

Hal ini menciptakan tatanan global dari semua peristiwa dalam database. Ini adalah properti konsistensi yang sangat kuat, dan umumnya sangat mahal. Namun, hal ini didukung dengan sangat baik. Hanya saja harganya sangat mahal dan lambat - hanya saja jarang digunakan. Ini disebut kemampuan bangkit.

Ada properti lain yang lebih kuat yang didukung di Spanner - disebut Konsistensi Eksternal. Kita akan membicarakannya nanti.

Kausal

Yang berikutnya adalah Kausal, itulah yang saya bicarakan. Ada beberapa sub-level lagi antara Kuat dan Kausal yang tidak akan saya bicarakan, tetapi semuanya bermuara pada Kausal. Ini adalah model yang penting karena merupakan model terkuat dari semua model, konsistensi terkuat dalam keberadaan jaringan atau partisi.

Kausal sebenarnya adalah situasi di mana peristiwa-peristiwa dihubungkan oleh hubungan sebab-akibat. Sangat sering mereka dianggap sebagai Hak Baca Anda dari sudut pandang klien. Jika klien telah mengamati beberapa nilai, dia tidak dapat melihat nilai-nilai yang ada di masa lalu. Dia sudah mulai melihat pembacaan awalan. Semuanya bermuara pada hal yang sama.
Kausal sebagai model konsistensi adalah pengurutan sebagian peristiwa di server, di mana peristiwa dari semua klien diamati dalam urutan yang sama. Dalam hal ini, Leonard dan Penny.

Akhirnya

Model ketiga adalah Konsistensi Akhirnya. Inilah yang benar-benar didukung oleh semua sistem terdistribusi, model minimal yang masuk akal. Artinya sebagai berikut: ketika kita memiliki beberapa perubahan pada data, pada titik tertentu perubahan tersebut menjadi konsisten.

Pada saat seperti itu dia tidak mengatakan apa-apa, kalau tidak dia akan berubah menjadi Konsistensi Eksternal - itu akan menjadi cerita yang sama sekali berbeda. Namun demikian, ini adalah model yang sangat populer, yang paling umum. Secara default, semua pengguna sistem terdistribusi menggunakan Konsistensi Akhirnya.

Saya ingin memberikan beberapa contoh perbandingan:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Apa arti panah-panah ini?

  • Latensi. Ketika kekuatan konsistensi meningkat, kekuatannya menjadi lebih besar karena alasan yang jelas: Anda perlu membuat lebih banyak catatan, mendapatkan konfirmasi dari semua host dan node yang berpartisipasi dalam cluster bahwa data sudah ada. Oleh karena itu, Konsistensi Akhir memiliki jawaban tercepat, karena di sana, sebagai suatu peraturan, Anda bahkan dapat memasukkannya ke dalam memori dan ini, pada prinsipnya, sudah cukup.
  • Tersedianya. Jika kita memahami ini sebagai kemampuan sistem untuk merespons jika ada kerusakan jaringan, partisi, atau semacam kegagalan, toleransi kesalahan meningkat seiring dengan menurunnya model konsistensi, karena bagi kita cukup satu host hidup dan pada saat yang sama. waktu menghasilkan beberapa data. Konsistensi Akhir tidak menjamin apa pun tentang data - bisa apa saja.
  • Anomali. Pada saat yang sama, tentu saja, jumlah anomali semakin meningkat. Dalam Konsistensi Kuat mereka seharusnya tidak ada sama sekali, tetapi dalam Konsistensi Akhirnya mereka bisa menjadi apa saja. Timbul pertanyaan: mengapa orang memilih Konsistensi Akhir jika mengandung anomali? Jawabannya adalah model Konsistensi Akhir dapat diterapkan dan terdapat anomali, misalnya dalam jangka waktu singkat; dimungkinkan untuk menggunakan wizard untuk membaca dan kurang lebih membaca data yang konsisten; Seringkali dimungkinkan untuk menggunakan model konsistensi yang kuat. Dalam praktiknya, hal ini berhasil, dan seringkali jumlah anomali dibatasi oleh waktu.

teorema CAP

Ketika Anda melihat kata konsistensi, ketersediaan – apa yang terlintas di benak Anda? Benar - teorema CAP! Sekarang saya ingin menghilangkan mitos tersebut... Bukan saya - melainkan Martin Kleppmann, yang menulis artikel yang luar biasa, sebuah buku yang luar biasa.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Teorema CAP merupakan prinsip yang dirumuskan pada tahun 2000-an yaitu Konsistensi, Ketersediaan, Partisi: ambil dua apa saja, dan Anda tidak bisa memilih tiga. Itu adalah prinsip tertentu. Hal ini dibuktikan sebagai teorema beberapa tahun kemudian oleh Gilbert dan Lynch. Kemudian ini mulai digunakan sebagai mantra – sistem mulai dibagi menjadi CA, CP, AP dan seterusnya.

Teorema ini sebenarnya terbukti untuk kasus berikut... Pertama, Ketersediaan dianggap bukan sebagai nilai kontinu dari nol hingga ratusan (0 - sistem "mati", 100 - merespons dengan cepat; kami terbiasa menganggapnya seperti itu) , tetapi sebagai properti algoritme, yang menjamin bahwa untuk semua eksekusinya, ia mengembalikan data.

Tidak ada sepatah kata pun tentang waktu respons sama sekali! Ada algoritma yang mengembalikan data setelah 100 tahun - algoritma yang tersedia benar-benar luar biasa, yang merupakan bagian dari teorema CAP.
Kedua: teorema terbukti untuk perubahan nilai kunci yang sama, meskipun perubahan tersebut dapat diubah ukurannya. Artinya pada kenyataannya praktis tidak digunakan, karena modelnya berbeda Konsistensi Akhirnya, Konsistensi Kuat (mungkin).

Untuk apa semua ini? Selain itu, teorema CAP dalam bentuk yang dibuktikan secara praktis tidak dapat diterapkan dan jarang digunakan. Dalam bentuk teoretis, hal itu membatasi segalanya. Ternyata suatu prinsip tertentu secara intuitif benar, namun secara umum belum terbukti.

Konsistensi kausal adalah model yang paling kuat

Apa yang terjadi sekarang adalah Anda bisa mendapatkan ketiga hal tersebut: Konsistensi, Ketersediaan menggunakan Partisi. Secara khusus, konsistensi kausal adalah model konsistensi terkuat, yang masih berfungsi dengan adanya Partisi (putusnya jaringan). Itulah mengapa hal ini sangat menarik, dan itulah sebabnya kami mengambilnya.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Pertama, menyederhanakan pekerjaan pengembang aplikasi. Secara khusus, adanya dukungan besar dari server: ketika semua catatan yang terjadi di dalam satu klien dijamin tiba dalam urutan yang sama di klien lain. Kedua, tahan terhadap partisi.

Dapur Internal MongoDB

Mengingat ini sudah makan siang, kami pindah ke dapur. Saya akan memberi tahu Anda tentang model sistem, yaitu apa itu MongoDB bagi mereka yang baru pertama kali mendengar tentang database semacam itu.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

MongoDB (selanjutnya disebut “MongoDB”) adalah sistem terdistribusi yang mendukung penskalaan horizontal, yaitu sharding; dan di dalam setiap pecahan juga mendukung redundansi data, yaitu replikasi.

Sharding di MongoDB (bukan database relasional) melakukan penyeimbangan otomatis, yaitu, setiap kumpulan dokumen (atau "tabel" dalam istilah data relasional) dibagi menjadi beberapa bagian, dan server secara otomatis memindahkannya antar shard.

Router Kueri, yang mendistribusikan permintaan, untuk klien adalah beberapa klien yang melaluinya ia bekerja. Ia sudah mengetahui di mana dan data apa yang berada dan mengarahkan semua permintaan ke pecahan yang benar.

Poin penting lainnya: MongoDB adalah master tunggal. Ada satu Primer - dapat mengambil catatan yang mendukung kunci yang dikandungnya. Anda tidak dapat melakukan penulisan Multi-master.

Kami membuat rilis 4.2 - hal-hal baru yang menarik muncul di sana. Secara khusus, mereka memasukkan Lucene - pencarian - yaitu java yang dapat dieksekusi langsung ke Mongo, dan di sana dimungkinkan untuk melakukan pencarian melalui Lucene, sama seperti di Elastica.

Dan mereka membuat produk baru - Charts, juga tersedia di Atlas (Cloud milik Mongo). Mereka memiliki Tingkat Gratis - Anda dapat bermain-main dengannya. Saya sangat menyukai Grafik - visualisasi data, sangat intuitif.

Bahan Konsistensi kausal

Saya menghitung sekitar 230 artikel yang telah diterbitkan tentang topik ini - dari Leslie Lampert. Sekarang dari ingatan saya, saya akan menyampaikan kepada Anda beberapa bagian dari materi ini.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Semuanya berawal dari artikel Leslie Lampert yang ditulis pada tahun 1970-an. Seperti yang Anda lihat, beberapa penelitian tentang topik ini masih berlangsung. Sekarang konsistensi kausal mendapat perhatian sehubungan dengan pengembangan sistem terdistribusi.

Pembatasan

Batasan apa saja yang ada? Hal ini sebenarnya menjadi salah satu poin utama, karena pembatasan yang diberlakukan suatu sistem produksi sangat berbeda dengan pembatasan yang ada pada artikel akademis. Seringkali mereka dibuat-buat.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

  • Pertama, “MongoDB” adalah master tunggal, seperti yang telah saya katakan (ini sangat menyederhanakan).
  • Kami percaya bahwa sistem harus mendukung sekitar 10 ribu pecahan. Kami tidak dapat membuat keputusan arsitektur apa pun yang secara eksplisit membatasi nilai ini.
  • Kami memiliki cloud, tetapi kami berasumsi bahwa seseorang masih memiliki kesempatan ketika dia mengunduh biner, menjalankannya di laptopnya, dan semuanya berfungsi dengan baik.
  • Kami berasumsi sesuatu yang jarang diasumsikan oleh Riset: klien eksternal dapat melakukan apa pun yang mereka inginkan. MongoDB adalah sumber terbuka. Oleh karena itu, klien bisa menjadi sangat pintar dan marah - mereka ingin menghancurkan segalanya. Kami berspekulasi bahwa Feilor Bizantium mungkin berasal.
  • Untuk klien eksternal yang berada di luar perimeter, ada batasan penting: jika fitur ini dinonaktifkan, maka tidak ada penurunan kinerja yang terlihat.
  • Hal lain yang umumnya anti-akademik: kompatibilitas versi sebelumnya dan versi mendatang. Driver lama harus mendukung pembaruan baru, dan database harus mendukung driver lama.

Secara umum, semua ini memberlakukan batasan.

Komponen konsistensi kausal

Sekarang saya akan berbicara tentang beberapa komponen. Jika kita mempertimbangkan konsistensi kausal secara umum, kita dapat memilih blok. Kami memilih dari karya-karya yang termasuk dalam blok tertentu: Pelacakan Ketergantungan, memilih jam, bagaimana jam-jam ini dapat disinkronkan satu sama lain, dan bagaimana kami memastikan keamanan - ini adalah garis besar dari apa yang akan saya bicarakan:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Pelacakan Ketergantungan Penuh

Mengapa itu diperlukan? Sehingga ketika data direplikasi, setiap record, setiap perubahan data berisi informasi tentang perubahan apa yang bergantung padanya. Perubahan pertama dan naif adalah ketika setiap pesan yang berisi catatan berisi informasi tentang pesan sebelumnya:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Dalam contoh ini, angka dalam tanda kurung kurawal adalah angka rekaman. Terkadang catatan dengan nilai ini bahkan ditransfer secara keseluruhan, terkadang beberapa versi ditransfer. Intinya adalah bahwa setiap perubahan berisi informasi tentang perubahan sebelumnya (jelas membawa semua ini ke dalam dirinya sendiri).

Mengapa kami memutuskan untuk tidak menggunakan pendekatan ini (pelacakan penuh)? Tentu saja, karena pendekatan ini tidak praktis: perubahan apa pun pada jejaring sosial bergantung pada semua perubahan sebelumnya pada jejaring sosial tersebut, yang ditransfer, katakanlah, Facebook atau VKontakte di setiap pembaruan. Namun demikian, ada banyak penelitian tentang Pelacakan Ketergantungan Penuh – ini adalah jaringan pra-sosial; untuk beberapa situasi ini benar-benar berfungsi.

Pelacakan Ketergantungan Eksplisit

Yang berikutnya lebih terbatas. Transfer informasi juga dipertimbangkan di sini, tetapi hanya informasi yang jelas-jelas bergantung. Tergantung pada apa, sebagai suatu peraturan, ditentukan oleh Aplikasi. Ketika data direplikasi, kueri hanya mengembalikan respons ketika dependensi sebelumnya telah dipenuhi, yaitu ditampilkan. Inilah inti cara kerja konsistensi kausal.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Dia melihat bahwa catatan 5 bergantung pada catatan 1, 2, 3, 4 - oleh karena itu, dia menunggu sampai klien memiliki akses ke perubahan yang dibuat oleh keputusan akses Penny, ketika semua perubahan sebelumnya telah melewati database.

Ini juga tidak cocok untuk kita, karena informasinya masih terlalu banyak dan akan memperlambat segalanya. Ada pendekatan lain...

Jam Lamport

Mereka sudah sangat tua. Lamport Clock berarti dependensi ini dilipat menjadi fungsi skalar, yang disebut Lamport Clock.

Fungsi skalar adalah bilangan abstrak. Ini sering disebut waktu logis. Dengan setiap peristiwa, penghitung ini meningkat. Counter, yang saat ini diketahui oleh proses, mengirimkan setiap pesan. Jelas bahwa proses mungkin tidak sinkron, mungkin memiliki waktu yang sangat berbeda. Namun demikian, sistem entah bagaimana menyeimbangkan waktu dengan pesan seperti itu. Apa yang terjadi dalam kasus ini?

Saya membagi pecahan besar itu menjadi dua untuk memperjelas: Teman dapat tinggal di satu node, yang berisi bagian dari koleksi, dan Umpan dapat tinggal di node lain, yang berisi bagian dari koleksi ini. Apakah sudah jelas bagaimana mereka bisa keluar dari barisan? Umpan pertama akan mengatakan: “Direplikasi”, dan kemudian Teman. Jika sistem tidak memberikan jaminan bahwa Umpan tidak akan ditampilkan sampai ketergantungan Teman di koleksi Teman juga dikirimkan, maka kita akan mengalami situasi persis seperti yang saya sebutkan.

Anda melihat bagaimana waktu penghitung di Feed meningkat secara logis:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Jadi sifat utama dari Jam Lamport dan konsistensi Kausal ini (dijelaskan melalui Jam Lamport) adalah sebagai berikut: jika kita mempunyai Peristiwa A dan B, dan Peristiwa B bergantung pada Peristiwa A*, maka Waktu Logis Peristiwa A kurang dari Waktu Logis dari Peristiwa B.

* Kadang-kadang mereka juga mengatakan bahwa A terjadi sebelum B, yaitu A terjadi sebelum B - ini adalah hubungan tertentu yang mengurutkan sebagian seluruh rangkaian peristiwa yang terjadi secara umum.

Yang sebaliknya tidak benar. Ini sebenarnya salah satu kelemahan utama Jam Lamport - pesanan parsial. Ada konsep tentang peristiwa serentak, yaitu peristiwa yang tidak terjadi (A terjadi sebelum B) maupun (A terjadi sebelum B). Contohnya adalah penambahan orang lain secara paralel oleh Leonard sebagai teman (bahkan bukan Leonard, tapi Sheldon, misalnya).
Ini adalah properti yang sering digunakan ketika bekerja dengan jam Lamport: mereka melihat secara spesifik fungsinya dan dari sini mereka menyimpulkan bahwa mungkin kejadian-kejadian ini bergantung. Karena ada satu cara yang benar: jika LogicalTime A lebih kecil dari LogicalTime B, maka B tidak dapat terjadi sebelum A; dan jika lebih, maka mungkin.

Jam Vektor

Perkembangan logis dari jam Lamport adalah Jam Vektor. Mereka berbeda karena setiap node yang ada di sini berisi jamnya sendiri-sendiri, dan ditransmisikan sebagai vektor.
Dalam hal ini, Anda melihat bahwa indeks ke nol dari vektor bertanggung jawab atas Umpan, dan indeks pertama dari vektor bertanggung jawab untuk Teman (masing-masing node ini). Dan sekarang mereka akan meningkat: indeks nol “Umpan” meningkat saat menulis – 1, 2, 3:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Mengapa Jam Vektor lebih baik? Karena mereka memungkinkan Anda mengetahui peristiwa mana yang terjadi secara bersamaan dan kapan terjadi pada node yang berbeda. Ini sangat penting untuk sistem sharding seperti MongoDB. Namun, kami tidak memilih ini, meskipun ini adalah hal yang luar biasa, dan berfungsi dengan baik, dan mungkin cocok untuk kami...

Jika kita memiliki 10 ribu pecahan, kita tidak dapat mentransfer 10 ribu komponen, meskipun kita mengompresnya atau membuat sesuatu yang lain - muatannya akan tetap beberapa kali lebih kecil dari volume keseluruhan vektor ini. Oleh karena itu, sambil mengertakkan hati dan gigi, kami meninggalkan pendekatan ini dan beralih ke pendekatan lain.

Kunci Pas TrueTime. Jam atom

Saya bilang akan ada cerita tentang Spanner. Ini adalah hal yang keren, langsung dari abad ke-XNUMX: jam atom, sinkronisasi GPS.

Apa idenya? "Spanner" adalah sistem Google yang baru-baru ini tersedia untuk orang-orang (mereka menambahkan SQL ke dalamnya). Setiap transaksi di sana memiliki cap waktu tertentu. Karena waktu disinkronkan*, setiap peristiwa dapat ditetapkan waktu tertentu - jam atom mempunyai waktu tunggu, setelah itu waktu yang berbeda dijamin akan “terjadi”.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Jadi, hanya dengan menulis ke database dan menunggu beberapa saat, Serializability acara dijamin secara otomatis. Mereka memiliki model Konsistensi terkuat yang dapat dibayangkan secara prinsip - yaitu Konsistensi Eksternal.

* Ini adalah masalah utama dengan jam Lampart - jam tersebut tidak pernah sinkron pada sistem terdistribusi. Mereka bisa berbeda; bahkan dengan NTP, mereka masih tidak bekerja dengan baik. "Spanner" memiliki jam atom dan sinkronisasi, tampaknya, adalah mikrodetik.

Mengapa kita tidak memilih? Kami tidak berasumsi bahwa pengguna kami memiliki jam atom bawaan. Ketika muncul, terpasang di setiap laptop, akan ada semacam sinkronisasi GPS yang sangat keren - lalu ya... Tapi untuk saat ini yang terbaik adalah Amazon, Stasiun Pangkalan - untuk para fanatik... Jadi kami menggunakan jam tangan lain .

Jam Hibrid

Ini sebenarnya yang terjadi di MongoDB ketika memastikan konsistensi kausal. Bagaimana cara mereka hibrida? Hibrid adalah nilai skalar, namun memiliki dua komponen:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

  • Yang pertama adalah zaman Unix (berapa detik telah berlalu sejak “awal dunia komputer”).
  • Yang kedua adalah beberapa kenaikan, juga int 32-bit yang tidak ditandatangani.

Sebenarnya itu saja. Ada pendekatan ini: bagian yang bertanggung jawab atas waktu disinkronkan dengan jam sepanjang waktu; setiap kali terjadi pembaruan, bagian ini disinkronkan dengan jam dan ternyata waktunya selalu kurang lebih tepat, dan kenaikan memungkinkan Anda membedakan peristiwa yang terjadi pada titik waktu yang sama.

Mengapa ini penting untuk MongoDB? Karena memungkinkan Anda membuat beberapa cadangan restoran pada titik waktu tertentu, yaitu acara diindeks berdasarkan waktu. Hal ini penting ketika peristiwa tertentu diperlukan; Untuk database, event adalah perubahan pada database yang terjadi pada interval waktu tertentu.

Saya akan memberi tahu Anda alasan yang paling penting hanya untuk Anda (tolong, jangan beri tahu siapa pun)! Kami melakukan ini karena seperti inilah data yang terorganisir dan terindeks di MongoDB OpLog. OpLog adalah struktur data yang benar-benar berisi semua perubahan dalam database: perubahan tersebut pertama-tama masuk ke OpLog, dan kemudian diterapkan ke Penyimpanan itu sendiri jika itu adalah tanggal atau pecahan yang direplikasi.

Inilah alasan utamanya. Namun, ada juga persyaratan praktis untuk mengembangkan database, yang berarti database harus sederhana - sedikit kode, sesedikit mungkin kerusakan yang perlu ditulis ulang dan diuji. Fakta bahwa oplog kami diindeks oleh jam hybrid sangat membantu dan memungkinkan kami membuat pilihan yang tepat. Itu benar-benar terbayar dan entah bagaimana secara ajaib berhasil pada prototipe pertama. Itu sangat keren!

Sinkronisasi jam

Ada beberapa metode sinkronisasi yang dijelaskan dalam literatur ilmiah. Saya berbicara tentang sinkronisasi ketika kita memiliki dua pecahan yang berbeda. Jika ada satu set replika, tidak diperlukan sinkronisasi apa pun: ini adalah “master tunggal”; kami memiliki OpLog, di mana semua perubahan terjadi - dalam hal ini, semuanya sudah diurutkan secara berurutan di "Oplog" itu sendiri. Namun jika kita memiliki dua shard yang berbeda, sinkronisasi waktu penting di sini. Di sinilah jam vektor lebih membantu! Tapi kami tidak memilikinya.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Yang kedua cocok - ini adalah "Detak Jantung". Dimungkinkan untuk bertukar beberapa sinyal yang terjadi setiap satuan waktu. Namun Detak Jantung terlalu lambat, kami tidak dapat memberikan latensi kepada klien kami.

Waktu yang sebenarnya, tentu saja, adalah hal yang menakjubkan. Tapi, sekali lagi, ini mungkin masa depan... Meski sudah bisa dilakukan di Atlas, sudah ada sinkronisasi waktu “Amazon” yang cepat. Tapi itu tidak akan tersedia untuk semua orang.

Bergosip adalah ketika semua pesan menyertakan waktu. Ini kira-kira yang kami gunakan. Setiap pesan antar node, driver, router node data, semuanya untuk MongoDB adalah semacam elemen, komponen database yang berisi jam yang berjalan. Mereka memiliki arti waktu hibrida di mana-mana, itu ditransmisikan. 64 bit? Ini memungkinkan, ini mungkin.

Bagaimana semuanya bekerja sama?

Di sini saya melihat satu set replika untuk membuatnya lebih mudah. Ada Primer dan Sekunder. Sekunder melakukan replikasi dan tidak selalu tersinkronisasi sepenuhnya dengan Primer.

Penyisipan terjadi ke dalam “Primery” dengan nilai waktu tertentu. Sisipan ini menambah hitungan internal sebesar 11, jika ini adalah jumlah maksimum. Atau akan memeriksa nilai jam dan menyinkronkan ke jam jika nilai jamnya lebih besar. Ini memungkinkan Anda mengatur berdasarkan waktu.

Setelah dia membuat rekaman, terjadilah momen penting. Jamnya ada di "MongoDB" dan bertambah hanya jika ditulis ke "Oplog". Ini adalah peristiwa yang mengubah keadaan sistem. Di semua artikel klasik, suatu peristiwa dianggap ketika sebuah pesan mencapai sebuah node: pesan telah tiba, yang berarti sistem telah mengubah statusnya.

Hal ini disebabkan oleh fakta bahwa selama penelitian tidak sepenuhnya jelas bagaimana pesan ini akan ditafsirkan. Kita tahu pasti jika tidak tercermin di “Oplog”, maka tidak akan diinterpretasikan dengan cara apapun, dan perubahan status sistem hanya masuk ke “Oplog”. Ini menyederhanakan segalanya bagi kami: model menyederhanakannya, dan memungkinkan kami mengaturnya dalam satu set replika, dan banyak hal berguna lainnya.

Nilai yang sudah ditulis ke "Oplog" dikembalikan - kita tahu bahwa "Oplog" sudah berisi nilai ini, dan waktunya adalah 12. Sekarang, katakanlah, pembacaan dimulai dari node lain (Sekunder), dan ditransmisikan setelahClusterTime di pesannya. Dia berkata: "Saya membutuhkan segala sesuatu yang terjadi setidaknya setelah jam 12 atau selama dua belas" (lihat gambar di atas).

Inilah yang disebut dengan Causal a Consistent (CAT). Ada konsep dalam teori bahwa ini adalah suatu potongan waktu, yang konsisten dengan sendirinya. Dalam hal ini, kita dapat mengatakan bahwa ini adalah keadaan sistem yang diamati pada waktu 12.

Sekarang belum ada apa-apa di sini, karena ini mensimulasikan situasi ketika Anda memerlukan Sekunder untuk mereplikasi data dari Primer. Dia menunggu... Dan sekarang datanya telah tiba - dia mengembalikan nilai-nilai ini.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Begitulah cara kerjanya. Hampir.

Apa maksudnya "hampir"? Mari kita asumsikan bahwa ada seseorang yang telah membaca dan memahami cara kerja semua ini. Saya menyadari bahwa setiap kali ClusterTime terjadi, ia memperbarui jam logis internal, dan kemudian entri berikutnya bertambah satu. Fungsi ini membutuhkan 20 baris. Katakanlah orang ini mengirimkan angka 64-bit terbesar, dikurangi satu.

Mengapa "minus satu"? Karena jam internal akan diganti ke dalam nilai ini (tentu saja, ini adalah kemungkinan terbesar dan lebih besar dari waktu saat ini), maka entri akan terjadi di "Oplog", dan jam akan bertambah satuan lagi - dan sudah akan ada menjadi nilai maksimum (hanya ada semua unit, tidak ada tempat lain untuk dituju) , unsaint ints).

Jelas bahwa setelah itu sistem menjadi benar-benar tidak dapat diakses untuk apa pun. Itu hanya bisa dibongkar dan dibersihkan - banyak pekerjaan manual. Ketersediaan penuh:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Terlebih lagi, jika hal ini direplikasi di tempat lain, maka seluruh cluster akan runtuh. Situasi yang benar-benar tidak dapat diterima yang dapat diatur oleh siapa pun dengan sangat cepat dan mudah! Oleh karena itu, kami menganggap momen ini sebagai salah satu momen terpenting. Bagaimana cara mencegahnya?

Cara kami adalah dengan menandatangani clusterTime

Beginilah cara penyampaiannya dalam pesan (sebelum teks biru). Namun kami juga mulai membuat tanda tangan (teks biru):

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Tanda tangan dihasilkan oleh kunci yang disimpan di dalam database, di dalam batas aman; itu sendiri dibuat dan diperbarui (pengguna tidak melihat apa pun tentangnya). Hash dihasilkan, dan setiap pesan ditandatangani saat dibuat dan divalidasi saat diterima.
Pertanyaan yang mungkin muncul di benak orang-orang: “Seberapa besar hal ini memperlambat?” Sudah saya katakan bahwa ini akan bekerja dengan cepat, terutama jika tidak ada fitur ini.

Apa yang dimaksud dengan penggunaan konsistensi kausal dalam kasus ini? Ini untuk menampilkan parameter afterClusterTime. Tanpa ini, itu hanya akan meneruskan nilai. Gosip, mulai dari versi 3.6, selalu berhasil.

Jika kita membiarkan pembuatan tanda tangan terus-menerus, hal ini akan memperlambat sistem meskipun tidak ada fitur, yang tidak memenuhi pendekatan dan persyaratan kami. Jadi apa yang kita lakukan?

Lakukan dengan cepat!

Memang cukup sederhana, namun triknya menarik. Saya akan membagikannya, mungkin ada yang tertarik.
Kami memiliki hash yang menyimpan data yang ditandatangani. Semua data melewati cache. Cache tidak menandatangani waktu tertentu, tetapi Rentangnya. Ketika beberapa nilai tiba, kami membuat Range, menutupi 16 bit terakhir, dan kami menandatangani nilai ini:

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Dengan menerima tanda tangan seperti itu, kami mempercepat sistem (relatif) 65 ribu kali lipat. Ini berfungsi dengan baik: saat kami melakukan eksperimen, waktu sebenarnya berkurang 10 ribu kali lipat saat kami melakukan pembaruan berurutan. Jelas bahwa ketika mereka berselisih, hal ini tidak berhasil. Namun dalam sebagian besar kasus praktis, ini berhasil. Kombinasi tanda tangan Range dan tanda tangan memecahkan masalah keamanan.

Apa yang telah kita pelajari?

Pelajaran yang kami dapat dari ini:

  • Materi, cerita, artikel perlu kita baca, karena banyak hal menarik yang kita dapatkan. Saat kita mengerjakan suatu fitur (apalagi saat ini, saat kita melakukan transaksi, dll), kita perlu membaca dan memahaminya. Memang butuh waktu, tapi sebenarnya sangat berguna karena memperjelas keberadaan kita. Sepertinya kami tidak menemukan sesuatu yang baru – kami hanya mengambil bahan-bahannya.

    Secara umum, ada perbedaan pemikiran tertentu ketika ada konferensi akademik (Sigmon, misalnya) - setiap orang fokus pada ide-ide baru. Apa yang baru tentang algoritma kami? Tidak ada hal baru di sini. Kebaruannya terletak pada cara kami memadukan pendekatan-pendekatan yang sudah ada. Oleh karena itu, hal pertama yang harus dilakukan adalah membaca karya klasik, dimulai dengan Lampart.

  • Dalam produksi, persyaratannya sangat berbeda. Saya yakin banyak dari Anda tidak dihadapkan dengan database “bulat” dalam ruang hampa abstrak, tetapi dengan hal-hal normal dan nyata yang memiliki masalah dengan ketersediaan, latensi, dan toleransi kesalahan.
  • Hal terakhir adalah kami harus mempertimbangkan ide-ide yang berbeda dan menggabungkan beberapa artikel yang sangat berbeda ke dalam satu pendekatan secara bersamaan. Gagasan tentang penandatanganan, misalnya, umumnya berasal dari sebuah artikel yang membahas tentang protokol Paxos, yang untuk non-Bizantium yang Gagal berada di dalam protokol otorisasi, untuk yang Bizantium - di luar protokol otorisasi... Secara umum, inilah yang kami lakukan akhirnya melakukan.

    Sama sekali tidak ada hal baru di sini! Tapi begitu kita mencampur semuanya... Sama saja dengan mengatakan bahwa resep salad Olivier itu tidak masuk akal, karena telur, mayones, dan mentimun sudah ditemukan... Ceritanya hampir sama.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Saya akan menyelesaikannya dengan ini. Terima kasih!

pertanyaan

Pertanyaan dari penonton (selanjutnya disebut B): – Terima kasih, Mikhail, atas laporannya! Topik tentang waktu memang menarik. Anda menggunakan Gosip. Mereka bilang setiap orang punya waktunya masing-masing, semua orang tahu waktu setempatnya. Sejauh yang saya pahami, kami memiliki driver - mungkin ada banyak klien dengan driver, perencana kueri juga, pecahan juga... Dan apa yang akan dilakukan sistem jika kami tiba-tiba mengalami perbedaan: seseorang memutuskan bahwa itu untuk a satu menit di depan, seseorang satu menit di belakang? Dimana kita akan berakhir?

MT: – Pertanyaan yang bagus sekali! Saya hanya ingin berbicara tentang pecahan. Jika saya memahami pertanyaan dengan benar, kita memiliki situasi berikut: ada pecahan 1 dan pecahan 2, pembacaan terjadi dari dua pecahan ini - keduanya memiliki ketidaksesuaian, tidak berinteraksi satu sama lain, karena waktu yang mereka ketahui berbeda, terutama saat mereka ada di oplog.
Katakanlah shard 1 menghasilkan satu juta rekaman, shard 2 tidak melakukan apa pun, dan permintaan mencapai dua shard. Dan yang pertama memiliki afterClusterTime lebih dari satu juta. Dalam situasi seperti itu, seperti yang saya jelaskan, shard 2 tidak akan pernah merespons sama sekali.

Dalam: – Saya ingin tahu bagaimana mereka menyinkronkan dan memilih satu waktu yang logis?

MT: - Sangat mudah untuk disinkronkan. Shard, ketika afterClusterTime datang kepadanya dan dia tidak menemukan waktu di "Oplog", inisiasi tidak disetujui. Artinya, dia meningkatkan waktunya dengan tangannya ke nilai ini. Artinya tidak ada kejadian yang cocok dengan permintaan ini. Dia menciptakan peristiwa ini secara artifisial dan dengan demikian menjadi Konsisten Kausal.

Dalam: – Bagaimana jika setelah ini ada kejadian lain yang hilang di suatu tempat di jaringan datang kepadanya?

MT: – Shard dirancang sedemikian rupa sehingga tidak akan datang lagi, karena merupakan master tunggal. Kalau dia sudah mendaftar, maka mereka tidak akan datang, tapi akan datang nanti. Tidak mungkin ada sesuatu yang terjebak di suatu tempat, kemudian dia tidak menulis, dan kemudian peristiwa-peristiwa ini tiba - dan konsistensi Kausal rusak. Ketika dia tidak menulis, mereka semua harus datang berikutnya (dia akan menunggu mereka).

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Dalam: – Saya punya beberapa pertanyaan tentang antrian. Konsistensi kausal mengasumsikan adanya rangkaian tindakan tertentu yang perlu dilakukan. Apa yang terjadi jika salah satu paket kami hilang? Inilah tanggal 10, 11... tanggal 12 telah menghilang, dan semua orang menunggu hal itu menjadi kenyataan. Dan tiba-tiba mobil kami mati, kami tidak bisa berbuat apa-apa. Apakah ada panjang antrian maksimum yang terakumulasi sebelum dieksekusi? Kegagalan fatal apa yang terjadi ketika salah satu negara bagian hilang? Terlebih lagi, jika kita menuliskan bahwa ada suatu keadaan sebelumnya, maka kita harus memulainya dari sana? Tapi mereka tidak mengusirnya!

MT: – Juga pertanyaan yang bagus! Apa yang kita lakukan? MongoDB memiliki konsep kuorum tulis, kuorum baca. Kapan pesan bisa hilang? Ketika penulisan tidak mencapai kuorum atau ketika pembacaan tidak mencapai kuorum (beberapa jenis sampah mungkin juga menempel).
Mengenai konsistensi kausal, telah dilakukan uji eksperimental besar-besaran, yang hasilnya adalah jika penulisan dan pembacaan tidak kuorum, terjadi pelanggaran konsistensi kausal. Persis seperti yang Anda katakan!

Saran kami: gunakan setidaknya kuorum bacaan saat menggunakan konsistensi kausal. Dalam hal ini, tidak ada yang akan hilang, bahkan jika catatan kuorum hilang... Ini adalah situasi ortogonal: jika pengguna tidak ingin datanya hilang, ia perlu menggunakan catatan kuorum. Konsistensi kausal tidak menjamin ketahanan. Daya tahan dijamin melalui replikasi dan mesin yang terkait dengan replikasi.

Dalam: – Saat kita membuat sebuah instance yang melakukan sharding untuk kita (masing-masing bukan master, melainkan slave), instance tersebut bergantung pada waktu Unix dari mesinnya sendiri atau pada waktu “master”; Apakah ini disinkronkan untuk pertama kali atau secara berkala?

MT: – Saya akan mengklarifikasi sekarang. Shard (yaitu partisi horizontal) – selalu ada Primer di sana. Dan sebuah pecahan bisa memiliki "master" dan bisa juga ada replikanya. Namun shard selalu mendukung perekaman, karena harus mendukung beberapa domain (shard memiliki Primer).

Dalam: – Jadi semuanya tergantung sepenuhnya pada “master”? Apakah waktu master selalu digunakan?

MT: - Ya. Secara kiasan Anda dapat mengatakan: jam terus berdetak ketika entri ke "master", ke "Oplog" terjadi.

Dalam: – Kami memiliki klien yang terhubung dan tidak perlu tahu apa pun tentang waktu?

MT: – Anda tidak perlu tahu apa pun! Jika kita berbicara tentang cara kerjanya pada klien: ketika klien ingin menggunakan konsistensi Kausal, dia perlu membuka sesi. Sekarang semuanya ada di sana: transaksi dalam sesi, dan mengambil hak... Sesi adalah urutan peristiwa logis yang terjadi dengan klien.

Jika dia membuka sesi ini dan mengatakan di sana bahwa dia menginginkan konsistensi Kausal (jika sesi mendukung konsistensi Kausal secara default), semuanya bekerja secara otomatis. Pengemudi mengingat waktu ini dan menambahnya ketika menerima pesan baru. Ia mengingat respons apa yang dikembalikan sebelumnya dari server yang mengembalikan data. Permintaan berikutnya akan berisi afterCluster("waktu lebih besar dari ini").

Klien tidak perlu mengetahui apa pun! Ini sama sekali tidak jelas baginya. Jika orang menggunakan fitur ini, apa yang dapat mereka lakukan? Pertama, Anda dapat membaca sekunder dengan aman: Anda dapat menulis ke Primer dan membaca dari sekunder yang direplikasi secara geografis dan memastikannya berfungsi. Pada saat yang sama, sesi yang direkam di Primer bahkan dapat ditransfer ke Sekunder, yaitu Anda tidak dapat menggunakan satu sesi, tetapi beberapa sesi.

Dalam: – Lapisan baru ilmu Komputasi – tipe data CRDT (Tipe Data Replikasi Bebas Konflik) – sangat terkait dengan topik konsistensi Akhirnya. Sudahkah Anda mempertimbangkan untuk mengintegrasikan jenis data ini ke dalam database dan apa yang dapat Anda katakan tentang hal itu?

MT: - Pertanyaan bagus! CRDT masuk akal untuk konflik tulis: di MongoDB, master tunggal.

Dalam: – Saya punya pertanyaan dari para devops. Di dunia nyata, ada situasi Jesuit ketika Kegagalan Bizantium terjadi, dan orang-orang jahat di dalam perimeter yang dilindungi mulai menyusup ke dalam protokol, mengirim paket kerajinan dengan cara khusus?

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

MT: – Orang jahat di dalam perimeter itu seperti kuda Troya! Orang jahat di dalam perimeter bisa melakukan banyak hal buruk.

Dalam: – Jelas bahwa meninggalkan, secara kasar, sebuah lubang di server di mana Anda dapat menempatkan kebun binatang gajah dan meruntuhkan seluruh cluster selamanya... Ini akan memakan waktu untuk pemulihan manual... Ini, secara halus, adalah salah. Di sisi lain, ini menarik: dalam kehidupan nyata, dalam praktiknya, adakah situasi ketika serangan internal serupa secara alami terjadi?

MT: – Karena saya jarang menemukan pelanggaran keamanan dalam kehidupan nyata, saya tidak bisa memastikan apakah hal itu benar-benar terjadi. Namun jika kita berbicara tentang filosofi pembangunan, kita berpikir seperti ini: kita memiliki batas yang memberikan keamanan kepada orang-orang - ini adalah kastil, tembok; dan di dalam perimeter Anda dapat melakukan apa pun yang Anda inginkan. Jelas ada pengguna yang hanya bisa melihat, dan ada pengguna yang punya kemampuan menghapus direktori.

Tergantung pada haknya, kerusakan yang dapat ditimbulkan oleh pengguna bisa berupa tikus, atau bisa juga gajah. Jelas bahwa pengguna dengan hak penuh dapat melakukan apa saja. Pengguna dengan hak terbatas dapat menyebabkan lebih sedikit kerugian. Secara khusus, ini tidak dapat merusak sistem.

Dalam: – Di perimeter yang dilindungi, seseorang mencoba membuat protokol yang tidak terduga untuk server untuk menghancurkan server sepenuhnya, dan jika Anda beruntung, seluruh cluster... Apakah hal itu bisa menjadi “bagus”?

MT: “Saya belum pernah mendengar hal seperti itu.” Fakta bahwa Anda dapat membuat server crash dengan cara ini bukanlah rahasia lagi. Gagal di dalam, dari protokol, menjadi pengguna resmi yang bisa menulis sesuatu seperti ini di pesan.. Sebenarnya tidak mungkin, karena masih akan diverifikasi. Dimungkinkan untuk menonaktifkan otentikasi ini untuk pengguna yang tidak menginginkannya - maka itu adalah masalah mereka; mereka, secara kasar, menghancurkan tembok itu sendiri dan Anda dapat mendorong seekor gajah ke sana, yang akan menginjak-injak... Tapi secara umum, Anda bisa berpakaian seperti tukang reparasi, datang dan menariknya keluar!

Dalam: – Terima kasih atas laporannya. Sergei (Yandex). Terdapat sebuah konstanta di Mong yang membatasi jumlah anggota yang mempunyai hak suara di Replica Set, dan konstanta tersebut adalah 7 (tujuh). Mengapa ini bersifat konstan? Mengapa ini bukan semacam parameter?

MT: – Kami memiliki Set Replika dengan 40 node. Selalu ada mayoritas. Saya tidak tahu versi yang mana...

Dalam: – Di Replica Set bisa menjalankan non-voting member, tapi maksimal 7 voting member. Bagaimana kita bisa selamat dari shutdown jika Replica Set kita tersebar di 3 data center? Satu pusat data dapat mati dengan mudah, dan mesin lainnya dapat mati.

MT: – Hal ini sedikit di luar cakupan laporan. Ini adalah pertanyaan umum. Mungkin aku bisa menceritakannya padamu nanti.

HighLoad++, Mikhail Tyulenev (MongoDB): Konsistensi kausal: dari teori hingga praktik

Beberapa iklan 🙂

Terima kasih untuk tetap bersama kami. Apakah Anda menyukai artikel kami? Ingin melihat konten yang lebih menarik? Dukung kami dengan melakukan pemesanan atau merekomendasikan kepada teman, cloud VPS untuk pengembang mulai $4.99, analog unik dari server level awal, yang kami temukan untuk Anda: Seluruh kebenaran tentang VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps dari $19 atau bagaimana cara berbagi server? (tersedia dengan RAID1 dan RAID10, hingga 24 core dan hingga 40GB DDR4).

Dell R730xd 2x lebih murah di pusat data Equinix Tier IV di Amsterdam? Hanya disini 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV dari $199 di Belanda! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - mulai $99! Membaca tentang Bagaimana membangun infrastruktur corp. kelas dengan penggunaan server Dell R730xd E5-2650 v4 senilai 9000 euro untuk satu sen?

Sumber: www.habr.com

Tambah komentar