1.1 Apakah itu sharding?

Jika anda gigih google, ternyata terdapat sempadan yang agak kabur antara partitioning kononnya dan sharding kononnya. Semua orang memanggil apa sahaja yang mereka mahu, apa sahaja yang mereka mahu. Sesetengah orang membezakan antara pembahagian mendatar dan pemisahan. Orang lain mengatakan bahawa sharding adalah sejenis pembahagian mendatar tertentu.

Saya tidak menemui satu pun piawaian istilah yang akan diluluskan oleh bapa pengasas dan diperakui oleh ISO. Keyakinan dalaman peribadi adalah seperti ini: Pembahagian secara purata ialah "memotong pangkal menjadi kepingan" dengan cara yang diambil secara sewenang-wenangnya.

  • Pembahagian menegak - mengikut lajur. Sebagai contoh, terdapat jadual gergasi dengan beberapa bilion rekod dalam 60 lajur. Daripada menyimpan satu jadual gergasi sedemikian, kami menyimpan sekurang-kurangnya 60 jadual gergasi sebanyak 2 bilion rekod setiap satu - dan ini bukan asas lajur, tetapi pembahagian menegak (sebagai contoh istilah).
  • Pembahagian mendatar - kami memotong baris demi baris, mungkin di dalam pelayan.

Saat yang janggal di sini ialah perbezaan halus antara pembahagian mendatar dan pemisahan. Saya boleh dipotong menjadi kepingan, tetapi saya tidak dapat memberitahu anda dengan pasti apa itu. Terdapat perasaan bahawa sharding dan partitioning mendatar adalah kira-kira perkara yang sama.

Sharding adalah, secara umum, apabila jadual besar dari segi pangkalan data atau pro-pengumpulan dokumen, objek, jika anda tidak mempunyai pangkalan data, tetapi kedai dokumen, dipotong tepat oleh objek. Iaitu, daripada 2 bilion objek, kepingan dipilih tidak kira saiznya. Objek itu sendiri di dalam setiap objek tidak dipotong menjadi kepingan, kami tidak meletakkannya ke dalam lajur yang berasingan, iaitu, kami meletakkannya dalam kelompok di tempat yang berbeza.

Terdapat perbezaan istilah yang halus. Sebagai contoh, secara relatifnya, pembangun Postgres boleh mengatakan bahawa pembahagian mendatar ialah apabila semua jadual di mana jadual utama dibahagikan terletak dalam skema yang sama, dan apabila pada mesin yang berbeza, ini sudah menjadi sharding.

Dalam pengertian umum, tanpa terikat dengan terminologi pangkalan data tertentu dan sistem pengurusan data tertentu, terdapat perasaan bahawa sharding hanya menghiris baris demi baris / dokumen demi dokumen, dan sebagainya - itu sahaja.

Saya menekankan tipikal. Dalam erti kata bahawa kami melakukan semua ini bukan sahaja untuk memotong 2 bilion dokumen kepada 20 jadual, setiap satu daripadanya akan lebih mudah diurus, tetapi untuk mengedarkannya ke atas banyak teras, banyak cakera atau banyak pelayan fizikal atau maya yang berbeza .

1.2 Bahagikan yang tidak boleh dibahagikan

Difahamkan bahawa kami melakukan ini supaya setiap serpihan - setiap keping data - direplikasi berkali-kali. Tetapi sebenarnya, tidak.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

Malah, jika anda melakukan penghirisan data sedemikian, dan dari satu jadual SQL gergasi pada MySQL pada komputer riba anda yang gagah berani, anda akan menghasilkan 16 jadual kecil, tanpa melampaui satu komputer riba, bukan satu skema, bukan satu pangkalan data, dll. . dan sebagainya. - itu sahaja, anda sudah mempunyai sharding.

Ini mengakibatkan perkara berikut:

  • Jalur lebar meningkat.
  • Latensi tidak berubah, iaitu, setiap orang, boleh dikatakan, pekerja atau pengguna dalam kes ini, mendapat sendiri. Permintaan yang berbeza dilayan pada masa yang sama.
  • Atau kedua-duanya, dan satu lagi, dan juga ketersediaan tinggi (replikasi).

Mengapa jalur lebar? Kita kadangkala boleh mempunyai volum data sedemikian yang tidak sesuai - tidak jelas di mana, tetapi ia tidak sesuai - pada 1 {kernel | cakera | pelayan | ...}. Hanya sumber yang tidak mencukupi, itu sahaja. Untuk bekerja dengan set data yang besar ini, anda perlu memotongnya.

