看tomcat源碼的一點理解

http連接的表現就是socket對象

客戶端連接服務端時,先隨機分配一個端口去連接服務器的80端口,然後服務器會另外隨機分配一個端口與客戶端通信,該端口由一個socket持有。在程序上的表現就是:當這個socket還存在,就意味着客戶端和服務端還在建立連接;反之,即斷開連接。

通常情況下,連接會被很快的處理完,然後斷開。當客戶端再次需要請求服務器資源數,再重新經歷上面的過程進行連接。這時客戶端和服務端的通信端口還是會重新隨機分配,每次連接可能都不一樣。客戶端在服務端是靠session唯一標識的,和端口沒有關係。

所以,我們常說的服務器能夠有多大的併發量,實際上就是指服務端能夠同時處理多少socket對象。

Tomcat bio和nio的區別

看tomcat源碼的一點理解_第1張圖片

  • bio:只有Acceptor和Worker
  • nio:在Acceptor和Worker之間多了一個隊列,Acceptor接收到請求之後,看Worker有沒有空,有空就直接處理,沒空的話,就先放到隊列裏。

socket對象在服務端的處理過程:

  1. 一開始建立連接,連接信息會存放在ServerSocket連接請求的隊列中(隊列長度爲acceptCount)
  2. 如果現在提交的任務數沒有超過maxConnections,那麼就ServerSocket.accept()返回socket對象,封裝爲任務提交到線程池;現在提交的任務數超過了maxConnections,則阻塞
  3. 任務提交到線程池後,分三種情況
    1. 線程數<=minSpareThreads:不管有沒有空閒線程,每次來任務都新建線程
    2. minSpareThreads<線程數
    3. 線程數==maxThreads:把任務放入任務隊列中排隊
  4. 當任務被處理完後,或隊列已滿則銷燬任務以及任務中的socket對象

Tomcat連接數相關參數

  • minProcessors (minSpareThreads):最小空閒連接線程數,線程數小於此數時,每次來任務都新建線程處理,默認值爲25
  • maxProcessors (maxThreads):最大連接線程數,線程數小於此數時,每次來任務如果沒有空餘線程才新建線程處理,默認值爲200
  • acceptCount:允許的最大併發連接數(瞬時連接),爲ServerSocket連接請求的隊列長度,默認值爲100
  • maxConnections:允許的最大連接數,計數參數,可以提交給線程池的最大任務數,默認值爲10000
  • enableLookups:是否反查域名,取值爲:true或false。爲了提高處理能力,應設置爲false
  • connectionTimeout:網絡連接超時,單位:毫秒。設置爲0表示永不超時,這樣設置有隱患的。通常可設置爲30000毫秒

Tomcat連接數相關參數對應程序

  • minProcessors和maxProcessors:連接線程數,對應HttpProcessor線程池中的線程數
  • acceptCount:允許的最大併發連接數,對應ServerSocket(int port, int backlog)中的backlog(連接請求的隊列長度)
  • maxConnections:允許的最大連接數,線程池有個計數器connectionLimitLatch = new LimitLatch(getMaxConnections());,任務進入線程池時會調用countUpOrAwaitConnection(),任務完成時會調用countDownConnection()。如果線程池中的任務數超過maxConnections時,countUpOrAwaitConnection()就會阻塞,這樣就可以阻止任務繼續提交

maxConnections在不同模式下的默認值

當Tomcat接收的連接數達到maxConnections時,Acceptor線程不會讀取accept隊列中的連接;這時accept隊列中的線程會一直阻塞着,直到Tomcat接收的連接數小於maxConnections。如果設置爲-1,則連接數不受限制。

默認值與連接器使用的協議有關:NIO的默認值是10000,APR/native的默認值是8192,而BIO的默認值爲maxThreads。
在windows下,APR/native的maxConnections值會自動調整爲設置值以下最大的1024的整數倍;如設置爲2000,則最大值實際是1024。

 

Tomcat中線程池解析

1. 線程池

executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);

 

2. 任務隊列

taskqueue = new TaskQueue(maxQueueSize); //maxQueueSize = Integer.MAX_VALUE;

 

