天天看點

openEuler 資源使用率提升之道 04

概述

在資料中心伺服器或者各種雲叢集(後續簡稱叢集)的生産環境上,部署着很多日常的線上(LC, Latency-critical service)服務。這類服務具有一定的負載不确定性,叢集需要将伺服器的平均使用率保持在較低的水準,使得當突發流量帶來請求洪峰時,仍有充足資源用于計算與響應,進而避免了請求堆積造成的服務癱瘓,保證使用者能夠擁有良好的體驗。但是這樣做造成了大批的空閑資源浪費,提高了維護成本。在這種條件下想要提高資源使用率,一種直接的方式是線上服務負載較低時,部署另一種任務,提高資源的利用效率。這類應用不要求有極高的響應速度,但是将耗費較大的計算資源,我們稱之為離線任務(BE, Best-effort batch)。是以各大雲服務廠商引入線上離線混合部署方案來提升伺服器的資源使用率,以降低雲的營運成本。但事物的發展是具有兩面性的,混合部署也不例外,提升資源使用率的同時也會帶來資源隔離的問題。

本文詳細介紹并分享關于提升 CPU 資源隔離的混部技術細節:

  • 「CPU 搶占」:當一台服務上同時存在線上服務、離線服務,如果不對離線服務加以限制,離線服務将會盡可能多的占用資源,進而增加線上任務的相應時延。是以本方案在同一個核上的線上(LC)服務能夠搶占壓制離線(BE)服務,最終保證線上服務的 QoS.
  • 「SMT 隔離控制」:同一個實體 CPU 的超線程共享核心的硬體資源,如 Cache 和計算單元。當線上任務和離線任務同時運作在一對超線程上時,會因為硬體資源争搶出現互相幹擾的情況。此時需要驅離離線任務,該 HT 核進入 idle。

在混部場景 CPU 在離線排程的實作中,存在線上作業時,我們會對離線任務進行 throttle,以確定線上任務的 CPU 資源供應。當開啟 HT 後,我們會驅離同時運作在同一個實體核且運作在不同邏輯核的離線任務。本方案的設計目标是保證線上業務服務品質前提下實作資源使用率最大化提升。是以本方案的設計是圍繞如何提升 CPU 資源使用率和保障線上業務的響應速度展開。主要包括以下兩個子特性的設計:

特性一、CPU 搶占

(1)線上任務搶占時延保證

為了保證線上任務能夠快速搶占離線任務,我們預設會将離線任務的排程政策設定為

SCHED_IDLE

,而線上任務排程政策不做修改(通常情況下線上任務的排程政策為

SCHED_OTHER

),當線上任務搶占離線任務時,可以快速搶占,不受限于

sched_min_granularity_ns 和sched_wakeup_granularity_ns

機制限制。

(2)線上任務絕對壓制離線任務

當線上任務在運作時,離線任務需要停止運作,以避免和線上任務搶占 CPU 資源,是以線上任務需要盡可能地壓制離線任務,通過引入

throttle 機制

對離線任務進行限制, 在一個 CPU 上同時存在線上和離線任務的場景下,将

離線組對應的cfs_rq

添加到一個

全局 percpu

連結清單

throttle_list

,進而将 CPU 資源完全讓給線上任務。具體流程如下:

openEuler 資源使用率提升之道 04

圖 1 離線任務 throttle

特性二、SMT 隔離控制

由于同一個實體 CPU 上的超線程共享核心的硬體資源,比如 Cache 和計算單元。當線上任務和離線任務同時運作在一對超線程上時,互相之間會因為硬體資源争搶,而出現互相幹擾的情況。而 CFS 在設計時完全沒有考慮這個問題。其結果是,在混部場景中,線上業務的性能受損。實際測試使用 CPU 密集型 benchmark,因超線程導緻的性能幹擾可達 40%+。雖然 Linux 5.14 版本已經合入了 Core Scheduing,但該特性本身是為了解決利用 SMT 側信道問題的,避免互相不被信任的兩個程序工作在一個核的不同 SMT 上。其有幾點缺陷是我們不用該特性做 SMT 驅離的理由,首先其設計和實作過重,開銷較大(比如 core 級别的 rq lock)。其次其并不支援組排程功能,是以程序為粒度進行隔離,而我們的需求是希望對線上任務和離線任務進行隔離。為了盡可能減輕這種競争的影響,我們讓一個核執行線上任務的時候,它對應的 MT 上不再運作離線任務;或者當一個核上有離線任務運作的時候,線上任務排程到了其對應的 HT 上時,會由該線上任務發送 IPI 将離線任務驅趕走。保證線上任務運作時不被幹擾。如下圖所示:

