Kompresi data di Apache Ignite. pengalaman Sber

Kompresi data di Apache Ignite. pengalaman SberSaat bekerja dengan data dalam jumlah besar, masalah kurangnya ruang disk terkadang bisa muncul. Salah satu cara untuk mengatasi masalah ini adalah kompresi, sehingga pada peralatan yang sama Anda dapat meningkatkan volume penyimpanan. Pada artikel ini, kita akan melihat cara kerja kompresi data di Apache Ignite. Artikel ini hanya akan menjelaskan metode kompresi disk yang diterapkan dalam produk. Metode kompresi data lainnya (melalui jaringan, dalam memori), baik diterapkan atau tidak, akan tetap berada di luar cakupan.

Jadi, ketika mode persistensi diaktifkan, sebagai akibat dari perubahan data di cache, Ignite mulai menulis ke disk:

  1. Isi cache
  2. Write Ahead Log (selanjutnya disebut WAL)

Mekanisme kompresi WAL telah ada sejak lama, yang disebut pemadatan WAL. Apache Ignite 2.8 yang baru dirilis memperkenalkan dua mekanisme lagi yang memungkinkan Anda mengompresi data pada disk: kompresi halaman disk untuk mengompresi konten cache dan kompresi snapshot halaman WAL untuk mengompresi beberapa entri WAL. Rincian lebih lanjut tentang ketiga mekanisme tersebut di bawah ini.

Kompresi halaman disk

Bagaimana itu bekerja

Pertama, mari kita lihat sekilas bagaimana Ignite menyimpan data. Memori halaman digunakan untuk penyimpanan. Ukuran halaman diatur pada awal node dan tidak dapat diubah pada tahap selanjutnya; juga, ukuran halaman harus pangkat dua dan kelipatan dari ukuran blok sistem file. Halaman dimuat ke dalam RAM dari disk sesuai kebutuhan; ukuran data pada disk mungkin melebihi jumlah RAM yang dialokasikan. Jika tidak ada cukup ruang di RAM untuk memuat halaman dari disk, halaman lama yang tidak lagi digunakan akan dikeluarkan dari RAM.

Data disimpan pada disk dalam bentuk berikut: file terpisah dibuat untuk setiap partisi dari setiap grup cache; dalam file ini, halaman muncul satu demi satu dalam urutan indeks menaik. Pengidentifikasi halaman lengkap berisi pengidentifikasi grup cache, nomor partisi, dan indeks halaman dalam file. Jadi, dengan menggunakan pengidentifikasi halaman penuh, kita dapat secara unik menentukan file dan offset dalam file untuk setiap halaman. Anda dapat membaca lebih lanjut tentang paging memory di artikel Apache Ignite Wiki: Ignite Persistent Store - di balik terpal.

Mekanisme kompresi halaman disk, seperti yang Anda duga dari namanya, bekerja di tingkat halaman. Ketika mekanisme ini diaktifkan, data dalam RAM diproses apa adanya, tanpa kompresi apa pun, tetapi ketika halaman disimpan dari RAM ke disk, halaman tersebut dikompresi.

Namun mengompresi setiap halaman satu per satu bukanlah solusi untuk masalah ini; Anda perlu mengurangi ukuran file data yang dihasilkan. Jika ukuran halaman tidak lagi tetap, kami tidak dapat lagi menulis halaman ke file satu demi satu, karena hal ini dapat menimbulkan sejumlah masalah:

  • Dengan menggunakan indeks halaman, kami tidak akan dapat menghitung offset lokasinya di file.
  • Tidak jelas apa yang harus dilakukan dengan halaman yang tidak ada di akhir file dan mengubah ukurannya. Jika ukuran halaman diperkecil, ruang yang dikosongkan akan hilang. Jika ukuran halaman bertambah, Anda perlu mencari tempat baru di file untuk itu.
  • Jika halaman berpindah beberapa byte yang bukan kelipatan ukuran blok sistem file, maka membaca atau menulisnya memerlukan sentuhan satu blok sistem file lagi, yang dapat menyebabkan penurunan kinerja.

