Categories
程式開發

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐


Alibaba Cloud Linux 2 (原Aliyun Linux 2)是阿里雲操作系統團隊基於社區版4.19 LTS 內核打造的一款針對雲產品優化的下一代Linux 操作系統發行版,不僅提供Linux社區的最新增強功能,也提供了雲上最佳用戶體驗並針對阿里雲基礎設施做了深度的優化。今年 3 月 26 日Alibaba Cloud Linux 2 LTS 正式發布,這是一個重要的里程碑。在 LTS 版本中,阿里雲操作系統團隊將提供長期的技術支持、穩定的安全更新以及持續的特性與優化。

阿里云同時推出了基於 Alibaba Cloud Linux 2 LTS 的快速啟動版鏡像,當前正在火熱公測中,用戶可以在北京、杭州、張家口、香港等可用區的控制台中購買試用。 Alibaba Cloud Linux 2 LTS 為快速啟動版做了大量優化工作,本文將深度披露相關操作系統側的優化技術細節。

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 1

鏡像目前在北京、杭州、張家口、香港等可用區公測,歡迎購買試用。

1、Linux 系統啟動流程簡介

我們首先需要定義 Linux 系統啟動 ,這裡我們定義為從系統上電到用戶能夠登錄終端的時間為啟動時長,對於雲上用戶來說,從 Guest OS 啟動到用戶可以通過 ssh 登錄的階段,為系統啟動階段。通用 Linux操作系統啟動大致分為三個階段:引導階段(第一階段),內核啟動階段(第二階段)及用戶態啟動階段(第三階段),相關流程如下圖所示:

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 2

下面來看看各階段大致的啟動流程。

第一階段

Bootloader 是位於系統引導扇區的一段獨立的系統程序,用於系統啟動初期的硬件初始化,系統分區識別,系統內核加載及跳轉執行。目前應用比較廣泛的bootloader 是用於通用系統的 Grub2 和嵌入式系統的 uboot。 Grub2是多重引導器(multiboot),提供交互界面,默認配置下 Grub2 有5秒交互超時時間,啟動耗時較長。

第二階段

Bootloader 加載 Linux 內核(一般為壓縮內核 vmlinuz)到內存,並運行內核自解壓縮程序,解壓後跳轉至start_kernel(),開始內核初始化流程:

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 3

第三階段

Linux 內核完成一系列初始化動作之後,開始運行 init 程序,創建 PID 為 1 的用戶態進程,將系統控制權從內核態跳轉到用戶態。 init 程序會繼續進行用戶態啟動流程,開啟各種必要的或是預先配置的系統服務,最後啟動登陸服務,完成整個系統的啟動。

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 4

Initrd 與 Switch Root

init 是用戶態程序,存放在系統根文件系統(rootfs)裡。內核需要先掛載 rootfs,才能運行 init 程序。通用 Linux發行版需要支持多種磁盤設備及文件系統,這需要內核預加載多種可能的磁盤設備驅動及文件系統相關用戶態工具軟件才能正確識別rootfs。而這些驅動及用戶態工具一般都存放在 rootfs 中,形成一個循環依賴。

為解決這個問題,initrd 應運而生,將掛載rootfs 必要的驅動、用戶態工具以及其他需要預加載的代碼從rootfs 中抽取出來,並依照rootfs的文件結構,打包成一個小的rootfs,做成一個內存盤(ram disk)。內核在掛載最終的 rootfs 之前,先從內存中掛載initrd,加載必要的驅動後,先運行 initrd 中的 init 程序,掛載最終的 rootfs。然後執行 switch root動作,切換至最終的 rootfs。

Alibaba Cloud Linux 2 採用 systemd 來管理用戶空間啟動流程,systemd 就是 init 程序,initrd 使用壓縮格式的initramfs 文件。因此在加載 initrd 之前,內核需要先解壓縮 initramfs。

cloud-init

在阿里雲 ECS 環境中,cloud-init 是一個必不可少的初始化配置工具。在實例啟動階段能從多種數據源讀取相關數據並據此對虛擬機進行配置,如用戶密碼,主機名,網絡,用戶數據等等一些配置。

2、工欲善其事必先利其器

優化系統啟動時間,自然需要先對系統啟動畫像,了解啟動時間分佈情況,找出系統啟動耗時熱點。

啟動時間測量

