TL; DR: Linux çekirdeği arabellekli bir G / Ç yazımını kaybederse , uygulamanın öğrenmesi için herhangi bir yol var mı?
fsync()
Dayanıklılık için dosyaya (ve üst dizinine) sahip olduğunuzu biliyorum . Soru, çekirdek bir G / Ç hatası nedeniyle yazma bekleyen kirli arabellekleri kaybederse , uygulama bunu nasıl algılayabilir ve kurtarabilir veya iptal edebilir?
Yazma sırasının ve yazma dayanıklılığının önemli olabileceği veritabanı uygulamaları vb.
Kayıp yazılar? Nasıl?
Linux çekirdeğinin blok katmanı, bazı durumlarda , vb. Tarafından başarıyla gönderilen arabelleğe alınmış G / Ç isteklerini aşağıdaki gibi bir hata ile kaybedebilir :write()
pwrite()
Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0
(Bkz. end_buffer_write_sync(...)
Ve end_buffer_async_write(...)
içerifs/buffer.c
).
Daha yeni çekirdeklerde hata bunun yerine "kayıp zaman uyumsuz sayfa yazma" yı içerecektir :
Buffer I/O error on dev dm-0, logical block 12345, lost async page write
Uygulamanın write()
hatasız olarak geri döndüğünden, bir hatayı tekrar uygulamaya bildirmenin bir yolu yoktur.
Onları mı tespit ediyorsunuz?
Çekirdek kaynaklarına aşina değilim, ama async yazma yapıyorsa yazılmamış olan arabellek üzerinde ayarlandığını düşünüyorumAS_EIO
:
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
ancak daha sonra fsync()
dosyada diskte olduğunu onaylamak için uygulamanın bunu öğrenip öğrenemeyeceği net değil .
Öyle görünüyor wait_on_page_writeback_range(...)
içindemm/filemap.c
vasitasiyla do_sync_mapping_range(...)
içindefs/sync.c
tarafından çağrılan dönün hangi sys_sync_file_range(...)
. -EIO
Bir veya daha fazla arabellek yazılamazsa geri döner .
Tahmin ettiğim gibi, bunun fsync()
sonucuna yayılırsa, uygulama paniği ve bir G / Ç hatası alırsa fsync()
ve yeniden başlatıldığında işini nasıl yeniden yapacağını bilirse kurtarırsa, bu yeterli koruma mıdır?
Uygulamanın muhtemelen bir dosyadaki hangi bayt ofsetlerinin kayıp sayfalara karşılık geldiğini bilmesinin bir yolu yoktur, böylece nasıl olduğunu bilirse onları yeniden yazabilir, ancak uygulama fsync()
dosyanın son başarılı olmasından bu yana tüm bekleyen çalışmalarını tekrarlarsa ve bu yeniden yazarsa kayıp sayfalardaki herhangi bir G / Ç hata işaretini temizlemeli ve bir sonrakinin fsync()
tamamlanmasına izin veren dosyaya karşı kayıp yazmalara karşılık gelen kirli çekirdek arabellekleri - doğru mu?
Öyleyse, kurtarmanın ve yeniden çalışmaların çok şiddetli olacağı yerlere fsync()
geri dönebilecek başka, zararsız durumlar var -EIO
mı?
Neden?
Elbette bu tür hatalar olmamalıdır. Bu durumda hata, dm-multipath
sürücünün varsayılan değerleri ile SAN tarafından ince-yetkilendirilmiş depolama alanı tahsis edemediğini bildirmek için kullanılan algılama kodu arasındaki talihsiz bir etkileşimden kaynaklanır . Ancak, bu olabilecekleri tek durum değildir - örneğin libvirt, Docker ve daha fazlası tarafından kullanılan ince provizyonlu LVM'den raporlar da gördüm. Bir veritabanı gibi kritik bir uygulama, her şey yolundaymış gibi körü körüne devam etmek yerine, bu tür hatalarla başa çıkmaya çalışmalıdır.
Eğer çekirdek çekirdek panik ölmeden kaybetmek yazım işlemine 's Tamam düşünür, uygulamalar başa çıkmak için bir yol bulmalıyız.
Pratik etki, bir SAN ile çok yollu bir sorunun DBMS yazmalarının başarısız olduğunu bilmediği için veritabanı bozulmasına neden olan kayıp yazmalara neden olduğu bir durum bulduğumdur. Eğlenceli değil.