Untuk menghindari penyelesaian masalah ini pada levelnya sendiri, kompresi halaman disk di Apache Ignite menggunakan mekanisme sistem file yang disebut file sparse. File renggang adalah file yang beberapa wilayahnya nol dapat ditandai sebagai "lubang". Dalam hal ini, tidak ada blok sistem file yang akan dialokasikan untuk menyimpan lubang ini, sehingga menghemat ruang disk.

Adalah logis bahwa untuk membebaskan blok sistem file, ukuran lubang harus lebih besar atau sama dengan blok sistem file, yang memberikan batasan tambahan pada ukuran halaman dan Apache Ignite: agar kompresi memiliki efek apa pun, ukuran halaman harus lebih besar dari ukuran blok sistem file. Jika ukuran halaman sama dengan ukuran blok, maka kita tidak akan pernah bisa mengosongkan satu blok pun, karena untuk mengosongkan satu blok, halaman yang dikompresi harus menempati 0 byte. Jika ukuran halaman sama dengan ukuran 2 atau 4 blok, kita sudah dapat mengosongkan setidaknya satu blok jika halaman kita dikompresi masing-masing setidaknya 50% atau 75%.

Dengan demikian, gambaran akhir tentang cara kerja mekanisme tersebut: Saat menulis halaman ke disk, upaya dilakukan untuk mengompresi halaman. Jika ukuran halaman yang dikompresi memungkinkan satu atau lebih blok sistem file untuk dibebaskan, maka halaman tersebut ditulis dalam bentuk terkompresi, dan sebuah "lubang" dibuat sebagai pengganti blok yang dibebaskan (panggilan sistem dijalankan fallocate() dengan bendera lubang pukulan). Jika ukuran halaman yang dikompresi tidak memungkinkan blok untuk dibebaskan, halaman tersebut disimpan sebagaimana adanya, tidak terkompresi. Semua offset halaman dihitung dengan cara yang sama seperti tanpa kompresi, yaitu dengan mengalikan indeks halaman dengan ukuran halaman. Anda tidak perlu memindahkan halaman sendiri. Offset halaman, seperti halnya tanpa kompresi, berada pada batas blok sistem file.

Kompresi data di Apache Ignite. pengalaman Sber

Dalam implementasi saat ini, Ignite hanya dapat bekerja dengan file yang jarang di OS Linux; oleh karena itu, kompresi halaman disk hanya dapat diaktifkan saat menggunakan Ignite pada sistem operasi ini.

Algoritma kompresi yang dapat digunakan untuk kompresi halaman disk: ZSTD, LZ4, Snappy. Selain itu, terdapat mode operasi (SKIP_GARBAGE), di mana hanya ruang yang tidak terpakai di halaman yang dibuang tanpa menerapkan kompresi pada data yang tersisa, yang mengurangi beban pada CPU dibandingkan dengan algoritma yang disebutkan sebelumnya.

Dampak Kinerja

Sayangnya, saya tidak melakukan pengukuran performa sebenarnya di stand sebenarnya, karena kami tidak berencana menggunakan mekanisme ini dalam produksi, namun secara teoritis kami dapat berspekulasi di mana kami akan kalah dan di mana kami akan menang.

Untuk melakukan ini, kita perlu mengingat bagaimana halaman dibaca dan ditulis saat diakses:

  • Saat melakukan operasi baca, pertama-tama dicari di RAM; jika pencarian tidak berhasil, halaman dimuat ke dalam RAM dari disk oleh thread yang sama yang melakukan pembacaan.
  • Ketika operasi penulisan dilakukan, halaman dalam RAM ditandai sebagai kotor, tetapi halaman tersebut tidak langsung disimpan secara fisik ke disk oleh thread yang melakukan penulisan. Semua halaman kotor disimpan ke disk nanti dalam proses pos pemeriksaan di thread terpisah.

Jadi dampaknya pada operasi baca adalah:

  • Positif (disk IO), karena penurunan jumlah blok sistem file baca.
  • Negatif (CPU), karena beban tambahan yang dibutuhkan sistem operasi untuk bekerja dengan file yang jarang. Mungkin juga operasi IO tambahan secara implisit akan muncul di sini untuk menyimpan struktur file renggang yang lebih kompleks (sayangnya, saya tidak mengetahui semua detail tentang cara kerja file renggang).
  • Negatif (CPU), karena kebutuhan untuk mendekompresi halaman.
  • Tidak ada dampak pada operasi tulis.
  • Dampak pada proses pos pemeriksaan (semuanya di sini mirip dengan operasi baca):
  • Positif (disk IO), karena penurunan jumlah blok sistem file tertulis.
  • Negatif (CPU, mungkin disk IO), karena bekerja dengan file yang jarang.
  • Negatif (CPU), karena perlunya kompresi halaman.