Linux 操作系統有如下常見的啟動時間測量統計方法:

  • systemd-analyze : systemd 自帶的啟動分析工具,能夠給出總的啟動時間消耗,已經用戶態服務啟動耗時統計。

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 5

  • dmesg : dmesg 輸出內核啟動日誌,時間戳能夠幫助分析內核初始化各階段耗時情況。配合-d選項計算出日誌間的時間差,方便快速定位內核啟動過程中耗時熱點。

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 6

  • initcall_debug : 內核啟動參數,開啟後會統計內核各初始化函數的耗時情況,相比dmesg -d更加精確。
  • printk/trace_printk : 要分析一些啟動熱點的細化耗時情況時,手動增加一些 printk/trace_printk 探針能夠幫助獲取時間統計信息。
  • ftrace : 必要時也可開啟內核早期 ftrace 功能,幫助分析熱點耗時。不過需要注意開啟 ftrace 後可能會導致函數延時增加,因此不宜參考 ftrace 得出函數絕對耗時,可以參照 trace 結果幫助分析熱點函數的耗時邏輯。

還有其他一些時間測試方法,以及圖形化畫像工具,這裡不一一介紹。

啟動耗時熱點分析

對早期 Alibaba Cloud Linux 2 啟動進行測量畫像後,按耗時排序,得到如下耗時熱點:

熱點 耗時 內核啟動佔比 總啟動佔比
mem init ~35 3.5% 0.7%
ORC unwind init ~90 9% 1.8%
buddy init 250 25% 5%
console enable ~60 6% 1.2 %
initramfs unpack 250 25% 5%
free initmem 270 27% 5.4%
mouse probe 650 65% 13%
systemd initrd 600 N/A 12%
mount rootfs 200 N/A 4%
cloud init 2740 N/A 54.8%

採樣機器:ecs.g6.large 2C8G 實例

可見:

  • 內核啟動階段,鼠標探測耗時佔比較高。
  • 總體啟動耗時中,一半以上的時間消耗在用戶態 cloud-init 進程上;

3、 快速啟動優化

常用啟動優化方法

常用的啟動優化方法大致如下:

  • 瘦身
    • 移除不必要的代碼,如模塊,服務等,縮減啟動初始化步驟;
    • 移除不必要的測試,調式及打印;
    • 精簡共享庫;
  • 異步、並行
    • 將耗時動作從關鍵路徑移除,延後執行;
    • 將順序動作並行化執行 ;
  • 原地執行(XIP) : 多用於嵌入式系統;
  • 定制化 : 將通用初始化程序定制化 ;
  • 算法優化 : 改進算法,加速初始化時間。

我們的優化策略

去 initrd

從前面的啟動耗時熱點分析結果可以看出,initrd 解壓縮及 initrd systemd 耗時佔了較大比率。

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 7

Alibaba Cloud Linux 2 只運行於阿里云云服務器上,系統盤設備基本固定為virtio-blk 設備,根文件系統格式基本固定為ext4文件系統,去掉initrd 方案應該可行,理論上會優化掉initramfs unpack(270) + initrdsystemd(560) ~ 800ms 的啟動耗時。於是開搞:

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 8

可見 initrd systemd 時間確實優化掉了,但是! 總的啟動時間並沒有理論優化收益

繼續探索原因,發現是內核啟動耗時增加了約 400ms。進一步分析發現,啟動耗時熱點之一的 mouse probe(600ms),去 initrd 之前是與 initrd systemd 並行執行的。

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 9

去掉initrd後,這部分時間就直接計入內核啟動時間了。抵去優化掉的 initramfs unpacking 的 200ms,內核實際增加了 400ms 左右。

因此,要最大化去 initrd 的優化收益,必須同時解決 mouse probe 的耗時。

延遲probe

通用 Linux 系統需要支持多種 IO 設備,而鼠標鍵盤是比較常用的輸入設備,特別是鼠標,產品繁多,接口多樣。系統啟動過程中加載鼠標驅動後,需要掃描多種 IO 總線來探測鼠標設備,這一過程非常耗時。

依據前面提到的優化方法,我們有兩種方案:

  1. 對雲環境定制鼠標驅動,固定探測 virtio 設備;
  2. 將鼠標探測從啟動關鍵路徑剝離,延遲探測,與後面系統啟動服務並行;

第一種方案需要重構相關代碼,成本較高;而且定制化限制較多,無法與開源社區協作。因此需要思考第二種方法:延遲探測。一種簡單可行的方法是將原本內置(built-in)的設備驅動重新編譯為內核模塊(kernel module),因內核模塊存放在根文件系統,所以加載時機被動推遲到根文件系統掛載之後,此時內核已經啟動完成,自然與用戶態初始化進程並行執行。

測試結果如下:

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 10

