Surprise fsync () PostgreSQL

Pengembang DBMS, berdasarkan kebutuhan, khawatir bahwa data dengan aman jatuh ke penyimpanan permanen. Karena itu, ketika komunitas PostgreSQL menemukan bahwa cara kernel menangani kesalahan I / O dapat menyebabkan hilangnya data tanpa ada kesalahan yang dilaporkan ke ruang pengguna, banyak ketidakpuasan muncul. Masalahnya, yang diperburuk oleh fakta bahwa PostgreSQL melakukan buffered I / O, tidak unik untuk Linux, dan tidak akan mudah untuk diselesaikan bahkan di sana.

Craig Ringer pertama kali melaporkan masalah ini ke milis pgsql-hacker pada akhir Maret. Singkatnya, PostgreSQL mengasumsikan bahwa panggilan fsync() berhasil menunjukkan bahwa semua data yang direkam sejak panggilan terakhir yang berhasil dengan aman ditransfer ke penyimpanan persisten. Ketika penulisan buffer I / O gagal karena kesalahan perangkat keras, sistem file bereaksi secara berbeda, tetapi perilaku ini biasanya melibatkan menghapus data pada halaman terkait dan menandainya sebagai bersih. Oleh karena itu, membaca blok yang baru saja ditulis kemungkinan besar akan mengembalikan sesuatu yang lain, tetapi tidak mencatat data.

Bagaimana dengan pelaporan kesalahan? Setahun yang lalu, KTT Linux Filesystem, Storage and Memory-Management Summit (LSFMM) termasuk sesi laporan bug di mana semuanya disebut "berantakan"; kesalahan dapat dengan mudah hilang, jadi tidak ada aplikasi yang akan melihatnya. Beberapa tambalan yang termasuk dalam 4.13 sedikit memperbaiki situasi selama siklus pengembangan (dan pada 4.16 ada beberapa perubahan untuk memperbaikinya lebih lanjut), namun, ada cara untuk kehilangan pemberitahuan kesalahan, seperti dijelaskan di bawah ini. Jika ini terjadi pada server PostgreSQL, ini dapat menyebabkan korupsi basis data otomatis.

Pengembang PostgreSQL tidak senang. Tom Lane menggambarkan ini sebagai " kerusakan otak pada nukleus, " sementara Robert Haas menyebutnya " 100% bodoh ." Pada awal diskusi, pengembang PostgreSQL memahami dengan jelas bagaimana, menurut mereka, kernel harus bekerja: halaman yang tidak dapat ditulis harus disimpan dalam memori dalam keadaan "kotor" (untuk upaya selanjutnya), dan deskriptor file yang sesuai harus diterjemahkan ke dalam Status kesalahan permanen sehingga server PostgreSQL tidak dapat melewati masalah.

Di mana ada yang tidak beres


Namun, bahkan sebelum komunitas kernel masuk ke dalam diskusi, menjadi jelas bahwa situasinya tidak sesederhana kelihatannya. Thomas Munro mengatakan bahwa Linux tidak unik dalam perilaku ini; OpenBSD dan NetBSD mungkin juga tidak melaporkan kesalahan tulis di ruang pengguna. Dan, ternyata, cara PostgreSQL menangani operasi I / O buffered sangat menyulitkan gambar.

Mekanisme ini telah dijelaskan secara rinci oleh Haas. Server PostgreSQL berfungsi sebagai serangkaian proses, banyak di antaranya dapat melakukan I / O pada file database. Namun, fsync() panggilan fsync() ditangani dalam proses checkpointer tunggal ("checkpointer"), yaitu menjaga penyimpanan disk dalam keadaan yang konsisten untuk pulih dari kegagalan. Checkpointer biasanya tidak membuat semua file yang relevan tetap terbuka, jadi sering kali harus membuka file sebelum memanggil fsync() . Di sinilah masalah muncul: bahkan di kernel 4.13 dan versi yang lebih baru, checkpointer tidak akan melihat kesalahan apa pun yang terjadi sebelum file dibuka. Jika sesuatu yang buruk terjadi sebelum memanggil open() checkpointer-a, maka panggilan berikutnya ke fsync() akan mengembalikan kesuksesan. Ada beberapa cara untuk menyebabkan kesalahan I / O di luar fsync() ; misalnya, kernel mungkin menemui salah satunya saat melakukan penulisan balik latar belakang. sync() panggilan seseorang sync() juga mungkin mengalami kesalahan I / O dan โ€œmenyerapโ€ status kesalahan yang dihasilkan.

Haas menggambarkan perilaku ini sebagai tidak dapat memenuhi harapan PostgreSQL:
Semua yang Anda (atau seseorang) miliki pada dasarnya merupakan asumsi yang tidak terbukti
deskriptor file mana yang mungkin relevan dengan kesalahan tertentu, tetapi kebetulan PostgreSQL tidak pernah cocok dengannya. Anda dapat terus mengatakan bahwa masalahnya ada di dugaan kami, tetapi bagi saya keliru menganggap bahwa kami adalah satu-satunya program yang pernah melakukannya.