3. 部分代碼

    public boolean offer(Runnable o) {
        //we can't do any checks
        if (parent==null) return super.offer(o);
        //we are maxed out on threads, simply queue the object
        //如果線程數==maxThreads,把任務放入任務隊列中排隊
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
        //we have idle threads, just add it to the queue
        //如果有空閒線程,就使用空閒線程
        if (parent.getSubmittedCount()<(parent.getPoolSize())) return super.offer(o);
        //if we have less threads than maximum force creation of a new thread
        //如果沒有空閒線程才新建線程,並且線程數還沒有達到maxThreads就返回false,這會導致#############1
        if (parent.getPoolSize()


思考:由此可見,用異常來控制邏輯,儘管很巧妙,但並不是一個好的設計 (←_←#)

在線用戶數、連接數、瞬時併發數、線程數的區別

在線用戶數=連接數+靜態用戶數(已登錄,但連接已斷開,只是在瀏覽靜態數據)(有session對象,沒有socket對象)
連接數=已接受連接數+瞬時併發數(acceptCount:在連接隊列裏等待的socket對象數) //這個狀態的客戶端顯示爲瀏覽器顯示“轉圈”
已接受連接數=線程數(RUNNABLE狀態)(正在處理)+任務隊列中的任務數(已接受,待處理)

對網絡端口的理解

實際上,電腦在網卡上的硬件網絡端口只有一個。我們所說的1-65535號端口,並不是真的有這麼多個硬件端口,硬件端口實際上只有一個,訪問所有端口的數據包都發往這個硬件端口。硬件端口接收到數據包之後進行解析,然後通知監聽對應端口的socket對象來取數據。

參考

[1] 併發量計算

1.業務併發用戶數;2.最大併發訪問數;3.系統用戶數;4.同時在線用戶數;

假設一個OA系統有1000用戶,這是系統用戶數;最高峯同時有500人在線,是“同時在線人數”,也稱作“最大業務併發用戶數”;500個同時使用系統用戶中20%查看系統公告,不構成壓力;20%填寫表格(只在提交時纔會請求,填寫對服務器不構成壓力);40%在發呆(什麼都沒做);20%用戶不停從一個頁面跳轉另一個頁面(只有這20%對服務器產生了壓力)。

說明服務器實際壓力,能承受的最大併發訪問數,既取決於業務併發用戶數,還取決於用戶的業務場景,這些可以通過對服務器日誌的分析得到。

一般只需要分析出典型業務(用戶常用,最關注的業務操作)
給出一個估算業務併發用戶數的公式(測試人員一般只關心業務併發用戶數)
C=nL/T
C^=C+3×(C的平方根)
C是平均的業務併發用戶數、n是login session的數量、L是login session的平均長度、T是指考察的時間段長度、C^是指業務併發用戶數的峯值。

該公式的得出是假設用戶的login session產生符合泊松分佈而估算得到。
假設OA系統有1000用戶,每天400個用戶發訪問,每個登錄到退出平均時間2小時,在1天時間內用戶只在8小時內使用該系統。
C=400×2/8=100
C^=100+3×(100的平方根)=100+3×10=130
另外,如果知道平均每個用戶發出的請求數u,則系統吞吐量可以估算爲u×C

請注意:精確估算,還要考慮用戶業務操作存在一定的時間集中性(比如上班後1小時內是OA系統高峯期),採用公式計算仍然會存在偏差。針對例子OA系統可以把1小時設定爲考察時間的粒度,將一天8小時劃分爲8個區間,這樣可以解決業務操作存在集中性問題,更趨於精準,偏差更小。

[2] 系統吞度量要素

系統吞吐量幾個重要參數:QPS(TPS)、併發數、響應時間

QPS(TPS):每秒鐘request/事務 數量

併發數: 系統同時處理的request/事務數

響應時間: 一般取平均響應時間

(很多人經常會把併發數和TPS理解混淆)

理解了上面三個要素的意義之後,就能推算出它們之間的關係:

QPS(TPS)= 併發數/平均響應時間

一個系統吞吐量通常由QPS(TPS)、併發數兩個因素決定,每套系統這兩個值都有一個相對極限值,在應用場景訪問壓力下,只要某一項達到系統最高值,系統的吞吐量就上不去了,如果壓力繼續增大,系統的吞吐量反而會下降,原因是系統超負荷工作,上下文切換、內存等等其它消耗導致系統性能下降。 決定系統響應時間要素

我們做項目要排計劃,可以多人同時併發做多項任務,也可以一個人或者多個人串行工作,始終會有一條關鍵路徑,這條路徑就是項目的工期。

系統一次調用的響應時間跟項目計劃一樣,也有一條關鍵路徑,這個關鍵路徑是就是系統影響時間;

關鍵路徑是有CPU運算、IO、外部系統響應等等組成。

[3] tomcat高併發配置與優化

 

 

tomcat的acceptCount與maxConnections

https://segmentfault.com/a/1190000008064162

 

SYN攻擊

在三次握手過程中,Server發送SYN-ACK之後,收到Client的ACK之前的TCP連接稱爲半連接(half-open connect),此時Server處於SYN_RCVD狀態,當收到ACK後,Server轉入ESTABLISHED狀態。SYN攻擊就是 Client在短時間內僞造大量不存在的IP地址,並向Server不斷地發送SYN包,Server回覆確認包,並等待Client的確認,由於源地址 是不存在的,因此,Server需要不斷重發直至超時,這些僞造的SYN包將產時間佔用未連接隊列,導致正常的SYN請求因爲隊列滿而被丟棄,從而引起網絡堵塞甚至系統癱瘓。SYN攻擊時一種典型的DDOS攻擊,檢測SYN攻擊的方式非常簡單,即當Server上有大量半連接狀態且源IP地址是隨機的,則可以斷定遭到SYN攻擊了,使用如下命令可以讓之現行:

netstat -nap | grep SYN_RECV

 

maxConnections表示有多少個socket連接到tomcat上。NIO模式下默認是10000。而maxThreads則是woker線程併發處理請求的最大數。也就是雖然client的socket連接上了,但是可能都在tomcat的task queue裏頭,等待worker線程處理返回響應。

 

tomcat server在tcp的accept隊列的大小設置的基礎上,對請求連接多做了一層保護,也就是maxConnections的大小限制。

當client端的大量請求過來時,首先是OS層的tcp的accept隊列幫忙擋住,accept隊列滿了的話,後續的連接無法進入accept隊列,無法交由工作線程處理,client將得到read timeout或者connection reset的錯誤。

第二層保護就是,在acceptor線程裏頭進行緩衝,當連接的socket超過maxConnections的時候,則進行阻塞等待,控制acceptor轉給worker線程連接的速度,稍微緩緩,等待worker線程處理響應client。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章