簡述Linux 中程式與執行緒

大雄45發表於2022-02-19
導讀 程式是一個具有一定獨立功能的程式關於某個資料集合的一次執行活動。它是作業系統動態執行的基本單元,在傳統的作業系統中,程式既是基本的分配單元,也是基本的執行單元。
程式

程式是一個具有一定獨立功能的程式關於某個資料集合的一次執行活動。它是作業系統動態執行的基本單元,在傳統的作業系統中,程式既是基本的分配單元,也是基本的執行單元。程式的概念主要有兩點:第一,程式是一個實體。每一個程式都有它自己的地址空間,一般情況下,包括文字區域(text region)、資料區域(data region)和堆疊(stack region)。文字區域儲存處理器執行的程式碼;資料區域儲存變數和程式執行期間使用的動態分配的記憶體;堆疊區域儲存著活動過程呼叫的指令和本地變數。第二,程式是一個“執行中的程式”。程式是一個沒有生命的實體,只有處理器賦予程式生命時(作業系統執行之),它才能成為一個活動的實體,我們稱其為程式。

執行緒

執行緒是作業系統能夠進行運算排程的最小單位。它被包含在程式之中,是程式中的實際運作單位。一條執行緒指的是程式中一個單一順序的控制流,一個程式中可以併發多個執行緒,每條執行緒並行執行不同的任務。在Unix System V及SunOS中也被稱為輕量程式(lightweight processes),但輕量程式更多指核心執行緒(kernel thread),而把使用者執行緒(user thread)稱為執行緒。程式與執行緒之間的關係 同一程式中的多條執行緒將共享該程式中的全部系統資源,如虛擬地址空間,檔案描述符和訊號處理等等。但同一程式中的多個執行緒有各自的呼叫棧(call stack),自己的暫存器環境(register context),自己的執行緒本地儲存(thread-local storage)。

中執行緒與程式

linux核心中,程式與執行緒它們雖然都是任務,但是應該加以區分。其中,pid 是 process id,tgid 是 thread group ID。任何一個程式,如果只有主執行緒,那 pid 是自己,tgid 是自己,group_leader 指向的還是自己。但是,如果一個程式建立了其他執行緒,那就會有所變化了。執行緒有自己的 pid,tgid 就是程式的主執行緒的 pid,group_leader 指向的就是程式的主執行緒。所以有了 tgid,我們就知道 tast_struct 代表的是一個程式還是代表一個執行緒了。關係如下:

簡述Linux 中程式與執行緒簡述Linux 中程式與執行緒

關於執行緒與程式的核心引數

ulimit 限制,在 Linux 下執行ulimit -a,你會看到 ulimit 對各種資源的限制。

簡述Linux 中程式與執行緒簡述Linux 中程式與執行緒

其中的“max user processes”就是一個程式能建立的最大執行緒數,我們可以修改這個引數:

ulimit -u 66535

2.引數sys.kernel.threads-max限制。這個引數限制作業系統全域性的執行緒數,透過下面的 可以檢視它的值。檢視threads-max的方法:

cat /proc/sys/kernel/threads-max
32768

修改這個值的方法:

#方法一,重啟後會失效
echo 65535 > /proc/sys/kernel/threads-max
#方法二,永久修改
echo "kernel.threads-max = 65535" >> /etc/sysctl.conf

3.引數sys.kernel.pid_max限制。這個引數限制作業系統全域性的執行緒數,透過下面的 可以檢視它的值。這裡說一下32位作業系統這個值最大是32768不能修改,64位系統上pid_max最大值為2^22。Linux 核心在初始化系統的時候,會根據機器 CPU 的數目來設定 pid_max 的值。比如說,如果機器中 CPU 數目小於等於 32,那麼 pid_max 就會被設定為 32768(32K);如果機器中的 CPU 數目大於 32,那麼 pid_max 就被設定為 N*1024 (N 就是 CPU 數目)。檢視pid_max的方法:

cat /proc/sys/kernel/pid_max
32768

修改這個值的方法:

#方法一,重啟後會失效
echo 65535 > /proc/sys/kernel/pid_max
#方法二,永久修改
echo "kernel.pid_max = 65535" >> /etc/sysctl.conf

注意:一個執行緒數也會佔用一個pid,所以threads-max須要小於等於pid_max。

容器執行緒數量的限制

對於 Linux 系統而言,容器就是一組程式的集合。如果容器中的應用建立過多的程式或者出現 bug,就會產生類似 fork bomb 的行為。這樣,不但會使同一個節點上的其他容器無法工作,還會讓宿主機本身也無法工作。所以對於每個容器來說,我們都需要限制它的最大程式數目,而這個功能由 pids Cgroup 這個子系統來完成。之前遇到過這樣一個問題,java應用因為要處理很多定時任務,一個定時任務拉起一個執行緒。但是由於程式碼上的 bug ,沒有及時對執行緒進行回收,然後這個容器不斷產生執行緒,耗盡了宿主機的程式表空間,最終導致整臺linux上的服務報錯“java.lang.OutOfMemoryError: Unable to create native threads”,影響了其它的服務。建立程式出現“Resource temporarily unavailable”的報錯。這種問題除了讓開發人員修復 bug 外,也需要在系統層面對執行緒數量進行限制。

cgroup

cgroup中對pid進行了隔離,透過更改docker/kubelet配置,可以限制pid總數,從而達到限制執行緒總數的目的。

docker,容器啟動時設定 --pids-limit 引數,限制容器級別pid總數

kubelet,開啟SupportPodPidsLimit特性,設定–pod-max-pids引數,限制node每個pod的pid總數

原理如下:在一個容器建立之後,建立容器的服務會在 /sys/fs/cgroup/pids 下建立一個子目錄,就是一個控制組,控制組裡最關鍵的一個檔案就是 pids.max。kubelet或者docker向這個檔案寫入數值,而這個值就是這個容器中允許的最大程式數目。Kubernetes 裡面的每個節點都會執行一個叫做 Kubelet 的服務,負責節點上容器的狀態和生命週期,比如建立和刪除容器。根據 Kubernetes 的官方文件 Process ID Limits And Reservations 內容,可以設定 Kubelet 服務的 –pod-max-pids 配置選項,之後在該節點上建立的容器,最終都會使用 Cgroups pid 控制器限制容器的程式數量。

總結

linux中為了防止程式惡意使用資源,系統使用ulimit來限制程式的資源使用情況(包括檔案描述符,執行緒數,記憶體大小等)。同樣地在容器化場景中,需要限制其系統資源的使用量。pid是計算機重要資源,所以需要在使用時,加以限制,以保證資源的合理利用。dockerd暫無預設的pid limit設定;k8s 限制執行緒數,可透過在kubelet中開啟SupportPodPidsLimit特性,設定pod級別pid limit。

好了,今天的內容就到這裡。我是夏老師,祝你今天知識吃飽,我們下次再見。

原文來自:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2856455/,如需轉載,請註明出處,否則將追究法律責任。

相關文章