Mengapa kependaman? Pada satu teras, mengimbas jadual 2 bilion baris adalah 20 kali lebih perlahan daripada mengimbas 20 jadual pada 20 teras, melakukannya secara selari. Data diproses terlalu perlahan pada satu sumber.

Mengapa ketersediaan tinggi? Atau kami memotong data untuk melakukan kedua-duanya pada masa yang sama, dan pada masa yang sama beberapa salinan setiap serpihan - replikasi memastikan ketersediaan yang tinggi.

1.3 Contoh mudah "cara melakukannya dengan tangan"

Pecahan bersyarat boleh dipotong menggunakan ujian jadual ujian.dokumen untuk 32 dokumen dan menjana 16 jadual ujian daripada jadual ini, kira-kira 2 dokumen setiap ujian.docs00, 01, 02, ..., 15.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

Kenapa kira-kira? Kerana a priori kita tidak tahu bagaimana id diedarkan, jika dari 1 hingga 32 termasuk, maka akan ada tepat 2 dokumen setiap satu, jika tidak.

Kami melakukannya di sini mengapa. Selepas kami membuat 16 jadual, kami boleh "merebut" 16 daripada apa yang kami perlukan. Tidak kira apa yang kita pukul, kita boleh menyelaraskan sumber ini. Sebagai contoh, jika ruang cakera tidak mencukupi, adalah wajar untuk menguraikan jadual ini pada cakera berasingan.

Semua ini, malangnya, tidak percuma. Saya mengesyaki bahawa dalam kes standard SQL kanonik (saya tidak membaca semula standard SQL untuk masa yang lama, mungkin ia tidak dikemas kini untuk masa yang lama), tidak ada sintaks piawai rasmi untuk mengatakan kepada mana-mana pelayan SQL : "Pelayan SQL yang dihormati, buat saya 32 serpihan dan bahagikannya kepada 4 cakera. Tetapi dalam pelaksanaan individu, selalunya terdapat sintaks khusus untuk melakukan perkara yang sama pada dasarnya. PostgreSQL mempunyai mekanisme untuk pembahagian, MySQL mempunyai MariaDB, Oracle mungkin melakukan semua ini lama dahulu.

Namun begitu, jika kami melakukannya dengan tangan, tanpa sokongan pangkalan data dan dalam rangka kerja standard, maka kami membayar secara bersyarat dengan kerumitan akses data . Di mana terdapat SELECT * FROM dokumen yang mudah WHERE id=123, kini 16 x SELECT * FROM docsXX. Dan adalah baik jika kita cuba mendapatkan rekod dengan kunci. Lebih menarik jika kita cuba mendapatkan julat rekod awal. Sekarang (jika kita, saya tekankan, adalah, seolah-olah, bodoh, dan kekal dalam rangka kerja standard), keputusan 16 SELECT * FROM ini perlu digabungkan dalam aplikasi.

Apakah perubahan prestasi yang boleh anda jangkakan?

  • Secara intuitif - linear.
  • Secara teorinya - sublinear, kerana undang-undang Amdahl.
  • Secara praktikal, mungkin hampir linear, mungkin tidak.

Malah, jawapan yang betul tidak diketahui. Dengan penerapan teknik sharding yang bijak, anda boleh mencapai kemerosotan super-linear yang ketara dalam prestasi aplikasi anda, malah DBA akan berjalan dengan poker panas-panas.

Mari lihat bagaimana ini boleh dicapai. Adalah jelas bahawa hanya menetapkan tetapan kepada PostgreSQL shards=16, dan kemudian ia berlepas dengan sendirinya, adalah tidak menarik. Mari kita fikirkan bagaimana kita boleh memastikan bahawa kita memperlahankan daripada sharding sebanyak 16 kali dengan 32 - ini menarik dari sudut pandangan bagaimana untuk tidak melakukan ini.

Percubaan kami untuk mempercepatkan atau memperlahankan akan sentiasa berjalan ke dalam klasik - undang-undang Amdahl lama yang baik, yang mengatakan bahawa tiada penyelarasan sempurna bagi sebarang permintaan, sentiasa ada bahagian yang konsisten.

1.4 Undang-undang Amdahl

Sentiasa ada bahagian bersiri.

Sentiasa ada bahagian pelaksanaan pertanyaan yang selari, dan sentiasa ada bahagian yang tidak selari. Walaupun pada pendapat anda, pertanyaan selari sempurna, sekurang-kurangnya koleksi baris hasil yang anda akan hantar kepada pelanggan daripada baris yang diterima daripada setiap serpihan sentiasa ada dan ia sentiasa berurutan.

Selalu ada bahagian yang konsisten. Ia boleh menjadi kecil, tidak dapat dilihat sepenuhnya pada latar belakang umum, ia boleh menjadi gergasi dan, oleh itu, sangat mempengaruhi keselarian, tetapi ia sentiasa wujud.