帶 initrd 啟動

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 11

不帶 initrd 啟動

可見,內核啟動時間縮減約 200ms,優化掉 initrd systemd 時間;鼠標設備探測延後至 userspace 初始化階段,導致userspace 啟動時間略有增加。獲得預期的啟動時間優化。

內存初始化優化

內存初始化也是內核啟動熱點之一,特別是在大規格實例上,內存初始化耗時佔比較高。圖中為 750GB 實例內存初始化耗時:

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 12

mem init 耗時近 2s

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 13

buddy init 耗時 1.8s

內存初始化動作是在內核啟動的關鍵路徑上,優化思路是並行初始化。因內存初始化時機較早,系統多CPU還未初始化完成,所以需要將內存初始化延後至CPU初始化完成之後,採用多線程並行執行內存初始化。這部分工作社區已經完成,通過內核配置deferred struct page init特性來開啟。

開啟後,內存初始化延後,按 NUMA node 並行執行:

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 14

前半部耗時約 0.2s

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 15

後半部耗時約 1.3s

free initmem 修復

早期 Alibaba Cloud Linux 2 啟動優化前有一個概率性的啟動熱點,free initmem 到 buddy 系統時,會大概率出現200ms 以上延時,dmesg 日誌顯示如下,耗時超過 200ms:

1
[    0.687494] rtc_cmos 00:00: setting system clock to 2020-03-03 15:09:38 UTC (1583248178)
2
[    0.915315] Freeing unused kernel image memory: 1836K

經分析,發現是社區已知問題,並在新內核已經修復,移植修復後耗時約 5ms,基本消除這部分延時:

1
[    0.482477] rtc_cmos 00:00: setting system clock to 2020-03-03 15:01:41 UTC (1583247701)
2
[    0.487438] Freeing unused kernel image memory: 1856K

ORC unwind 初始化

內核中有一些靜態表,需要在內核初始化階段排序,有些表體積較大,初始化耗時佔比也不容小覷。如 ORC unwind 表格初始化排序,耗時約 90ms:

1
[    0.087330] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1910969940391419 ns
2
[    0.179718] random: get_random_bytes called from start_kernel+0x8b/0x

這些靜態表格是在內核構建階段生成,因此可以將排序動作從內核初始化階段移除,放到內核構建階段完成,以節省內核初始化時間。經調查發現社區已經有類似的優化方案,異常處理表(exception table)排序移植到了內核構建階段完成。於是筆者對異常處理表改進,增加了 ORC unwind 表格構建階段排序優化,相關係列補丁已經被社區接受,合入主線。

優化後基本削減了這部分耗時:

1
[    0.037253] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1910969940391419 ns
2
[    0.040714] random: get_random_bytes called from start_kernel+0x8b/0x563 with 

其它優化

另外,啟動階段的 console 輸出也是一個相對耗時的動作,因為串行口的波特率是固定的,大量是輸出會形成阻塞導致console enabled 延時較大。例如:

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 16

開啟 console output, console 耗時 2.6s

Alibaba Cloud Linux 2 LTS OS 啟動優化實踐 17

配置內核參數 quiet, 關閉 console output

此外,從前面的數據裡可以看到,cloud-init

等服務啟動時間佔了總啟動時間的很大比例。操作系統團隊聯合阿里雲虛擬化、鏡像等團隊,從底層雲基礎設施系統到用戶態程序都做了大量優化,這些優化極大地提升了用戶整體端到端啟動的體驗。在 Alibaba Cloud Linux 2 快速啟動版中,用戶可以更直觀地感受到這些啟動優化帶來的效果。

4、下一步工作

在操作系統層面,雖然 Alibaba Cloud Linux 2 LTS在啟動優化已經取得了不錯的效果,啟動性能得到進一步提升,但仍然還有進一步挖掘的空間。特別是內存初始化這塊,仍然是大規格實例啟動熱點。即便已經開啟的deferred page init 特性,但內存初始仍然限於node 間並行,而node內並行初始化值得進一步挖掘,特別對當前ECS實例大都為單node 實例(NUMA 關閉)的場景下,理論上有更大的收益。

作者介紹

阿里雲操作系統團隊,飛能

本文轉載自公眾號雲巔論劍。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MzUxNjE3MTcwMg==&mid=2247484339&idx=1&sn=1b91d732a190657066e73f28d23c3892&chksm=f9aa316aceddb87cab3ea7ef5deb0c1b088e6c962be5d725f8c98620185f9e3e76a7bf00928c&token=600041196&lang=zh_CN#rd