Linux调度系统全景指南(终结篇)
點擊上方藍字關注公眾號,更多經典內容等著你
? ?
?
| 導語本文主要是講Linux的調度系統, 本篇是終結篇,主要講當前多核系統調度策略和調度優化,調度可以說是操作系統的靈魂,為了讓CPU資源利用最大化,Linux設計了一套非常精細的調度系統,對大多數場景都進行了很多優化,系統擴展性強,我們可以根據業務模型和業務場景的特點,有針對性的去進行性能優化。歡迎大家相互交流學習!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 目錄
上篇請看(CPU和中斷):Linux調度系統全景指南(上篇)
中篇請看(搶占和時鐘):Linux調度系統全景指南(中篇)
下篇請看(進程和線程):Linux調度系統全景指南(下篇)? ?? ? ?? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?多核調度
在單核系統中,調度器只需要考慮任務執行先后順序的問題,在多核系統中,除了任務先后問題,調度器還需要考慮CPU分配問題。也就是說,在多核系統中,調度器還需要決定任務在哪個CPU上運行,需要盡量做到公平和整體性能最大化。一般來說,調度器可以被劃分為以下幾類:
(1)全局類(Global):即一個調度器就可以管理系統中的所有CPU,任務可以在CPU之間自由遷移。
(2)集群類(Clustered):系統中的CPU被分成互不相交的幾個cluster,調度器負責調度任務到cluster內的CPU上去。
(3)分區類(Partitioned ):每個調度器只管自己的那個CPU,系統有多少個CPU就有多少個調度器實體。
(4)任意類(Arbitrary ):每一個任務都可以運行在任何一個CPU集合上。
?
內核調度系統針對CPU架構演進:單CPU->SMP->NUMA->復雜混合架構, 做了針對性的優化設計;
SMP
? ? ? ?
SMP (Symmetric Multiprocessing),對稱多處理器. 顧名思義, 在SMP中所有的處理器都是對等的, 它們通過總線連接共享同一塊物理內存,這也就導致了系統中所有資源(CPU、內存、I/O等)都是共享的,其架構簡單,但是拓展性能比較差。
多處理器系統上,內核必須考慮幾個額外的問題,以確保良好的調度效率。
?CPU負荷必須盡可能公平地在所有的處理器上共享。如果一個處理器負責3個并發的應用程序,而另一個只能處理空閑進程,那是沒有意義的。
進程與系統中某些處理器的親合性(affinity)必須是可設置的。例如在4個CPU系統中,可以將計算密集型應用程序綁定到前3個CPU,而剩余的(交互式)進程則在第4個CPU上運行。
內核必須能夠將進程從一個CPU遷移到另一個。但該選項必須謹慎使用,因為它會嚴重危害性能。在小型SMP系統上CPU高速緩存是最大的問題。對于真正大型系統, CPU與遷移進程此前使用的物理內存距離可能有若干米,因此對該進程內存的訪問代價高昂。
進程對特定CPU的親合性 ,定義在task_struct的 cpus_allowed 成 員 中 。Linux 提供了sched_setaffinity系統調用,可修改進程與CPU的現有分配關系
在SMP系統上,每個調度器類的調度方法必須增加兩個額外的函數:
load_balance:允許從最忙的就緒隊列分配多個進程到當前CPU,但移動的負荷不能比max_load_move更多,每當內核認為有必要重新均衡時,核心調度器代碼都會調用這些函數;
move_one_task:move_one_task則使用了iter_move_one_task,從最忙碌的就緒隊列移出一個進程,遷移到當前CPU的就緒隊列;
在SMP系統上,周期性調度器函數scheduler_tick按上文所述完成所有系統都需要的任務之后,會調用trigger_load_balance函數,這會引發
SCHEDULE_SOFTIRQ軟中斷softIRQ,該中斷確保會在適當的時機執行run_rebalance_domains。該函數最終對當前CPU調用rebalance_domains,實現負載均衡。
?
NUMA
? ? ? ??
非統一內存訪問架構(英語:Non-uniform memory access,簡稱NUMA)是一種為多處理器的電腦設計的內存架構,內存訪問時間取決于內存相對于處理器的位置。在NUMA下,處理器訪問它自己的本地內存的速度比非本地內存(內存位于另一個處理器,或者是處理器之間共享的內存)快一些;
非統一內存訪問架構的特點是:被共享的內存物理上是分布式的,所有這些內存的集合就是全局地址空間。所以處理器訪問這些內存的時間是不一樣的,顯然訪問本地內存的速度要比訪問全局共享內存或遠程訪問外地內存要快些。另外,NUMA中內存可能是分層的:本地內存,群內共享內存,全局共享內存;
在NUMA中還有三個節點的概念:
?? ? ? ?本地節點:對于某個節點中的所有CPU,此節點稱為本地節點。
? ? ? ? 鄰居節點:與本地節點相鄰的節點稱為鄰居節點。
? ? ? ? 遠端節點:非本地節點或鄰居節點的節點,稱為遠端節點。
CPU訪問不同類型節點內存的速度是不相同的,訪問本地節點的速度最快,訪問遠端節點的速度最慢,即訪問速度與節點的距離有關,距離越遠訪問速度越慢,此距離稱作Node Distance。正是因為有這個特點,所以我們的應用程序要盡量的減少不通CPU模塊之間的交互,也就是說,如果你的應用程序能有方法固定在一個CPU模塊里,那么你的應用的性能將會有很大的提升;
調度域(Scheduling Domain)
Scheduling Domains 是現代硬件技術尤其是多 CPU 多核技術發展的產物。現在,一個復雜的高端系統由上到下可以這樣構成:
它是一個 NUMA 架構的系統,系統中的每個 Node 訪問系統中不同區域的內存有不同的速度。
同時它又是一個 SMP 系統。由多個物理 CPU(Physical Package) 構成。這些物理 CPU 共享系統中所有的內存。但都有自己獨立的 Cache 。
每個物理 CPU 又由多個核 (Core) 構成,即 Multi-core 技術或者叫 Chip-level Multi processor(CMP) 。這些核都被集成在一塊 die 里面。一般有自己獨立的 L1 Cache,但可能共享 L2 Cache 。
每個核中又通過 SMT 之類的技術實現多個硬件線程,或者叫 Virtual CPU( 比如 Intel 的 Hyper-threading 技術 ) 。這些硬件線程,邏輯上看是就是一個 CPU 。它們之間幾乎所有的東西都共享。包括 L1 Cache,甚至是邏輯運算單元 (ALU) 以及 Power 。
在上述系統中,最小的執行單元是邏輯 CPU,進程的調度執行也是相對于邏輯 CPU 的。因此,后文皆簡稱邏輯 CPU 為 CPU,是物理 CPU 時會特別說明。在這樣復雜的系統,調度器要解決的一個首要問題就是如何發揮這么多 CPU 的性能,使得負載均衡。不存某些 CPU 一直很忙,進程在排隊等待運行,而某些 CPU 卻是處于空閑狀態。但是在這些 CPU 之間進行 Load Balance 是有代價的,比如對處于兩個不同物理 CPU 的進程之間進行負載平衡的話,將會使得 Cache 失效。造成效率的下降。而且過多的 Load Balance 會大量占用 CPU 資源,為了解決上述的這些問題,內核開發人員 Nick Piggin 等人在 Linux 2.6 中引入基于 Scheduling Domains 的解決方案。
? ? ? ? ? ??
每個 Scheduling Domain 其實就是具有相同屬性的一組 cpu 的集合。并且跟據 Hyper-threading, Multi-core, SMP, NUMA architectures 這樣的系統結構劃分成不同的級別。不同級之間通過指針鏈接在一起,從而形成一種的樹狀的關系;
負載平衡就是針對 Scheduling domain 的。從葉節點往上遍歷。直到所有的 domain 中的負載都是平衡的。當然對不同的 domain 會有不同的策略識別是否負載不平衡,以及不同的調度策略。通過這樣的方式,從而很好的發揮眾多 cpu 的效率;
基于 Scheduling Domains 的調度器引入了一組新的數據結構。下面先講一下兩個主要的數據結構:
struct sched_domain: 代表一個 Scheduling Domain,也就是一個 CPU 集合,這個集合里所有的 CPU 都具有相同的屬性和調度策略。Load Balance 是針對每個 domain 里的 CPU 進行的。這里要注意 Scheduling Domains 是分級的。像上節所講的復雜系統就分為 Allnuma_domain,Numa_domain, Phy_domain, Core_domain, Smt_domain(Cpu_domain) 五個等級。
struct sched_group: 每個 Scheduling domain 都有一個或多個 CPU group,每個 group 都被 domain 當做一個單獨的單元來對待。Load Balance 就是在這些 CPU group 之間的 CPU 進行的。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??調度優化
? ??
當前主流服務器都是多核,多處理器,多NUMA等多CPU架構系統,很多程序都同時跑著服務器里面,怎么最大化利用當前CPU資源,?讓整體運行效率更高呢?
調度優化的本質?
?CPU資源和任務之間最優匹配
這里討論CPU調度優化一些比較常見的優化點,即包括怎么提升CPU性能,怎么提升單個程序性能,也包括怎么提升整個系統的性能,后面計劃會詳細討論關于性能優化等內容,本篇探討了一些優化點:
性能瓶頸
在進行任何性能優化前,有個很重要的前提原則是要找到性能瓶頸點,然后才能針對性優化,這要求我們學會用性能分析工具:
perf?
perf stat 采集程序運行事件,用于分析指定程序的性能概況:
task-clock:目標任務真真占用處理器的時間,單位是毫秒,我們稱之為任務執行時間,后面是任務的處理器占用率(執行時間和持續時間的比值)。持續時間值從任務提交到任務結束的總時間(總時間在stat結束之后會打印出來)。CPU 利用率,該值高,說明程序的多數時間花費在 CPU 計算上而非 IO。
context-switches:上下文切換次數,前半部分是切換次數,后面是平均每秒發生次數(M是10的6次方)。
cpu-migrations:處理器遷移,linux為了位置各個處理器的負載均衡,會在特定的條件下將某個任務從一個處理器遷往另外一個處理器,此時便是發生了一次處理器遷移。即被調度器從一個 CPU 轉移到另外一個 CPU 上運行。
page-fault:缺頁異常,linux內存管理子系統采用了分頁機制,
當應用程序請求的頁面尚未建立、請求的頁面不在內存中或者請求的頁面雖在在內存中,
但是尚未建立物理地址和虛擬地址的映射關系是,會觸發一次缺頁異常。
cycles:任務消耗的處理器周期數;處理器時鐘,一條機器指令可能需要多個 cycles;
instructions:任務執行期間產生的處理器指令數,IPC(instructions perf cycle)
IPC(Instructions/Cycles )是評價處理器與應用程序性能的重要指標。(很多指令需要多個處理周期才能執行完畢),
IPC越大越好,說明程序充分利用了處理器的特征。
branches:程序在執行期間遇到的分支指令數。
branch-misses:預測錯誤的分支指令數
cache-misses:cache時效的次數
cache-references:cache的命中次數
perf top?對系統性能進行實時分析:
可以觀察到當前函數CPU使用占比;
可以查看當前系統最耗時的內核函數或某個用戶進程;
可以查看到當前耗時的指令;
CPU 火焰圖
支持多種工具源,可以從包含堆棧跟蹤的任何配置文件數據生成火焰圖,包括從以下配置文件工具生成:
Linux: perf, eBPF, SystemTap, and ktap
Solaris, illumos, FreeBSD: DTrace
Mac OS X: DTrace and Instruments
Windows: Xperf.exe
可以查看哪些代碼路徑很熱(CPU占有率高)。
可以顯示堆棧路徑上CPU消耗,找到耗時的最多的函數;
gperf 性能檢測
Gperftools是可以對用戶程序進行性能統計分析。主要優點之一是非常好的圖形輸出,低開銷和使用非常簡單(檢查的應用程序不需要任何重新編譯,只需預加載探查器的庫即可啟用分析,并且在需要時可以進行可選的庫鏈接編譯);
可以顯示各個調用連上函數執行占比,找到耗時異常的函數,找到性能瓶頸點;
性能優化
局部性原理
局部性有兩種,即時間局部性和空間局部性。時間局部性是指當一個數據被訪問后,它很有可能會在不久的將來被再次訪問,比如循環代碼中的數據或指令本身。而空間局部性指的是,當程序訪問地址為x的數據時,很有可能會緊接著訪問x周圍的數據,比如遍歷數組或指令的順序執行。由于這兩種局部性存在于大多數的程序中,硬件系統可以很好地預測哪些數據可以放入緩存,從而運行得很好。
緩存優化-緩存親和性
緩存訪問在設計多處理器調度時遇到的最后一個問題,是所謂的緩存親和度(cache affinity)。這個概念很簡單:一個進程在某個CPU上運行時,會在該CPU的緩存中維護許多狀態。下次該進程在相同CPU上運行時,由于緩存中的數據而執行得更快。相反,在不同的CPU上執行,會由于需要重新加載數據而很慢(好在硬件保證的緩存一致性可以保證正確執行)。因此多處理器調度應該考慮到這種緩存親和性,并盡可能將進程保持在同一個CPU上。
NUMA優化
比起訪問remote memory,local memory 訪問不僅延遲低(100ns),而且也減少了對公共總線(interconnect)的競爭。因此合理地放置數據(比如直接調用NUMA api)?, ?軟件調優化基本上還是圍繞在盡量訪問本地內存這一思路上。如果本地內存已用完,那么盡量訪問本CPU下相臨節點的內存,避免訪問跨CPU訪問最遠端的內存,可以提高20-30%性能,具體數據和當前應用相關。
CPU資源優化
CPU獨占:獨占CPU資源,減少調度影響,提高系統性能;
CPU綁定:減少CPU上下文切換,提高系統性能;
中斷親和 :?中斷負載均衡,減輕其他CPU負擔,提高系統性能;
進程親和:減少CPU上下文切換,提高系統性能;
中斷隔離:減少中斷對CPU調度影響,提高系統性能;
內存優化
采用更大容量的內存,減少內存不足對性能影響,實現用空間換時間的性能優化;
使用新內存技術,比如DDR4,好的內存硬件可以減少內存延遲,提高內存訪問速度,從而提高系統性能。
時鐘優化
時鐘芯片:采用更高精度時鐘芯片可以獲得更精確的時間,可以讓系統控制粒度更細;
時鐘頻率:時鐘頻率調整,調高->可以達到更細的計時精度,提高任務調度的效率;調低->可以降低時鐘中斷的打擾和降低功耗;
優先級優化
優先級調整(nice):調整進程優先級,可以讓進程運行更快;
調度算法優化
?linux 系統一些主線調度算法演進:
?O(n)調度算法?-2.4時代
O(n)調度器
調度器采用基于優先級的設計;
pick next算法非常簡單:對runqueue中所有進程的優先級進行依次進行比較,選擇最高優先級的進程作為下一個被調度的進程;
每次進程切換時, 內核掃描可運行進程的鏈表, 計算優先級,然后選擇”最佳”進程來運行;
O(n)調度器面臨的問題
時間復雜度問題,時間復雜度是O(n),當系統中的進程很少的時候性能還可以,但是當系統中的進程逐漸增多,選擇下一個進程的時間則是逐漸增大。而且當系統中無可運行的進程時,重新初始化進程的時間片也是相當耗時,在系統中進程很多的情況系下。
SMP擴展問題。當需要picknext下一個進程時,需要對整個runqueue隊列進行加鎖的操作,spin_lock_irq(&runqueue_lock);當系統中進程數目比較多的時候,則在臨界區的時間就比較長,導致其余的CPU自旋比較浪費
實時進程的運行效率問題,因為實時進程和普通進程在一個列表中,每次查實時進程時,都需要全部掃描整個列表,導致實時進程不是很“實時”
CPU資源浪費問題:因為系統中只有一個runqueue,則當運行隊列中的進程少于CPU的個數時,其余的CPU則幾乎是idle狀態,浪費資源
cache緩存問題:當系統中的進程逐漸減少時,原先在CPU1上運行的進程,不得不在CPU2上運行,導致在CPU2上運行時,cacheline則幾乎是空白的,影響效率。
總之O(n)調度器有很多問題,不過有問題肯定要解決的。所以在Linux2.6引入了O(1)的調度器。
?O(1)調度算法 -2.6時代
? ? ? ? ? ????????????
O(1)調度器:
pick next算法借助于active數組,調度器只需按優先級將下一個任務從特定活動的運行隊列中取出即可,無需遍歷runqueue,schedule()函數的時間復雜度為O(1)(把O(n)復雜度操作分攤到常規每一次操作中),改進了前任調度器的可擴展性問題;
消了前任算法定期更新所有進程counter的操作,動態優先級的修改分布在進程切換,時鐘tick中斷以及其它一些內核函數中進行;
O(1)調度器還更好地區分了交互式進程和批處理式進程,提供了大量啟示用于確定任務是受 I/O 限制還是受處理器限制算法,使調度更精細;
O(1)調度器面臨的問題
O(1)調度器對NUMA支持不完善;
算法的主要復雜性來自動態優先級的計算,調度器根據平均睡眠時間和一些很難理解的經驗公式來修正進程的優先級以及區分交互式進程,導致調度系統代碼的日趨復雜,難以維護;
????CFS調度算法?-如今主流
CFS 背后的主要想法是維護為任務提供處理器時間方面的平衡(公平性)。這意味著應給進程分配相當數量的處理器。分給某個任務的時間失去平衡時(意味著一個或多個任務相對于其他任務而言未被給予相當數量的時間),應給失去平衡的任務分配時間,讓其執行;
CFS 在叫做vruntime-虛擬運行時?的地方維持提供給某個任務的時間量。任務的虛擬運行時越小, 意味著任務被允許訪問服務器的時間越短 — 其對處理器的需求越高;
CFS 不直接使用優先級而是將其用作允許任務執行的時間的衰減系數。低優先級任務具有更高的衰減系數,而高優先級任務具有較低的衰減系數。這意味著與高優先級任務相比,低優先級任務允許任務執行的時間消耗得更快。這是一個絕妙的解決方案,可以避免維護按優先級調度的運行隊列;
CFS 維護了一個以時間為順序的紅黑樹,任務存儲在以時間為順序的紅黑樹中,對處理器需求最多的任務 (最低虛擬運行時)存儲在樹的左側,處理器需求最少的任務(最高虛擬運行時)存儲在樹的右側,pick_next算法選擇vruntime最小進程運行,即選取紅黑樹最左端的節點調度為下一個以便保持公平性;
?
?BFS & MuqSS-面向桌面或移動設備調度器
BFS的原理十分簡單,其實質正是使用了O(1)調度器中的位圖的概念,所有進程被安排到103個queue中,各個進程不是按照優先級而是按照優先級區間被排列到各自所在的區間,每一個區間擁有一個queue:
BFS 是一個適用于桌面或移動設備的調度器,設計地比較簡潔,用于改善桌面應用的交互性,減小響應時間,提升用戶體驗。它采用了全局單任務隊列設計,不再讓每個 CPU 都有獨立的運行隊列。雖然使用單個全局隊列,需要引入隊列鎖來保證并發安全性,但是對于桌面系統而言,處理器通常都比較少,鎖的開銷基本可以忽略。BFS 每次會在任務鏈表中選擇具有最小 virtual deadline 的任務運行。
MuqSS 是作者后來基于 BFS 改進的一款調度器,同樣是用于桌面環境任務調度。它主要解決了 BFS 的兩個問題:
每次需要在對應優先級鏈表中遍歷查找需要執行任務,這個時間復雜度為 O(n)。所以新的調度器引入了跳表來解決該問題,從而將時間復雜度降低到 O(1)。
全局鎖爭奪的開銷優化,采用 try_lock 替代 lock。
并行優化
并行:多個任務在同一時刻一起發生;
并發:多個任務在同一時刻只能有一個發生,CPU快速切換-操作系統分時復用,給人的感覺還是同時在跑,本質還是串行執行;并發的關鍵是你有處理多個任務的能力,不一定要同時;并行的關鍵是你有同時處理多個任務的能力,必須在多核系統上。
在多核系統中需要并行編程提高CPU運行效率
一般采用多線程來實現并行計算來縮短計算時間,提高多核系統整體性能;
通常是一個線程綁定一個核,可以實現多線程程序CPU利用率最大化;
盡量使用線程 local 數據,減少共享數據訪問;
盡量使用線程棧內存(local變量),減少指針引用,數據結構內存對齊(利用編譯指令),減少cache miss;
了解參考一些經典成熟并行編程模型對你設計多線程并行程序大有裨益:
? ? ? ?https://zh.wikipedia.org/wiki/%E5%B9%B6%E8%A1%8C%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B
了解一些典型并行編程思想,OpenCL的GPU并行設計,FPGA里面的多pipeline并行設計,MapReduce大數據計數里面的分而治之;
如果不得不訪問共享數據,盡量讓共享訪問代價最小化,讓鎖范圍最小,比如采用原子操作,無鎖編程等技術;
? ? ? ?
鎖和無鎖設計優化
如何正確有效的保護共享數據是編寫并行程序必須面臨的一個難題,通常的手段就是同步。同步可分為阻塞型同步(Blocking Synchronization)和非阻塞型同步( Non-blocking Synchronization),多線程里面難免需要訪問"共享內存",如果不加鎖很容易導致結果異常,程序首先要保證正確,即使影響性能低也需要加鎖來防止錯誤,此時該怎么提高CPU執行性能呢??一個比較重要的優化工作是鎖需要精心設計。
阻塞鎖
阻塞鎖通過改變了線程的運行狀態。讓線程進入阻塞狀態進行等待,當獲得相應的信號(喚醒,時間) 時,才可以進入線程的準備就緒狀態,準備就緒狀態的線程,通過競爭,進入運行狀態;
mutex 主要用于線程間互斥訪問資源場景;
semaphore 主要用于多個線程同步場景;
讀寫鎖針主要用于讀多寫少場景;
非阻塞鎖
非阻塞鎖不會改變線程狀態,使用時不會產生調度,通過CPU忙等待或者基于CAS(Compare - And - Swap)原子操作指令實現非阻塞訪問資源;
自旋鎖底層通過控制原子變量的值,讓其他CPU忙等待,cache親和性高和控制好鎖粒度,可以提高多線程訪問資源效率,主要用于加鎖時間極短且無阻塞點場景;
RCU鎖(Read-Copy Update)--非常重要一種無鎖設計,對于被RCU保護的共享數據結構,讀者不需要獲得任何鎖就可以訪問它(因此不會導致鎖競爭,不會導致鎖競爭,內存延遲以及流水線停滯,讀效率極高),但寫者在訪問它時首先拷貝一個副本,然后對副本進行修改,最后使用一個回調(callback)機制在適當的時機把指向原來數據的指針重新指向新的被修改的數據。這個時機就是所有引用該數據的CPU都退出對共享數據的操作,RCU實際上是一種改進的讀寫鎖,更能提高讀多寫少場景的系統性能;
原子操作可以保證指令以原子的方式執行(鎖總線或者鎖CPU緩存)——執行過程不被打斷,主要用于全局統計、引用計數,無鎖設計等場景;
CAS操作(Compare And Set或是 Compare And Swap),現在幾乎所有的CPU指令都支持CAS的原子操作,X86下對應的是 CMPXCHG 匯編指令。有了這個原子操作,我們就可以用其來實現各種無鎖(lock free)的數據結構,主要用于各種追求極限高性能場景,比如內存數據庫,內存消息隊列,DPDK的內存池mempool,java 的Disruptor等;
真正無鎖-沒有資源沖突,每個線程只使用local數據,最高級別的無鎖設計,適合分而治之算法場景;
IO優化
零拷貝:? 減少驅動到協議棧之間內存拷貝,減少用戶空間到內核空間內存拷貝,提升IO性能;
網卡硬件升級:10G->25G->40G->100G->200G->400G->...;
kernelbypass:繞過內核協議棧(路徑長,多核性能差),提高IO吞吐量;
? ?DPDK:?
Intel DPDK全稱Intel Data Plane Development Kit,是intel提供的數據平面開發工具集,為Intel architecture(IA)處理器架構下用戶空間高效的數據包處理提供庫函數和驅動的支持,它不同于Linux系統以通用性設計為目的,而是專注于網絡應用中數據包的高性能處理,適合高性能網關(IO需求大)場景;
PMD用戶態驅動,使用無中斷方式直接操作網卡的接收和發送隊列;
采用HugePage減少TLB Miss;
DPDK采用向量SIMD指令優化性能;
CPU親緣性和獨占;
內存對齊:根據不同存儲硬件的配置來優化程序,確保對象位于不同channel和rank的起始地址,這樣能保證對象并并行加載,性能也能夠得到極大的提升;
Cache對齊,提高cache訪問效率:
NUMA親和,提高numa內存訪問性能;
減少進程上下文切換:保證活躍進程數目不超過CPU個數;減少堵塞函數的調用,盡量采樣無鎖數據結構;
利用空間局部性,采用預取Prefetch,在數據被用到之前就將其調入緩存,增加緩存命中率;
充分挖掘網卡的潛能:借助現代網卡支持的分流(RSS, FDIR)和卸載(TSO,chksum)等特性;
? ?XDP:
?XDP(eXpress Data Path)為Linux內核提供了高性能、可編程的網絡數據路徑。由于網絡包在還未進入網絡協議棧之前就處理,它給Linux網絡帶來了巨大的性能提升(性能比DPDK還要高)
在網絡協議棧前處理
無鎖設計
批量I/O操作
輪詢式
直接隊列訪問
DDIO(網卡直接IO),支持硬件offload加速
支持eBPF,高效開發,安全可靠,性能好
和內核耦合緊密,適合基于內核網絡組件平滑演進高性能方案,比如DDOS防護,網絡采樣,高性能防火墻;
? P4?
p4 為一種高級可編程協議無關處理語言,結合可編程交換機芯片,編程能力強,可以實現業務offload 到硬件,轉發面 p4lang 定制開發,控制面可通過 Apache Thrift、gRPC 接口遠程管理,生態繁榮包括P4 Runtime、Stratum;
性能高,1.8T ~ 6.5T 線速轉發,更低時延;
每Tbps設備成本大幅降低;
主要應用場景是大流量的邊界網關,大流量無狀態網關,大流量狀態網關(當前P4交換機對內存容量支持有限,對配置量有一定的限制);
時空互換
Per CPU
Per-CPU是基于空間換時間的方法, 讓每個CPU都有自己的私有數據段(放在L1中),并將一些變量私有化到?每個CPU的私有數據段中. 單個CPU在訪問自己的私有數據段時, 不需要考慮其他CPU之間的競爭問題,也不存在同步的問題. ?注意只有在該變量在各個CPU上邏輯獨立時才可使用。
指令并行
通過展開循環降低循環開銷,提高指令并行執行效率;
向量指令
采用SIMD擴展指令集來優化指令執行效率;
分支預測
分支預測采用空間換時間方式,直接預測分支條件,把分支指令填入流水線,如果預測失敗,再回滾清空流水線,重新選擇分支,通過采用有效的預測算法,可以極大提高CPU流水線的執行效率,我們需要合理利用這個特性,減少分支判斷,在代碼中采用編譯指令優化提供分支預測準確性,比如在linux內核中,提分支預測的信息提供給編譯器:?likely(x)? 表示x的值為真的可能性更大;unlikely(x)? ?表示x的值為假的可能性更大;這樣編譯器對代碼進行優化,以減少指令跳轉帶來的性能下降。
緩存系統:各種cache優化,用空間換時間;
BIOS優化
BIOS(基本輸入/輸出系統)是主板上的一個小內存,其數據定義了系統的配置。某些數據被寫入死存儲器(ROM),因此無法更改。另一方面,某些配置可以從BIOS配置中訪問,我們在啟動PC時通過按鍵激活該配置。
超線程優化(Hyper-Threading)
超線程,是一種用于提升CPU計算并行度的處理器技術,用一個物理核模擬兩個邏輯核。這兩個邏輯核擁有自己的中斷、狀態,但是共用物理核的計算資源(寄存器)。超線程技術旨在提高CPU計算資源的使用率,從而提高計算并行度。但是超線程也有副作用,會產生訪問cache的競爭,會導致更多的cache不命中(cache-miss),增加線程間的通信負載。加大內存的通信帶寬,I/O總線的壓力,所以對于一些高性能程序,一般是需要關閉超線程的;
電源模式
如果服務器想獲得最大的吞吐量或最低的延遲,修改電源模式為最大性能,可以提高服務器的性能;
Lockstep模式
鎖步模式對內存進行了更高的校驗,提升了系統的可靠性,但是降低了內存訪問的帶寬和延時,對于實時性要求高,吞吐量大的業務場景不適用,對于這些場景從系統,軟件和方案層面都有完善的保護機制,所以建議關閉;
Turbo Mode
Turbo boost就是Intel的睿頻加速技術,通常所說的自動超頻技術,主要用于提升處理器的頻率,最大程度發揮處理器性能;
批量合并
網絡 IO 和磁盤 IO,合并操作和批量操作往往能提升吞吐量,提高性能。
redis,mysql,kafak等采用批量操作都可以極大提升性能;
預處理
預處理策略就是提前做好一些準備工作,這樣可以提高后續處理性能;
比如網站頁面資源的提前加載,可以顯著地提升頁面下載性能;
比如CPU 預取指令,提前將所需要的數據和指令取出來,可以提高流水線效率和緩存效率;
惰性求值
惰性處理策略就是盡量將操作(比如計算),推遲到必需執行的時刻,這樣很可能避免多余的操作。
Linux COW(Copy On Write,寫時復制)機制,比如fork 調用只有真正用到資源時候才拷貝;
中斷后半部分優化,把可延遲函數放到延后處理,從而提高中斷處理整體效率;
缺頁中斷處理,不需要進程把所有內存頁載入內存,只有需要的時候再加載,這樣可以減少大量無效內存操作,提高整體性能;
架構優化
系統資源優化: 物理機器->集群->虛擬化->云計算->容器->k8s編排器;
應用架構優化:?單體應用->基于組件->面向服務->微服務;
軟件工程優化:?瀑布模型->敏捷開發->DevOps->智能化工程,主要是提高研發效能,建設產品的性能測試CI/CD自動化流水線,每個優化點都可以及時查看到性能指標變化和對比,從小作坊到標準化,工業化,智能化發展;
算法優化
算法復雜度優化:O(1)? < O(lgn)? <? O(n)?<? O(nlgn)? < O(n^2)< O(n^3)<O(2^n)? < O(n!) < O(n^n);
數據結構優化:hash結構 > 樹型結構?> 線性結構;
代碼優化
循環優化:適當展開循環,可以讓指令并行執行,提供搞性能;
條件判斷:減少條件判斷語句,可以減少分支預測失敗概率,提升CPU流水線效率,從而提升性能;
表達式優化:?優化布爾邏輯可以減少不必要計算;使++i而不使用i++可以減少中間臨時變量;
采用位運算:如果沒有越界風險,使用位運算符合計算機計算模型,效率更高;
內存&cache對齊:數據結構最好是cache 對齊的整數倍,把高頻使用的屬性,放到最前面,這樣可以提高cache命中效率,減少Cache miss;
指針優化:盡量減少指針使用,指針跳轉會導致Cache miss;
向量化:合適使用SIMD高級指令可以優化代碼;
插入其他語言:插入匯編,優化高頻函數;采用CPython優化python代碼;
遞歸優化:盡量把遞歸修改為循環,減少遞歸調用代價;
編譯優化
編譯器優化:O0 -->> O1 -->> O2 -->> O3,來額外的性能提升;
編譯器API:使用內聯函數,使用內存對齊API,使用cache對齊API等 ,可以更好讓編譯器優化代碼,減少調用指令,提高性能;
JIt編譯器優化:使用Jit技術,可以把中間代碼生成本地指令,提升代碼執行效率;
?????????????????優化無止境,上面每一個優化點,都可以更詳細展開講,更多是需要我們深入理解計算機原理,才能找到得更多優化點,讓我們向頂級程序員邁進;
—END—
關于linux調度系統系列文章終于完結,讓我們期待下個系列吧。
想要獲取linux調度全景指南精簡版,關注公眾號回復“調度”即可獲取。回復其他消息,獲取更多內容;
? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ??
往期推薦
Linux調度系統全景指南(上篇)
Linux調度系統全景指南(中篇)
Linux調度系統全景指南(下篇)
C++模版的本質
C++內存管理全景指南
云網絡丟包故障定位全景指南
騰訊資深工程師,一起修煉深厚內功
總結
以上是生活随笔為你收集整理的Linux调度系统全景指南(终结篇)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux调度系统全景指南(下篇)
- 下一篇: 经典永不过时!重温设计模式