openEuler 資源使用率提升之道 04

圖 2 SMT 隔離控制方案設計

方案需要重點解決的問題

(1)離線任務 kill boost

當線上任務 100% 運作時,kill 一個離線任務,此時離線任務需要得到運作以釋放一些系統資源,但是因為目前方案線上任務會對離線任務産生絕對壓制,為此引入 kill boost 解決此問題;

離線任務所在 group 為離線 group,root group 為線上任務,當對一個離線任務進行 kill 時,将對應的離線任務移入到 root group, 進而使離線任務變為線上任務,能夠得到機會運作進而釋放資源。

(2)優先級反轉

如果線上任務和離線任務之間有共享資源(比如核心中的一些公共資料),當離線任務因通路共享資源而拿到鎖(抽象一下,不一定是鎖)後,如果被“絕對壓制”,一直無法運作,當線上任務也需要通路該共享資源,而等待相應的鎖時,優先級反轉出現,導緻死鎖(長時間阻塞也可能)。優先級反轉是排程模型中需要考慮的一個經典問題。

目前該方案主要分為兩個子產品,優先級反轉檢測和優先級反轉處理:

  • 「優先級反轉檢測」:出現優先級反轉的前提的是,線上任務長時間 100%占用 CPU,導緻離線任務被壓制無法釋放資源導緻,基于這一特點,我們可以通過檢測離線任務是否長時間沒有得到運作來判斷是否可能存在優先級反轉流程。
  • 「優先級反轉處理」:當檢測到優先級反轉時,對應 CPU 上的離線任務不再被線上任務壓制, 可以正常運作,在傳回使用者态之前會進入睡眠流程,其中每次睡眠時間可以根據參數進行設定。當 CPU 處理完隊列中的所有任務時,就會進入 idle, 此時代表目前 CPU 恢複正常情況。代表優先級反轉問題已經解決,進入正常的在離線混跑邏輯。

任務管理

容器混部場景中,在離線任務是以

Cgroup 組

的形式進行配置的,是以我們提供了

Cgroup 接口

進行任務管理。對應路徑為:

/sys/fs/cgroup/cpu/xxx/cpu.qos_level
           

其中,

cpu.qos_level

檔案代表目前 group 裡任務的在離線屬性,預設值為 0,代表該任務為線上任務組; 若值為-1 則代表為離線任務組

于是,如果想要對任務進行管理,可以在工作節點上建立離線任務組,将離線任務的 pid 寫入到該組的 task 中,再設定對應的

cpu.qos_level

檔案:

# echo <pid> > /sys/fs/cgroup/cpu/xxx/tasks
# echo -1 > /sys/fs/cgroup/cpu/xxx/cpu.qos_level
           

通過混部引擎 rubik 進行管理

在容器混合部署場景下,混部引擎 rubik 可以自動感覺使用者配置的業務優先級并配置其 CPU 優先級屬性,rubik 具體的介紹和使用詳見《openEuler 資源使用率提升之道 03:rubik 混部引擎簡介》。

針對本文提到的 CPU 優先級的配置,使用者隻需要在部署業務 pod 時,在 yaml 内添加

volcano.sh/preemptable

的 annotation 辨別業務屬性,rubik 就會自動設定 pod 對應 cgroup 組的 cpu.qos_level 值。例如,如下為一個 nginx 線上業務 pod 的 yaml 檔案:

# cat nginx-online.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-online
  annotations:
    volcano.sh/preemptable: "false"   # volcano.sh/preemptable為true代表業務為離線業務,false代表業務為線上業務,預設為false
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "1"
      requests:
        memory: "200Mi"
        cpu: "1"
           
# cat /sys/fs/cgroup/cpu/kubepods/pod59f1cdfa-a0ad-4208-9e95-efbef3519c00/cpu.qos_level
0
           

總結

加入我們

繼續閱讀