Di samping itu, pengaruhnya berubah dan boleh berkembang dengan ketara, contohnya, jika kita memotong jadual kita - mari kita tingkatkan kepentingan - daripada 64 rekod kepada 16 jadual 4 rekod, bahagian ini akan berubah. Sudah tentu, berdasarkan jumlah data yang begitu besar, kami sedang mengusahakan telefon mudah alih dan pemproses 2 MHz 86, dan kami tidak mempunyai fail yang mencukupi yang boleh dibuka pada masa yang sama. Nampaknya, dengan input sedemikian, kami membuka satu fail pada satu masa.

  • Ia adalah Jumlah = Bersiri + Selari . Di mana, sebagai contoh, selari adalah semua kerja di dalam DB, dan siri menghantar hasilnya kepada pelanggan.
  • Menjadi Jumlah2 = Serial + Parallel/N + Xserial . Contohnya, apabila keseluruhan ORDER BY, Xserial>0.

Dengan contoh mudah ini, saya cuba menunjukkan bahawa beberapa Xserial muncul. Selain fakta bahawa sentiasa ada bahagian bersiri, dan fakta bahawa kami cuba bekerja dengan data secara selari, terdapat bahagian tambahan untuk menyediakan penghirisan data ini. Secara kasarnya, kita mungkin memerlukan:

  • cari 16 jadual ini dalam kamus dalaman pangkalan data;
  • membuka fail;
  • memperuntukkan ingatan;
  • tidak memperuntukkan ingatan;
  • hasil gabungan;
  • menyegerakkan antara teras.

Beberapa kesan tidak segerak masih muncul. Mereka boleh menjadi tidak penting dan menduduki satu bilion daripada jumlah masa, tetapi mereka sentiasa bukan sifar dan sentiasa ada. Dengan bantuan mereka, kita boleh kehilangan prestasi secara mendadak selepas sharding.

Ini adalah gambaran standard tentang undang-undang Amdahl. Perkara penting di sini ialah garisan, yang sepatutnya lurus dan berkembang secara linear, menjadi asimtot. Tetapi kerana graf dari Internet tidak boleh dibaca, saya membuat, pada pendapat saya, lebih banyak jadual visual dengan nombor.

Katakan kita mempunyai beberapa bahagian bersiri pemprosesan permintaan yang hanya mengambil masa 5%: bersiri = 0.05 = 1 / 20 .

Secara intuitif, nampaknya dengan bahagian bersiri yang mengambil hanya 1/20 daripada pemprosesan permintaan, jika kami menyelaraskan pemprosesan permintaan untuk 20 teras, ia akan menjadi kira-kira 20, dalam kes paling teruk 18, kali lebih cepat.

Malah, matematik adalah perkara yang tidak berperasaan :

dinding = 0.05 + 0.95/bilangan_teras, kelajuan = 1 / (0.05 + 0.95/bilangan_teras)

Ternyata jika anda mengira dengan teliti, dengan bahagian bersiri sebanyak 5%, kelajuan akan menjadi 10 kali ganda (10.3), iaitu 51% berbanding ideal teori.

8 teras = 5.9 = 74%
10 teras = 6.9 = 69%
20 teras = 10.3 = 51%
40 teras = 13.6 = 34%
128 teras = 17.4 = 14%

Setelah menggunakan 20 teras (20 cakera, jika anda suka) untuk tugas yang pernah dikerjakan oleh seseorang, kami tidak akan secara teorinya mendapat pecutan lebih daripada 20 kali, tetapi dalam amalan - lebih kurang. Selain itu, dengan peningkatan bilangan selari, ketidakcekapan meningkat dengan ketara.

Apabila hanya 1% daripada kerja bersiri yang tinggal, dan 99% adalah selari, nilai kelajuan bertambah baik:

8 teras = 7.5 = 93%
16 teras = 13.9 = 87%
32 teras = 24.4 = 76%
64 teras = 39.3 = 61%

Untuk pertanyaan termonuklear yang sempurna, yang secara semula jadi mengambil masa berjam-jam untuk disiapkan, dan kerja persediaan serta pemasangan hasilnya mengambil masa yang sangat singkat (siri = 0.001), kita sudah akan melihat kecekapan yang baik:

8 teras = 7.94 = 99%
16 teras = 15.76 = 99%
32 teras = 31.04 = 97%
64 teras = 60.20 = 94%

Sila ambil perhatian bahawa kita tidak akan pernah melihat 100% . Dalam kes yang sangat baik, anda boleh melihat, sebagai contoh, 99.999%, tetapi tidak betul-betul 100%.