零代價修復海量服務器的內核缺陷——UCloud內核熱補丁技術揭祕

下述爲UCloud資深工程師邱模炯在InfoQ架構師峯會上的演講——《UCloud雲平臺的內核實踐》中很是受關注的內核熱補丁技術的一部分。給你們揭開了UCloud雲平臺內核技術的神祕面紗。服務器

 

如何零代價修復海量服務器的Linux內核缺陷?數據結構

 

對於一個擁有成千上萬臺服務器的公司,Linux內核缺陷致使的死機家常便飯。讓工程師們糾結的是,到底要不要經過給服務器升級內核來修復缺陷?升級意味者服務器重啓、業務中斷以及繁重的準備工做;不升級則擔憂服務器死機,一樣形成業務中斷和繁重的善後工做。架構

 

而在今天的雲計算時代,一臺宿主機每每運行多個雲主機,每一次重啓不論是主動升級仍是被動死機,都意味着中斷其上運行的全部雲主機。所以,宿主機內核缺陷的修復更加棘手。運維

 

而做爲一個支撐着上萬家企業用戶IT基礎架構的雲服務商,UCloud雲平臺上的海量宿主機又是如何修復內核缺陷的呢?函數

 

邱模炯透露,若是按照傳統的重啓方式來修復,那麼不管是對於UCloud或是用戶,都意味着繁重的運維和業務中斷。可是,UCloud經過「內核熱補丁技術」——即給運行中的內核打上二進制補丁,UCloud已經作到了零代價免重啓修復海量服務器的內核缺陷!目前爲止,UCloud對所發現的上游內核10+個缺陷全以熱補丁方式修復,累計數萬臺次,無一例失敗且無任何反作用;理論上避免了相應次數的宿主機重啓及所隱含的雲主機業務中斷。這項技術在UCloud已經成熟。工具

 

UCloud內核熱補丁技術揭祕post

 

UCloud的熱補丁技術基於多年前的開源ksplice加以定製優化而來,經過加載一個特殊準備的熱補丁模塊來修復內核。其過程以下圖所示:性能

 

 

 

熱補丁模塊由ksplice程序編譯生成,包含有缺陷的二進制指令和修復後的二進制指令(這些二進制按函數級別組織);模塊加載後,自動定位到內核的缺陷處並以修復指令動態替換缺陷指令。優化

 

ksplice熱補丁模塊的建立原理見下圖:網站

 

首先獲取一份運行中內核對應的源碼並編譯出二進制,稱爲pre對象;打上源碼補丁再次編譯,稱爲post對象。而運行中的內核二進制稱爲run對象。post和pre逐條指令比較並找出存在差別的函數,以後把這些差別合併爲內核模塊形式的熱補丁。

 

建立好的熱補丁模塊在加載到內核時還會作些檢驗工做:對比pre和run對象。只有經過檢驗才能成功加載進內核。pre-run比較的目的是爲了辨別編譯過程差別是否過大以至於不能打入post對象的熱補丁;更重要的是,從pre-run差別中提取的關鍵信息才能把post對象的熱補丁順利打入運行中內核。

 

熱補丁模塊加載到內核後,便自動進行內核修復。也就是使用熱補丁中的二進制指令替換有缺陷的二進制指令。這裏ksplice利用了Linux內核的stop_machine機制:中止全部CPU的執行,只留下主CPU進行二進制指令替換。值得注意的是,stop_machine後若是發現任何一個線程棧的內容與熱補丁存在衝突,就須要退出指令替換以免系統崩潰。因此並不是全部熱補丁都能打入內核,有些頻繁使用的內核函數(如schedule, hrtimer相關)就沒法熱補丁,重試次數再多也無濟於事。

 

ksplice同時支持對內核和模塊進行熱補丁,也支持熱補丁後疊加熱補丁,靈活方便。不過也存在一些缺陷:stop_machine期間整個系統處於中斷狀態,雖然單次中斷小於1ms,但有些時候屢次重試的累計中斷也不小;另外,有些頻繁使用的函數沒法打入熱補丁。

 

kpatch和kgraft

kpatch和kgraft均是近期新出現的內核熱補丁技術,前者屬於Redhat公司,後者SuSE。二者原理和ksplice大體相同,都想合併進Linux內核,內核社區正在爭議對比。

 

kpatch原理和前面講的ksplice很接近。最大的區別在於二進制指令替換,stop_machine中止全部CPU執行後ksplice直接修改,而kpatch則藉助ftrace機制來觸發替換。目前的實現上,kpatch有較大侷限性,不支持對模塊打熱補丁,不支持函數靜態變量等。

 

kgraft原理也基本同樣。主要的差別有兩點:

 

1)熱補丁生成方法不一樣;

2)熱補丁打入內核過程裏kgraft用到了RCU漸進方法。得益於RCU方法,kgraft無需像ksplice和kpatch同樣調用stop_machine並檢查線程棧的衝突。不過它的缺點也緣於RCU,涉及到數據結構改變時,kgraft更難經過編寫輔助代碼打入熱補丁,這限制了kgraft的應用範圍。

 

有關kpatch和kgraft的詳細狀況請分別參考Redhat和SuSE網站的技術資料。

 

除了免重啓修復,熱補丁還用於內核開發過程的性能分析和故障定位。好比,加上性能統計代碼生成熱補丁,就能夠在線分析感興趣的性能問題;加入額外調試代碼捕捉運行中內核的異常。這些很是有用,更是海量服務器裏捕捉不可重現內核異常的不二法寶。因爲熱補丁不須要重啓服務器,既可打入也可撤銷,因此不會有反作用。

 

UCloud對開源Ksplice的優化主要在如下三個方面:

 

支持高版本內核

熱補丁技術與內核緊密耦合。不一樣版本的內核在指令結構體,符合表結構體和一些特性上(好比早期內核沒有ftrace)有所不一樣,直接影響熱補丁成敗。UCloud研究了各版本內核的區別,使得同一份ksplice支持各個版本的Linux內核。值得一提的是,解決了ftrace與ksplice不兼容的問題。

 

容許熱修復頻繁調用的函數

無論什麼樣的熱補丁技術,兩種類型的內核函數難以熱補丁:頻繁使用的內核函數如schedule, hrtimer;常常處於線程棧內核部分頂部的函數,如sys_poll, sys_read。UCloud更改了ksplice相關內核代碼和用戶態工具,成功解除了這些限制,好比UCloud現網服務器已打入了三個hrtimer熱補丁。

 

減小業務中斷時間

ksplice是在stop_machine後替換二進制指令的。雖然單次stop_machine對業務形成的中斷在一毫秒左右,但有些頻繁使用的內核函數須要大量重試才能碰到合適的熱補丁時機,因而會形成最長達上百毫秒的中斷。UCloud在此作過一點優化,使得業務中斷時間控制在十毫秒級別。

 

海量服務器環境下熱補丁技術可用來零代價且無反作用地修復內核缺陷,並且內核開發也因熱補丁能走得更遠更好。之前由於缺少輔助分析手段和害怕內核BUG,即便適合在內核實現的特性也被告誡移到用戶態實現,然而有了熱補丁,相關觀念也能夠適當調整,內核開發也能夠更加大膽和跳脫。

相關文章
相關標籤/搜索