SQLite-д 16 Жил Нуугдсан Ноцтой Алдаа: Tailscale Саатлын Шалтгааныг Илрүүлж, Нээлттэй Эхийн Санхүүжилтээр Засууллаа
Дэлхий дээрх хамгийн их туршигдсан, хамгийн өргөн тархсан, нисэх онгоцны системээс эхлээд таны ухаалаг утас, хөтөч бүрт чимээгүй ажиллаж байдаг программ хангамж бол эргэлзээгүй SQLite юм. Түүний 100% салбар тестлэгдсэн (branch coverage) чанарыг програм хангамжийн инженерийн ертөнцөд "алтан стандарт" гэж үздэг.
Гэтэл сүүлийн хэдэн сарын турш VPN болон сүлжээний дэд бүтцийн томоохон компани болох Tailscale-ийн удирдлагын төв систем (Control Plane) дээр үл тайлагдах өгөгдлийн гэмтэл (data corruption) цувралаар гарч, инженерүүдийг мухардалд оруулж байв.
Tailscale-ийн инженерүүд энэхүү нууцлаг алдааны мөрөөр уйгагүй мөшгисний эцэст SQLite-ийн суурь механизмд 16 жилийн турш нуугдсан маш ховор WAL (Write-Ahead Logging) race condition алдааг илрүүлж чадсан байна.
Асуудал хаанаас эхлэв?
Tailscale-ийн Control Plane нь секунд тутамд олон мянган зангилааны (node) төлөвийг зохицуулдаг бөгөөд асар өндөр унших/бичих ачааллыг даахын тулд SQLite-ийг WAL mode болон түрэмгий хурдан checkpointing тохиргоотойгоор ашигладаг.
Гэвч зарим нэгэн өндөр ачаалалтай хэрэглэгчдийн бааз дээр өгөгдөл гэнэт гэмтэж, бүтэц нь эвдэрсэн тул үйлчилгээ доголдож эхэлжээ. Сэргээх оролдлогууд нь дараах хоёр хүнд сонголттой тулгарч байв:
- Сүүлийн найдвартай backup-аас сэргээх — их хэмжээний сүүлийн үеийн өгөгдлийг алдах эрсдэлтэй.
- Гэмтсэн баазыг газар дээр нь засах — өгөгдлийн бүтцийн уялдаа алдагдах аюултай.
Инженерүүд өөрсдийн код болон дэд бүтцийг хэчнээн нэгж бүрээр нь шалгасан ч гэм буруутан нь тэдний хэрэглээний код биш байлаа.
16 жилийн настай "WAL-Reset" Race Condition гэж юу вэ?
SQLite нь бичих ажиллагааг хурдасгахын тулд өөрчлөлтүүдийг шууд үндсэн өгөгдлийн баазын файлд бичихгүйгээр эхлээд тусдаа .wal (Write-Ahead Log) файл руу дарааллуулан бичдэг. Дараа нь тодорхой давтамжтайгаар checkpoint процесс ажиллаж, уг WAL доторх өгөгдлийг үндсэн өгөгдлийн сангийн файл руу шилжүүлэн нэгтгэж, WAL-ийг шинээр эхлүүлдэг (reset хийдэг).
Алдааны гол шалтгаан нь:
- Олон процесс зэрэг өгөгдөл бичих үед checkpoint хийгдэх хоромхон зуурын хугацаанд (millisecond-ийн нарийвчлалтай өрсөлдөөн) SQLite-ийн заагч буруу тооцоологдож байв.
- WAL-ийг "бүрэн шилжиж дууслаа" гэж үзэн толгойг нь reset хийх хооронд өөр нэг процесс яг тэр хаяг руу шинэ хуудас (page) бичиж амждаг байжээ.
- Үүний үр дүнд шинээр бичигдсэн өгөгдөл хуучин өгөгдөлтэй давхцан дарагдаж (overwrite), өгөгдлийн бааз чимээгүйхэн гэмтдэг байсан нь тогтоогдов.
Энэ механизм 2010 онд SQLite 3.7.0 хувилбарт WAL анх нэвтэрснээс хойш 16 жилийн турш нэг ч автомат тест болон жирийн хэрэглээний үед илрэлгүй өдийг хүрсэн нь олон улсын инженерийн нийгэмлэгийг цочроолоо.
Нээлттэй эхийн экосистемд үлгэр жишээ хандлага
Tailscale энэ асуудлыг шийдэхдээ технологийн компаниудын гаргадаг нийтлэг алдаа болох "GitHub дээр гомдол мэдүүлээд орхих" замыг сонгосонгүй.
- Санхүүжилт ба Багаж бүтээлт: Тэд уг race condition-ийг алдаагүй тусгаарлан барьж авах тусгай нээлттэй эхийн SQLite VFS shim хэрэгслийг бүтээх зардлыг бүрэн санхүүжүүлж, SQLite-ийн үндсэн хөгжүүлэгчидтэй (D. Richard Hipp тэргүүтэй баг) шууд нягт хамтран ажиллав.
- Детерминистик симуляци: Энэхүү хүнд алдааг бодитоор дахин өдөөхийн тулд Antithesis зэрэг детерминистик туршилтын орчныг ашиглан миллисекундын давтамжтай бичилтүүдийн төлөвийг симуляци хийж баталгаажуулжээ.
- Давхар олз: Уг шалгалтын явцад SQLite-ийн stale expression index (илэрхийллийн индекс хуучрах)-тэй холбоотой өөр нэг ховор алдааг давхар илрүүлж зассан байна.
Хөгжүүлэгчдэд өгөх сургамж
- 100% тестлэгдсэн код ч алдаатай байж болно: Параллель ажиллагаа (concurrency) болон I/O-ийн түвшинд үүсэх race condition нь уламжлалт unit/integration тестүүдээр баригдах бараг боломжгүй байдаг.
- Trace & Debug хэрэгслүүдийн хүч: Хүнд түвшний системийн алдааг илрүүлэхэд тусгай VFS түвшний shim болон гүн лог бүртгэлийн дэд бүтэц амин чухал үүрэгтэй.
- Open Source-ийг дэмжих соёл: Хэрэв танай бизнесийн чухал дэд бүтэц нээлттэй эхийн сангаас хамаардаг бол асуудал үүссэн үед тэднийг санхүүжүүлж, инженерүүдийнх нь цагийг үнэлэх нь экосистемийг бүхэлд нь аврах хамгийн зөв гарц юм.
SQLite баг уг алдааны засварыг албан ёсны эх коддоо нэгтгэж, шинэ хувилбараа гаргаад байна.
Эх сурвалж: Tailscale Engineering Blog (tailscale.com/blog/sqlite-wal-reset-bug) & SQLite Documentation
Сэтгэгдэл
Ачаалж байна...