Бүтцийн 2 байтыг хасаж, математикаар оновчлов: Cloudflare сүлжээнээсээ 100TB RAM хэрхэн хэмнэсэн бэ?
Дэлхийн нийт интернэт урсгалын 20 орчим хувийг дамжуулдаг Cloudflare-ийн хувьд серверийн нөөцийн өчүүхэн оновчлол ч бодит амьдрал дээр асар том хэмнэлт болж хувирдаг. Дэд бүтцийн инженерүүдийн хувьд "Бид нэг серверийн санах ойг хэдэн мегабайтаар багасгалаа" гэдэг нь дэлхий даяар байрлах олон зуун дата төвийн цар хүрээнд терабайтаар хэмжигдэх нөөцийг чөлөөлдөг бичигдээгүй хуультай.
Cloudflare өөрсдийн инженерийн багийн хамгийн сүүлийн үеийн судалгаа, оновчлолын үр дүнгээ дэлгэлээ. Тэд Rust хэл дээр бичигдсэн Pingora Backend Router (PBR) системийнхээ ачаалал хуваарилах алгоритмыг математик болон санах ойн бүтцийн түвшинд шинэчилснээр нийт 100 терабайт (TB) RAM суллаж чадсан байна.
Хамгийн сонирхолтой нь энэ их хэмнэлтийн цаана шинэ техник хангамж авах биш, харин ердөө өгөгдлийн бүтцээс 2 байт хасаж, 100 мянган виртуал хэшээс илүүц 90 мянгыг нь тайрах математик шийдэл байв.
Асуудал: Санах ойд хадгалагддаг Consistent Hashing цагираг
Cloudflare нь үйлчлүүлэгчдийн хүсэлтийг кэш серверүүд рүү хуваарилахдаа Consistent Hashing буюу хэш цагираг (Hash Ring / Ketama алгоритм) ашигладаг. Энэ алгоритмын давуу тал нь серверийн сүлжээнд шинэ сервер нэмэгдэх эсвэл хасагдахад өмнө нь кэшлэгдсэн өгөгдлүүд бүхэлдээ эвдрэхгүй (cache churn үүсэхгүй), хамгийн бага хэмжээгээр шилждэгт оршино.
Гэвч энэ цагираг нь асар олон хэш утгыг RAM дотор байнга хадгалахыг шаарддаг. Pingora дээр хүсэлт бүрийг миллисекундээс бага хугацаанд чиглүүлэхийн тулд хэш цагиргийг санах ойд шууд бэлэн байлгадаг бөгөөд дата төвүүдийн цар хүрээ өсөхийн хэрээр уг бүтэц асар их санах ой идэж эхэлсэн байна.
Инженерүүд үүнийг шийдэхийн тулд хоёр шатлалт нарийн оновчлол хийжээ.
1-р алхам: 8 байтын бүтцийг 6 байт болгон шахав (Struct Memory Layout)
Анхны загварт хэш цагиргийн нэгж бүр нь дараах хэлбэртэй байв:
struct HashEntry {
hash: u32, // 4 bytes
index: u32, // 4 bytes
}
// Нийт хэмжээ = 8 bytes
Энд index нь хүсэлтийг хүлээн авах серверийн дугаарыг заадаг. Гэтэл инженерүүд нэгэн энгийн статистикийг анзаарчээ: Cloudflare-ийн аль ч дата төвд нэг дор 65,536 ($2^{16}$)-аас олон сервер зэрэг ажилладаггүй.
Тэгэхээр ердөө хэдэн мянган серверийг индекслэхийн тулд 4 байтын u32 (4.2 тэрбум хүртэл тоолох чадалтай) өгөгдлийн төрөл ашиглах нь цэвэр нөөцийн үрэлгэн зарцуулалт байв. Серверийн тоо 65 мянгаас хэтрэхгүй тул 2 байтын u16 төрөл бүрэн хангалттай.
4 байт (hash) + 2 байт (index) = Нийт 6 байт
Гэхдээ үүнийг Rust дээр хэрэгжүүлэхэд санах ойн байрлалын (memory alignment) асуудал тулгарчээ. Хэрэв шууд #[repr(packed)] ашиглавал санах ойн тэгш бус хаяглалтаас (unaligned access) болж зарим архитектур дээр CPU-ийн гүйцэтгэл унах эрсдэлтэй. Иймээс инженерүүд түүхий [u8; 6] массивыг санах ойд ашиглаж, өгөгдлийг уншихдаа бит шилжүүлэгч (getter method) ашиглан кодлов.
Зөвхөн энэ бүтцийн өөрчлөлтөөр нэгж элемент бүрийн эзлэх RAM 25 хувиар шууд багассан байна!
2-р алхам: Математик шинжилгээ буюу сүүлчийн 90,000 хэшийн үнэ цэн
Хоёр дахь бөгөөд хамгийн далайцтай өөрчлөлт нь математикийн магадлалын онол байв.
Consistent Hashing алгоритмд сервер бүрд ачааллыг жигд хуваарилахын тулд нэг серверт олон виртуал цэг (virtual node / hashes per server) үүсгэдэг. Сервер бүр хэдий чинээ олон хэш цэгтэй байна, ачаалал төдий чинээ тэнцвэртэй тархана. Иймээс Cloudflare-ийн хуучин тохиргоонд нэг серверт 100,000 хэш оноодог байв.
Ихэнх систем хөгжүүлэгчид энэ тоог туршилтаар эсвэл ойролцоо томьёогоор сонгодог. Харин Cloudflare-ийн инженерүүд $k$ ширхэг хэш цэг тутамд үүсэх ачааллын тархалтын алдааны (load distribution error) нарийн математик томьёог гарган боджээ.
Бодит тооцоолол хийгээд үзтэл цочирдом үр дүн гарчээ:
- Сервер тус бүрийн 100,000 хэшээс сүүлийн 90,000 хэш нь ачааллын жигд хуваарилалтыг ердөө 0.7%-иар л сайжруулж байв!
- Өөрөөр хэлбэл, хэш цагиргийн санах ойн 90 хувь нь өчүүхэн 0.7%-ийн тэнцвэржүүлэлтийн төлөө шатаж байжээ.
Инженерүүд ачааллын баланс алдагдахгүй байх хамгийн оновчтой цэгийг олж, виртуал хэшийн тоог эрс бууруулжээ. Энэхүү математик шийдэл нь санах ойн хэрэглээг даруй хэд дахин хөнгөвчилсөн байна.
Сүлжээг унагалгүй шилжүүлсэн нь (Zero-Downtime Migration)
Хэш цагиргийг дур мэдэн шууд шинэчилбэл дэлхий даяарх кэш нэгэн зэрэг хүчингүй болж, бүх хүсэлт үндсэн эх (origin) серверүүд рүү цуван асар том сүлжээний сүйрэл (thundering herd problem) үүсгэх аюултай.
Иймээс шилжүүлэлтийг дараах байдлаар маш нарийн хийсэн байна:
- Parallel Rings: Хүсэлт бүр дээр хуучин болон шинэ хэш цагиргийг зэрэгцүүлэн шалгах шилжилтийн систем ажиллуулсан.
- Blast Radius-ийг хязгаарлах: Глобал хувиар биш, харин дата төв бүрээр нь шат дараатай нэвтрүүлсэн.
- 7 гол метрик: Кэшийн хариу үйлдэл (cache hit ratio), санах ойн зарцуулалт, PBR холболтын алдаа, эх серверийн траффик зэрэг 7 үндсэн үзүүлэлтийг бодит хугацаанд хянаж, систем бүрэн тогтвортой байгааг баталгаажуулжээ.
Үр дүнд нь: Дэлхийн сүлжээнд нэг ч хүсэлт уналгүйгээр, нэг ч микросекундын саатал гаралгүйгээр нийт 100 TB RAM амжилттай суллагдсан байна!
Хөгжүүлэгчдэд өгөх сургамж
Cloudflare энэхүү шинэчлэлээ нээлттэй эхийн pingora-ketama сангийнхаа (v2 ring) шинэ хувилбарт оруулан нийтийн хүртээл болгожээ.
Энэхүү туршлага нь орчин үеийн програм хангамжийн инженерүүдэд нэгэн чухал сургамжийг өгч байна: Хамгийн том дэд бүтцийн түгжрэл нь үргэлж шинэ кластер, нэмэлт сервер нэхдэггүй. Өгөгдлийн бүтцээ зөв сонгох (Data layout), хэрэгцээгүй байтуудыг танах, онолын математикаа бодит кодондоо хэрэглэх нь хэдэн сая долларын дэд бүтцийн зардлыг хэмнэж чаддаг болохыг энэ удаагийн оновчлол бэлхнээ харууллаа.
Эх сурвалж: Cloudflare Engineering Blog
Сэтгэгдэл
Ачаалж байна...