Akibatnya, Joshua Drake memindahkan percakapan ke daftar pengembangan untuk ext4, termasuk bagian dari komunitas pengembangan kernel. Dave Chinner dengan cepat menggambarkan perilaku ini sebagai " resep untuk bencana, terutama dalam kode lintas-platform, di mana setiap platform OS berperilaku berbeda dan hampir tidak pernah cocok dengan apa yang diharapkan ." Sebagai gantinya, Ted Tso menjelaskan mengapa halaman yang terpengaruh ditandai sebagai bersih setelah kesalahan I / O; singkatnya, penyebab paling umum dari kesalahan I / O adalah ketika pengguna mengeluarkan drive USB pada waktu yang salah. Jika suatu proses menyalin banyak data ke disk ini, hasilnya adalah akumulasi dari halaman-halaman kotor dalam memori, mungkin sampai pada titik bahwa sistem tidak memiliki cukup memori untuk tugas-tugas lain. Dengan demikian, halaman-halaman ini tidak dapat disimpan dan akan dihapus jika pengguna ingin sistem tetap dapat digunakan setelah peristiwa semacam itu.

Baik Chinner dan Tso, bersama dengan yang lain, mengatakan PostgreSQL memiliki solusi yang tepat - beralih ke I / O (DIO) langsung. Menggunakan DIO memberikan tingkat kontrol yang lebih besar atas penulisan kembali dan I / O secara umum; ini termasuk akses ke informasi tentang operasi I / O yang mungkin gagal. Andres Freund, seperti sejumlah pengembang PostgreSQL lainnya, mengakui bahwa DIO adalah solusi jangka panjang terbaik. Tetapi dia juga mencatat bahwa orang seharusnya tidak mengharapkan pengembang untuk terjun jauh ke dalam pelaksanaan tugas ini. Sementara itu, dia mengatakan bahwa ada program lain (dia menyebutkan dpkg) yang juga rentan terhadap perilaku ini.

Menuju solusi jangka pendek


Selama diskusi, perhatian yang cukup besar diberikan pada gagasan bahwa kegagalan menulis harus mengarah pada fakta bahwa halaman yang terpengaruh akan disimpan dalam memori dalam keadaan kotor mereka. Tetapi para pengembang PostgreSQL dengan cepat menjauh dari ide ini dan tidak menuntutnya. Yang benar-benar mereka butuhkan pada akhirnya adalah cara yang andal untuk mencari tahu apakah ada yang salah. Dengan mengingat hal ini, mekanisme penanganan kesalahan PostgreSQL yang biasa dapat menangani hal ini; Namun, sedikit yang bisa dilakukan tanpa kehadirannya.

Pada beberapa titik dalam diskusi, Tso menyebutkan bahwa Google memiliki mekanisme penanganan kesalahan I / O sendiri. Kernel diinstruksikan untuk melaporkan kesalahan I / O melalui soket netlink; Proses khusus menerima pemberitahuan ini dan merespons sesuai. Namun mekanisme ini tidak pernah melakukan ini di pintu masuk. Freind menunjukkan bahwa mekanisme ini akan "ideal" untuk PostgreSQL, sehingga mungkin muncul dalam domain publik dalam waktu dekat.

Sementara itu, Jeff Leighton memikirkan ide lain: untuk menetapkan bendera di superblok sistem file ketika kesalahan I / O terjadi. Panggilan ke syncfs() kemudian akan menghapus bendera ini dan mengembalikan kesalahan jika sudah diatur. syncfs() PostgreSQL secara berkala dapat memanggil syncfs() untuk mencari kesalahan pada sistem file yang berisi database. Freund setuju bahwa ini bisa menjadi solusi untuk masalah tersebut.

Tentu saja, mekanisme semacam itu hanya akan muncul di kernel baru; Sementara itu, instalasi PostgreSQL biasanya berjalan pada kernel lama yang didukung oleh distribusi perusahaan. Dalam kernel ini, tampaknya tidak ada perbaikan yang termasuk dalam 4.13. Untuk sistem ini, sedikit yang bisa dilakukan untuk membantu PostgreSQL mendeteksi kesalahan I / O. Mungkin cukup untuk memulai daemon yang memindai log sistem dan mencari pesan kesalahan I / O di sana. Bukan solusi yang paling elegan, dan ini diperumit oleh fakta bahwa driver blok dan sistem file yang berbeda, sebagai aturan, melaporkan kesalahan dengan cara yang berbeda, tetapi ini mungkin merupakan pilihan terbaik yang tersedia.

Langkah selanjutnya adalah diskusi di acara LSFMM 2018 pada 23 April. Jika Anda beruntung, akan ada semacam solusi yang akan bekerja untuk pihak yang berkepentingan. Namun, satu hal yang tidak akan berubah adalah fakta sederhana bahwa penanganan kesalahan sulit dilakukan dengan benar.

Source: https://habr.com/ru/post/id472684/


All Articles