最大程序執行緒數 連線數
========================
=========================================================
===========================================================================
開發的原因,需要對吞吐量(TPS)、QPS、併發數、響應時間(RT)幾個概念做下了解,查自百度百科,記錄如下: 1. 響應時間(RT) 響應時間是指系統對請求作出響應的時間。直觀上看,這個指標與人對軟體效能的主觀感受是非常一致的,因為它完整地記錄了整個計算機系統處理請求的時間。由於一個系統通常會提供許多功能,而不同功能的處理邏輯也千差萬別,因而不同功能的響應時間也不盡相同,甚至同一功能在不同輸入資料的情況下響應時間也不相同。所以,在討論一個系統的響應時間時,人們通常是指該系統所有功能的平均時間或者所有功能的最大響應時間。當然,往往也需要對每個或每組功能討論其平均響應時間和最大響應時間。 對於單機的沒有併發操作的應用系統而言,人們普遍認為響應時間是一個合理且準確的效能指標。需要指出的是,響應時間的絕對值並不能直接反映軟體的效能的高低,軟體效能的高低實際上取決於使用者對該響應時間的接受程度。對於一個遊戲軟體來說,響應時間小於100毫秒應該是不錯的,響應時間在1秒左右可能屬於勉強可以接受,如果響應時間達到3秒就完全難以接受了。而對於編譯系統來說,完整編譯一個較大規模軟體的原始碼可能需要幾十分鐘甚至更長時間,但這些響應時間對於使用者來說都是可以接受的。 2. 吞吐量(Throughput) 吞吐量是指系統在單位時間內處理請求的數量。對於無併發的應用系統而言,吞吐量與響應時間成嚴格的反比關係,實際上此時吞吐量就是響應時間的倒數。前面已經說過,對於單使用者的系統,響應時間(或者系統響應時間和應用延遲時間)可以很好地度量系統的效能,但對於併發系統,通常需要用吞吐量作為效能指標。 對於一個多使用者的系統,如果只有一個使用者使用時系統的平均響應時間是t,當有你n個使用者使用時,每個使用者看到的響應時間通常並不是n×t,而往往比n×t小很多(當然,在某些特殊情況下也可能比n×t大,甚至大很多)。這是因為處理每個請求需要用到很多資源,由於每個請求的處理過程中有許多不走難以併發執行,這導致在具體的一個時間點,所佔資源往往並不多。也就是說在處理單個請求時,在每個時間點都可能有許多資源被閒置,當處理多個請求時,如果資源配置合理,每個使用者看到的平均響應時間並不隨使用者數的增加而線性增加。實際上,不同系統的平均響應時間隨使用者數增加而增長的速度也不大相同,這也是採用吞吐量來度量併發系統的效能的主要原因。一般而言,吞吐量是一個比較通用的指標,兩個具有不同使用者數和使用者使用模式的系統,如果其最大吞吐量基本一致,則可以判斷兩個系統的處理能力基本一致。 3. 併發使用者數 併發使用者數是指系統可以同時承載的正常使用系統功能的使用者的數量。與吞吐量相比,併發使用者數是一個更直觀但也更籠統的效能指標。實際上,併發使用者數是一個非常不準確的指標,因為使用者不同的使用模式會導致不同使用者在單位時間發出不同數量的請求。一網站系統為例,假設使用者只有註冊後才能使用,但註冊使用者並不是每時每刻都在使用該網站,因此具體一個時刻只有部分註冊使用者同時線上,線上使用者就在瀏覽網站時會花很多時間閱讀網站上的資訊,因而具體一個時刻只有部分線上使用者同時向系統發出請求。這樣,對於網站系統我們會有三個關於使用者數的統計數字:註冊使用者數、線上使用者數和同時發請求使用者數。由於註冊使用者可能長時間不登陸網站,使用註冊使用者數作為效能指標會造成很大的誤差。而線上使用者數和同事發請求使用者數都可以作為效能指標。相比而言,以線上使用者作為效能指標更直觀些,而以同時發請求使用者數作為效能指標更準確些。 4. QPS每秒查詢率(Query Per Second) 每秒查詢率QPS是對一個特定的查詢伺服器在規定時間內所處理流量多少的衡量標準,在因特網上,作為域名系統伺服器的機器的效能經常用每秒查詢率來衡量。對應fetches/sec,即每秒的響應請求數,也即是最大吞吐能力。 (看來是類似於TPS,只是應用於特定場景的吞吐量
=========================================
===========================================================
=============================================================================
tomcat的maxThreads、acceptCount(最大執行緒數、最大排隊數)
2015.08.14 15:58* 字數 1403 閱讀 3672評論 0喜歡 4
最佳執行緒數:
效能壓測的情況下,起初隨著使用者數的增加,QPS會上升,當到了一定的閥值之後,使用者數量增加QPS並不會增加,或者增加不明顯,同時請求的響應時間卻大幅增加。這個閥值我們認為是最佳執行緒數。
為什麼要找最佳執行緒數
1.過多的執行緒只會造成,更多的記憶體開銷,更多的CPU開銷,但是對提升QPS確毫無幫助
2.找到最佳執行緒數後通過簡單的設定,可以讓web系統更加穩定,得到最高,最穩定的QPS輸出
最佳執行緒數的獲取:
1、通過使用者慢慢遞增來進行效能壓測,觀察QPS,響應時間
2、根據公式計算:伺服器端最佳執行緒數量=((執行緒等待時間+執行緒cpu時間)/執行緒cpu時間) * cpu數量
3、單使用者壓測,檢視CPU的消耗,然後直接乘以百分比,再進行壓測,一般這個值的附近應該就是最佳執行緒數量。
影響最佳執行緒數的主要因素:
1、IO
2、CPU
根據公式:伺服器端最佳執行緒數量=((執行緒等待時間+執行緒cpu時間)/執行緒cpu時間) * cpu數量
一般來說是IO和CPU。IO開銷較多的應用其CPU執行緒等待時間會比較長,所以執行緒數量可以開的多一些,相反則執行緒數量要少一些,其實有兩種極端,純IO的應用,比如proxy,則執行緒數量可以開到非常大(實在太大了則需要考慮執行緒切換的開銷),這種應用基本上後端(比如這個proxy是代理搜尋的)的QPS能有多少,proxy就有多少。
另一種是耗CPU的計算,這種情況一般來講只能開到CPU個數的執行緒數量。但是並不是說這種應用的QPS就不高,往往這種應用的QPS可以很高。
QPS和執行緒數的關係
1、在最佳執行緒數量之前,QPS和執行緒是互相遞增的關係,執行緒數量到了最佳執行緒之後,QPS持平,不在上升,甚至略有下降,同時相應時間持續上升。
2、同一個系統而言,支援的執行緒數越多(最佳執行緒數越多而不是配置的執行緒數越多),QPS越高
QPS和響應時間的關係
1、對於一般的web系統,響應時間一般有CPU執行時間+IO等待時間組成
2、CPU的執行時間減少,對QPS有實質的提升,IO時間的減少,對QPS提升不明顯。如果要想明顯提升QPS,優化系統的時候要著重優化CPU消耗大戶。
最佳執行緒數和jvm堆記憶體得關係:
以上都是依據效能瓶頸在CPU的情況,對於java應用還有一個因素是FULL GC,我們要保證在最佳執行緒數量下,不會發生頻繁FULL GC
根據公式::(小GC時間間隔/rt)*(併發執行緒數量 * thm) <=young 計算得到的併發執行緒數量如果<最佳執行緒數量 則可能導致FULL GC較頻繁,實際情況看來這種情況在web系統上非常少。不過可以模擬出來。
所以我們在設定jboss執行緒的時候,可以利用記憶體公式計算出來的執行緒數量來設定,通過壓測和計算得到最佳執行緒數,然後設定執行緒數。
設定執行緒數量:
壓測最佳執行緒數<真實設定的執行緒數量<記憶體極限執行緒數
比如,通過壓測得到某系統的最佳執行緒數量是10,然後通過記憶體計算的執行緒數量是20,則,設定jboss的執行緒數量為15是可行的,如果直接設定了10,由於系統本身會受到一些依賴系統的變化而產生一些變化,比如系統依賴一些IO的響應時間會突然延長,由於執行緒數量還是10,其實這個時候最佳執行緒數量已經變成了13了,由於我們設定死了10,其結果就是導致qps下降,但是如果超過20,則又會引起FULL gc非常頻繁,反過來影響QPS的下降。
jboss的執行緒數設定:
對於jboss而言,設定執行緒數量要看使用了那種執行緒連線,如http、ajp等
http和ajp的設定是完全一樣的,非常簡單:
以ajp為例,找到server.xml或者tomcat-server.xml:
預設執行緒數量是200個
maxThreads="200"minSpareThreads="40" maxSpareThreads="75" maxPostSize="512000" acceptCount="300" bufferSize="16384" emptySessionPath="false" enableLookups="false" redirectPort="8443" useBodyEncodingForURI="true"/>
這裡將預設的執行緒數量改成了20,當然相應的其他最小空閒執行緒數和最大空閒執行緒數也做一下調整:
maxThreads="20"minSpareThreads="20" maxSpareThreads="20" maxPostSize="512000" acceptCount="300" bufferSize="16384" emptySessionPath="false" enableLookups="false" redirectPort="8443" useBodyEncodingForURI="true"/>
============================================
=============================================================
==========================================================================
JVM最大建立執行緒數量由JVM堆記憶體大小、執行緒的Stack記憶體大小、系統最大可建立執行緒數(Java執行緒的實現是基於底層系統的執行緒機制來實現的,Windows下_beginthreadex,Linux下pthread_create)三個方面影響。具體如下:
-Xms 最小堆記憶體-Xmx 最大堆記憶體-Xss 設定每個執行緒的堆疊大小。JDK5.0以後每個執行緒堆疊大小為1M作業系統限制 系統最大可開執行緒數,主要受以下幾個引數影響
/proc/sys/kernel/pid_max
/proc/sys/kernel/thread-max
max_user_process(ulimit -u) 在64位Linux系統(CentOS 6, 3G記憶體)下測試,發現還有一個引數是會限制執行緒數量:max user process(可通過ulimit –a檢視,預設值1024,通過ulimit –u可以修改此值),這個值在上面的32位Ubuntu測試環境下並無限制
/proc/sys/vm/max_map_count
將threads-max,pid_max,max user process,這三個引數值都修改成100000,-Xms,-Xmx儘量小(128m,64m),-Xss儘量小(64位下最小104k,可取值128k)。事先預測在這樣的測試環境下,執行緒數量就只會受限於測試環境的記憶體大小(3G),可是實際的測試結果是執行緒數量在達到32K(32768,建立的數量最多的時候大概是33000左右)左右時JVM是丟擲警告:Attempt to allocate stack guard pages failed,然後出現OutOfMemoryError無法建立本地執行緒。檢視記憶體後發現還有很多空閒,所以應該不是記憶體容量的原因。/proc/sys/vm/max_map_count的數量翻倍,從65536變為131072,建立的執行緒總數量達到65000+,電腦基本要卡死(3G記憶體)…
簡單查了下這個引數的作用,在[8]中的描述如下:
“This file contains the maximum number of memory map areas a process may have. Memory map areas are used as a side-effect of calling malloc, directly by mmap and mprotect, and also when loading shared libraries.
While most applications need less than a thousand maps, certain programs, particularly malloc debuggers, may consume lots of them, e.g., up to one or two maps per allocation.
The default value is 65536.”
作業系統最大執行緒數限制
32位Linux系統可建立的最大pid數是32678,這個數值可以通過/proc/sys/kernel/pid_max來做修改(修改其值為10000:echo 10000 > /proc/sys/kernel/pid_max),但是在32系統下這個值只能改小,無法改大。
Windows可建立的執行緒數量比linux可能更少。
在64位Linux系統(CentOS 6)下,還有一個引數會限制執行緒數量:max user process(可通過ulimit –a檢視,預設值1024,通過ulimit –u可以修改此值)
測試程式如下:
- import java.util.concurrent.atomic.AtomicInteger;
- public class TestThread extends Thread {
- private static final AtomicInteger count = new AtomicInteger();
- public static void main(String[] args) {
- while (true)
- (new TestThread()).start();
- }
- @Override
- public void run() {
- System.out.println(count.incrementAndGet());
- while (true)
- try {
- Thread.sleep(Integer.MAX_VALUE);
- } catch (InterruptedException e) {
- break;
- }
- }
- }
測試環境:
系統:Ubuntu 10.04 Linux Kernel 2.6 (32位)
記憶體:2G
JDK:1.7
測試結果:
◆ 不考慮系統限制
-Xms |
-Xmx |
-Xss |
結果 |
1024m |
1024m |
1024k |
1737 |
1024m |
1024m |
64k |
26077 |
512m |
512m |
64k |
31842 |
256m |
256m |
64k |
31842 |
在建立的執行緒數量達到31842個時,系統中無法建立任何執行緒。
由上面的測試結果可以看出增大堆記憶體(-Xms,-Xmx)會減少可建立的執行緒數量,增大執行緒棧記憶體(-Xss,32位系統中此引數值最小為60K)也會減少可建立的執行緒數量。
◆ 結合系統限制
執行緒數量31842的限制是是由系統可以生成的最大執行緒數量決定的:/proc/sys/kernel/threads-max,可其預設值是32080。修改其值為10000:echo 10000 > /proc/sys/kernel/threads-max,修改後的測試結果如下:
-Xms |
-Xmx |
-Xss |
結果 |
256m |
256m |
64k |
9761 |
這樣的話,是不是意味著可以配置儘量多的執行緒?再做修改:echo 1000000 > /proc/sys/kernel/threads-max,修改後的測試結果如下:
-Xms |
-Xmx |
-Xss |
結果 |
256m |
256m |
64k |
32279 |
128m |
128m |
64k |
32279 |
發現執行緒數量在達到32279以後,不再增長。查了一下,32位Linux系統可建立的最大pid數是32678,這個數值可以通過/proc/sys/kernel/pid_max來做修改(修改方法同threads-max),但是在32系統下這個值只能改小,無法更大。在threads-max一定的情況下,修改pid_max對應的測試結果如下:
pid_max |
-Xms |
-Xmx |
-Xss |
結果 |
1000 |
128m |
128m |
64k |
582 |
10000 |
128m |
128m |
64k |
9507 |
在Windows上的情況應該類似,不過相比Linux,Windows上可建立的執行緒數量可能更少。基於執行緒模型的伺服器總要受限於這個執行緒數量的限制。
總結:
JVM中可以生成的最大數量由JVM的堆記憶體大小、Thread的Stack記憶體大小、系統最大可建立的執行緒數量(Java執行緒的實現是基於底層系統的執行緒機制來實現的,Windows下_beginthreadex,Linux下pthread_create)三個方面影響。具體數量可以根據Java程序可以訪問的最大記憶體(32位系統上一般2G)、堆記憶體、Thread的Stack記憶體來估算。
一、模擬問題:
首先我們通過下面這個測試程式 來認識這個問題: 執行的環境 (有必要說明一下,不同環境會有不同的結果):32位 Windows XP,Sun JDK 1.6.0_18, eclipse 3.4, 測試程式:
Java程式碼
- import java.util.concurrent.CountDownLatch;
- public class TestNativeOutOfMemoryError {
- public static void main(String[] args) {
- for (int i = 0;; i++) {
- System.out.println("i = " + i);
- new Thread(new HoldThread()).start();
- }
- }
- }
- class HoldThread extends Thread {
- CountDownLatch cdl = new CountDownLatch(1);
- public HoldThread() {
- this.setDaemon(true);
- }
- public void run() {
- try {
- cdl.await();
- } catch (InterruptedException e) {
- }
- }
- }
不指定任何JVM引數,eclipse中直接執行輸出,看到了這位朋友了吧: i = 5602 Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:597) at TestNativeOutOfMemoryError.main(TestNativeOutOfMemoryError.java:20)
二、分析問題:
這個異常問題本質原因是我們建立了太多的執行緒,而能建立的執行緒數是有限制的,導致了異常的發生。能建立的執行緒數的具體計算公式如下: (MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads MaxProcessMemory 指的是一個程序的最大記憶體 JVMMemory JVM記憶體 ReservedOsMemory 保留的作業系統記憶體 ThreadStackSize 執行緒棧的大小 在java語言裡, 當你建立一個執行緒的時候,虛擬機器會在JVM記憶體建立一個Thread物件同時建立一個作業系統執行緒,而這個系統執行緒的記憶體用的不是JVMMemory,而是系統中剩下的記憶體(MaxProcessMemory - JVMMemory - ReservedOsMemory)。 結合上面例子我們來對公式說明一下: MaxProcessMemory 在32位的 windows下是 2G JVMMemory eclipse預設啟動的程式記憶體是64M ReservedOsMemory 一般是130M左右 ThreadStackSize 32位 JDK 1.6預設的stacksize 325K左右 公式如下: (2*1024*1024-64*1024-130*1024)/325 = 5841 公式計算所得5841,和實踐5602基本一致(有偏差是因為ReservedOsMemory不能很精確) 由公式得出結論:你給JVM記憶體越多,那麼你能建立的執行緒越少,越容易發生java.lang.OutOfMemoryError: unable to create new native thread。 咦,有點揹我們的常理,恩,讓我們來驗證一下,依舊使用上面的測試程式,加上下面的JVM引數,測試結果如下: ThreadStackSize JVMMemory 能建立的執行緒數 預設的325K -Xms1024m -Xmx1024m i = 2655 預設的325K -Xms1224m -Xmx1224m i = 2072 預設的325K -Xms1324m -Xmx1324m i = 1753 預設的325K -Xms1424m -Xmx1424m i = 1435 -Xss1024k -Xms1424m -Xmx1424m i = 452 完全和公式一致。 三、解決問題: 1, 如果程式中有bug,導致建立大量不需要的執行緒或者執行緒沒有及時回收,那麼必須解決這個bug,修改引數是不能解決問題的。 2, 如果程式確實需要大量的執行緒,現有的設定不能達到要求,那麼可以通過修改MaxProcessMemory,JVMMemory,ThreadStackSize這三個因素,來增加能建立的執行緒數: a, MaxProcessMemory 使用64位作業系統 b, JVMMemory 減少JVMMemory的分配 c, ThreadStackSize 減小單個執行緒的棧大小
參考資料:
1. http://blog.krecan.net/2010/04/07/how-many-threads-a-jvm-can-handle/
2. http://www.cyberciti.biz/tips/maximum-number-of-processes-linux-26-kernel-can-handle.html
3. http://geekomatic.ch/2010/11/24/1290630420000.html
4. http://stackoverflow.com/questions/763579/how-many-threads-can-a-java-vm-support
5. http://www.iteye.com/topic/1035818
6. http://hi.baidu.com/hexiong/blog/item/16dc9e518fb10c2542a75b3c.html
7. https://listman.redhat.com/archives/phil-list/2003-August/msg00025.html
8. http://www.linuxinsight.com/proc_sys_vm_max_map_count.html
http://jzhihui.iteye.com/blog/1271122
http://sesame.iteye.com/blog/622670
小小菜鳥一枚
======================================
==================================================
=================================================================
=============================================================================
關於linux系統最大程序數和單程序最大執行緒數的測試
2017年03月02日 22:08:17 逐鹿之城 閱讀數:8014 標籤: 程序數執行緒數 更多
我的系統:RedHat企業7 64位 記憶體6G
ulimit -a檢視用於shell啟動程序所佔用的資源預設設定
一.最大程序數
1.使用命令ulimit -u
檢視軟限制,我的為7807
/etc/security/limits.conf檢視硬限制,核心引數kernel.pid_max也做了限制
2.系統用pid_t表示程序號,那麼最大的程序數當然也不能超過pid_t的型別
檢視最大程序數
cat /proc/sys/kernel/pid_max#查系統支援的最大程序數,一般會很大,相當於理論值
- 1
3.建立一個新程序會消耗系統資源(主要是記憶體),經測試,在建立6000多個程序時,程式執行的很緩慢,通過vmstat
命令看到,swap記憶體置入置出頻繁,可以判斷是由於記憶體不足,使用虛擬記憶體,所建立過多程序時,系統記憶體必須要加以衡量。
程式碼驗證:
#include<iostream>
#include<unistd.h>
#include<stdio.h>
using namespace std;
int main()
{
pid_t pid;
int i=0;
while(1)
{
pid = fork();
if(pid == 0)
break;
else if(pid == -1)
{
perror("create error");
break;
}
cout<<i++<<" process"<<endl;
}
}
可以即使是系統的預設配置檔案,對最大程序數還是有所限制的,我的機器最多建立了32012個程序。這也就是為什麼用ps aux命令監控系統資源時,程序的pid達到了近30000.
二.最大執行緒數
在/usr/include/bits/local_lim.h
下#define PTHREAD_THREADS_MAX 1024
,可見最大執行緒數限制為1024,而NPTL( Native POSIX Thread Library)中則沒有硬性的限制,僅受限於系統資源(主要是執行緒的stack所佔用的記憶體,可用命令ulimits -s
檢視,一般是8192KB(8M))。
cat /proc/sys/kernel/threads-max #查系統支援的最大執行緒數,一般會很大,相當於理論值
程式碼試驗:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void* foo(void*)
{}
int main()
{
pthread_t thread;
int i = 0;
while(1)
{
if(pthread_create(&thread, NULL, foo, NULL) != 0)
return -1;
printf("%d\n", i);
i++;
}
return 0;
}
最終結果為32747個,遠遠小於理論值90829 Linux上,最大執行緒數目是: number of threads = total virtual memory / (stack size*1024*1024),由於我機子的virtual memory為unlimited,,當然。在32位系統上,程序空間是4G,其中0-3G是使用者空間(0x0-0xBFFFFFFF), 3G-4G是核心空間。 因此理論上講,使用者空間大小/棧大小=最大執行緒數。3072M/8M=384,考慮到系統的佔用,主執行緒(管理執行緒)等,應該是在380左右. 也許在你的系統上是382. 我們可以減小棧限制或者增大虛擬記憶體使得執行緒的數目增加。
檢查虛擬記憶體: ulimit -v
檢查棧大小: ulimit -s
設定虛擬記憶體: ulimit -v 新值
設定棧大小: ulimit -s 新值
或者pthread_create用pthread_attr_getstacksize設定一個較小的棧大小
總結系統限制有: /proc/sys/kernel/pid_max #查系統支援的最大執行緒數,一般會很大,相當於理論值 /proc/sys/kernel/thread-max max_user_process(ulimit -u) #系統限制某使用者下最多可以執行多少程序或執行緒 /proc/sys/vm/max_map_count硬體記憶體大小(我的為65530)
補充
1.查詢當前某程式的執行緒或程序數 pstree -p
ps -e | grep java | awk '{print $1}'
| wc -l 上面用的是命令替換,關於命令替換,就是說用“括起來的命令會優先執行,然後以其輸出作為其他命令的引數 或 pstree -p 程序號 | wc -l top -H 程序號 | wc -l 上面用的是管道,關於管道:管道符號”|”左邊命令的輸出作為右邊命令的輸入 2.查詢當前整個系統已用的執行緒或程序數 pstree -p | wc -