Sisi skala manakah yang akan menentukan skalanya? Ini semua sangat bergantung pada lingkungan, namun saya cenderung percaya bahwa kompresi halaman disk kemungkinan besar akan menyebabkan penurunan kinerja pada sebagian besar sistem. Selain itu, pengujian pada DBMS lain yang menggunakan pendekatan serupa dengan file renggang menunjukkan penurunan kinerja saat kompresi diaktifkan.

Cara mengaktifkan dan mengkonfigurasi

Seperti disebutkan di atas, versi minimum Apache Ignite yang mendukung kompresi halaman disk adalah 2.8 dan hanya sistem operasi Linux yang didukung. Aktifkan dan konfigurasikan sebagai berikut:

  • Harus ada modul kompresi penyalaan di jalur kelas. Secara default, ini terletak di distribusi Apache Ignite di direktori libs/optional dan tidak termasuk dalam jalur kelas. Anda cukup memindahkan direktori ke atas satu tingkat ke libs dan kemudian ketika Anda menjalankannya melalui ignition.sh maka direktori tersebut akan diaktifkan secara otomatis.
  • Persistensi harus diaktifkan (Diaktifkan melalui DataRegionConfiguration.setPersistenceEnabled(true)).
  • Ukuran halaman harus lebih besar dari ukuran blok sistem file (Anda dapat mengaturnya menggunakan DataStorageConfiguration.setPageSize() ).
  • Untuk setiap cache yang datanya perlu dikompresi, Anda harus mengonfigurasi metode kompresi dan (opsional) tingkat kompresi (metode CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

pemadatan WAL

Bagaimana itu bekerja

Apa itu WAL dan mengapa diperlukan? Singkatnya: ini adalah log yang berisi semua peristiwa yang pada akhirnya mengubah penyimpanan halaman. Hal ini diperlukan terutama untuk dapat pulih jika terjatuh. Operasi apa pun, sebelum memberikan kendali kepada pengguna, harus terlebih dahulu mencatat peristiwa di WAL, sehingga jika terjadi kegagalan, peristiwa tersebut dapat diputar ulang di log dan memulihkan semua operasi yang responsnya berhasil diterima oleh pengguna, bahkan jika operasi ini tidak punya waktu untuk tercermin dalam penyimpanan halaman pada disk (telah dijelaskan di atas bahwa penulisan sebenarnya ke penyimpanan halaman dilakukan dalam proses yang disebut "pos pemeriksaan" dengan beberapa penundaan oleh utas terpisah).

Entri di WAL dibagi menjadi logis dan fisik. Boolean adalah kunci dan nilai itu sendiri. Fisik - mencerminkan perubahan pada halaman di penyimpanan halaman. Meskipun catatan logis dapat berguna untuk beberapa kasus lain, catatan fisik hanya diperlukan untuk pemulihan jika terjadi kerusakan dan catatan hanya diperlukan sejak pos pemeriksaan terakhir berhasil. Di sini kami tidak akan menjelaskan secara detail dan menjelaskan mengapa cara kerjanya seperti ini, tetapi bagi yang tertarik dapat merujuk ke artikel yang telah disebutkan di Apache Ignite Wiki: Ignite Persistent Store - di balik terpal.

Seringkali ada beberapa catatan fisik per catatan logis. Artinya, misalnya, satu operasi memasukkan ke dalam cache mempengaruhi beberapa halaman di memori halaman (halaman dengan data itu sendiri, halaman dengan indeks, halaman dengan daftar bebas). Dalam beberapa pengujian sintetis, saya menemukan bahwa catatan fisik menempati hingga 90% file WAL. Namun, mereka diperlukan untuk waktu yang sangat singkat (secara default, interval antar pos pemeriksaan adalah 3 menit). Masuk akal untuk membuang data ini setelah kehilangan relevansinya. Inilah yang dilakukan mekanisme pemadatan WAL: menghilangkan catatan fisik dan mengompresi catatan logis yang tersisa menggunakan zip, sementara ukuran file berkurang secara signifikan (terkadang hingga puluhan kali lipat).

Secara fisik, WAL terdiri dari beberapa segmen (10 secara default) dengan ukuran tetap (64MB secara default), yang ditimpa secara melingkar. Segera setelah segmen saat ini terisi, segmen berikutnya ditetapkan sebagai segmen saat ini, dan segmen yang terisi disalin ke arsip melalui thread terpisah. Pemadatan WAL sudah berfungsi dengan segmen arsip. Selain itu, sebagai thread terpisah, ia memantau pelaksanaan pos pemeriksaan dan memulai kompresi di segmen arsip yang catatan fisiknya tidak lagi diperlukan.

Kompresi data di Apache Ignite. pengalaman Sber

Dampak Kinerja

Karena pemadatan WAL dijalankan sebagai thread terpisah, seharusnya tidak ada dampak langsung pada operasi yang dilakukan. Namun hal ini tetap memberikan beban latar belakang tambahan pada CPU (kompresi) dan disk (membaca setiap segmen WAL dari arsip dan menulis segmen terkompresi), sehingga jika sistem berjalan pada kapasitas maksimumnya, hal ini juga akan menyebabkan penurunan kinerja.

Cara mengaktifkan dan mengkonfigurasi

Anda dapat mengaktifkan pemadatan WAL menggunakan properti WalCompactionEnabled Π² DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Selain itu, dengan menggunakan metode DataStorageConfiguration.setWalCompactionLevel(), Anda dapat mengatur tingkat kompresi jika Anda tidak puas dengan nilai default (BEST_SPEED).

Kompresi snapshot halaman WAL

Bagaimana itu bekerja

Kita telah mengetahui bahwa dalam catatan WAL dibagi menjadi logis dan fisik. Untuk setiap perubahan pada setiap halaman, catatan WAL fisik dihasilkan di memori halaman. Catatan fisik, pada gilirannya, juga dibagi menjadi 2 subtipe: catatan snapshot halaman dan catatan delta. Setiap kali kita mengubah sesuatu pada halaman dan memindahkannya dari keadaan bersih ke keadaan kotor, salinan lengkap halaman ini disimpan di WAL (catatan cuplikan halaman). Bahkan jika kita hanya mengubah satu byte di WAL, catatannya akan sedikit lebih besar dari ukuran halaman. Jika kita mengubah sesuatu pada halaman yang sudah kotor, catatan delta terbentuk di WAL, yang hanya mencerminkan perubahan dibandingkan dengan keadaan halaman sebelumnya, tetapi tidak seluruh halaman. Karena pengaturan ulang status halaman dari kotor menjadi bersih dilakukan selama proses pos pemeriksaan, segera setelah dimulainya pos pemeriksaan, hampir semua catatan fisik hanya akan terdiri dari cuplikan halaman (karena semua halaman segera setelah dimulainya pos pemeriksaan bersih) , lalu saat kita mendekati pos pemeriksaan berikutnya, pecahan rekaman delta mulai bertambah dan disetel ulang lagi di awal pos pemeriksaan berikutnya. Pengukuran dalam beberapa pengujian sintetik menunjukkan bahwa pangsa cuplikan halaman dalam total volume catatan fisik mencapai 90%.

Ide kompresi snapshot halaman WAL adalah untuk mengompresi snapshot halaman menggunakan alat kompresi halaman yang sudah jadi (lihat kompresi halaman disk). Pada saat yang sama, di WAL, catatan disimpan secara berurutan dalam mode hanya tambahan dan tidak perlu mengikat catatan ke batas blok sistem file, jadi di sini, tidak seperti mekanisme kompresi halaman disk, kita tidak memerlukan file renggang di semuanya; oleh karena itu, mekanisme ini tidak hanya akan bekerja pada OS Linux. Selain itu, tidak lagi menjadi masalah bagi kami seberapa banyak kami dapat mengompresi halaman. Bahkan jika kita mengosongkan 1 byte, ini sudah merupakan hasil positif dan kita dapat menyimpan data terkompresi di WAL, tidak seperti kompresi halaman disk, di mana kita menyimpan halaman terkompresi hanya jika kita membebaskan lebih dari 1 blok sistem file.

Halaman adalah data yang sangat dapat dikompres, bagiannya dalam total volume WAL sangat tinggi, jadi tanpa mengubah format file WAL kita bisa mendapatkan pengurangan ukuran yang signifikan. Kompresi, termasuk catatan logis, akan memerlukan perubahan format dan hilangnya kompatibilitas, misalnya, bagi konsumen eksternal yang mungkin tertarik dengan catatan logis, namun tidak akan menyebabkan pengurangan ukuran file secara signifikan.

Seperti halnya kompresi halaman disk, kompresi snapshot halaman WAL dapat menggunakan algoritma kompresi ZSTD, LZ4, Snappy, serta mode SKIP_GARBAGE.

Dampak Kinerja

Tidak sulit untuk menyadari bahwa mengaktifkan kompresi snapshot halaman WAL secara langsung hanya memengaruhi thread yang menulis data ke memori halaman, yaitu thread yang mengubah data dalam cache. Pembacaan catatan fisik dari WAL hanya terjadi sekali, pada saat node diangkat setelah terjatuh (dan hanya jika node tersebut jatuh selama pos pemeriksaan).

Hal ini mempengaruhi thread yang mengubah data dengan cara berikut: kita mendapatkan efek negatif (CPU) karena kebutuhan untuk mengompresi halaman setiap kali sebelum menulis ke disk, dan efek positif (disk IO) karena penurunan jumlah data tertulis. Oleh karena itu, semuanya sederhana di sini: jika kinerja sistem dibatasi oleh CPU, kita mengalami sedikit penurunan, jika dibatasi oleh I/O disk, kita mendapatkan peningkatan.

Secara tidak langsung, pengurangan ukuran WAL juga mempengaruhi (secara positif) aliran yang membuang segmen WAL ke dalam arsip dan aliran pemadatan WAL.

Pengujian kinerja nyata di lingkungan kami menggunakan data sintetis menunjukkan sedikit peningkatan (throughput meningkat sebesar 10%-15%, latensi menurun sebesar 10%-15%).

Cara mengaktifkan dan mengkonfigurasi

Versi minimum Apache Ignite: 2.8. Aktifkan dan konfigurasikan sebagai berikut:

  • Harus ada modul kompresi penyalaan di jalur kelas. Secara default, ini terletak di distribusi Apache Ignite di direktori libs/optional dan tidak termasuk dalam jalur kelas. Anda cukup memindahkan direktori ke atas satu tingkat ke libs dan kemudian ketika Anda menjalankannya melalui ignition.sh maka direktori tersebut akan diaktifkan secara otomatis.
  • Persistensi harus diaktifkan (Diaktifkan melalui DataRegionConfiguration.setPersistenceEnabled(true)).
  • Mode kompresi harus diatur menggunakan metode ini DataStorageConfiguration.setWalPageCompression(), kompresi dinonaktifkan secara default (mode DISABLED).
  • Secara opsional, Anda dapat mengatur tingkat kompresi menggunakan metode ini DataStorageConfiguration.setWalPageCompression(), lihat javadoc untuk metode mengetahui nilai yang valid untuk setiap mode.

Kesimpulan

Mekanisme kompresi data yang dipertimbangkan di Apache Ignite dapat digunakan secara independen satu sama lain, namun kombinasi keduanya juga dapat diterima. Memahami cara kerjanya akan memungkinkan Anda menentukan seberapa cocoknya untuk tugas Anda di lingkungan Anda dan apa yang harus Anda korbankan saat menggunakannya. Kompresi halaman disk dirancang untuk mengompresi penyimpanan utama dan dapat memberikan rasio kompresi sedang. Kompresi snapshot halaman WAL akan memberikan tingkat kompresi rata-rata untuk file WAL, dan kemungkinan besar bahkan akan meningkatkan kinerja. Pemadatan WAL tidak akan berdampak positif pada kinerja, namun akan mengurangi ukuran file WAL sebanyak mungkin dengan menghapus catatan fisik.

Sumber: www.habr.com

Tambah komentar