轉自:http://blog.csdn.net/u010954257/article/details/54178160
最近在做一個大並發服務的測試(目前測到86萬,當然有大量長連接,每天打的日志高到170多g,不打算繼續測了),業務系統為反向代理ATS,服務的內容為動態域名,大部分的url很長,不過打開后的值只是0或1這樣的標記。
當服務器在幾萬並發時,一般不需要考慮TCP連接消耗內存的問題,但當服務器承載幾十萬並發時,會暴漏出各種的問題,因此不得不考慮TCP連接對內存資源的消耗,當然跑到86萬的並發需要對業務系統、Centos做各種參數優化,牽涉面太多,今天只說TCP內存占用(由於線上系統干擾條件很多,無法特定的對某個參數去調試,只分享一下做過程的心得,拋磚引玉),出現的問題如下:
(內存不夠用,kernel直接把ats的進程給殺掉了,然后out of socket memory)
(跑着跑着,直接out of socket memory)
(tsar的內存監控數據)
每一個TCP連接都會有對應的socket封裝,而每個socket都要占用一個fd,現在的業務系統大都采用epoll的網絡I/O模型,他可以高效的處理大批量socket句柄,而這個socket句柄的對應的TCP讀寫緩存再加上一個TCP控制塊就是單個TCP連接所消耗的內存,當然這個讀寫緩存的大小是根據系統的需要動態變化的,和TCP的滑動窗口大小成正相關。
對於tcp能夠使用多少緩存,centos是會有全局控制的,例如我線上的服務器(內存62G,有15個G做內存cache使用)。
TCP能夠使用的內存:這三個值就是TCP使用內存的大小,單位是頁,每個頁是4K的大小,如下:
這三個值分別代表
Low:6179424 (6179424*4/1024/1024大概23g)
Pressure:8239232 (8239232*4/1024/1024大概31g)
High:12358848 (echo 12358848*4/1024/1024大概47g)
這個也是系統裝后的默認取值,也就是說最大有47個g(75%的內存)可以用作TCP連接,這三個量也同時代表了三個閥值,TCP的使用小於第二個值時kernel不會有任何提示操作,當大於第二個值時進入壓力模式,當高於第三個值時將不接受新的TCP連接,同時會報出“Out of socket memory”或者“TCP:too many of orphaned sockets”。
TCP讀緩存大小,單位是字節:第一個是最小值4K,第二個是默認值85K,第三個是最大值16M,如下:
這個可以在sysctl.conf中net.ipv4.tcp_rmem中進行調整。
TCP寫緩存大小,單位是字節:第一個是最小值4K,第二個是默認值64K,第三個是最大值16M,如下:
這個可以在sysctl.conf中net.ipv4.tcp_wmem中進行調整。
也就是說一個TCP在三次握手建立連接后,最小的內存消耗在8K左右,最大的內存消耗在32M左右,你可以通過MTU估算MSS,然后算出一個滑動窗口有多少個MSS。現在可以進行簡單計算了,按照系統TCP的全局控制,有47個g可用作內存緩存,假設按照默認的讀寫緩存計算,一個TCP連接占用149K加1K的tcp控制塊共150K的內存,那么系統能承受最大的並發為 47*1024*1024/150 = 32萬,當然這只是理論,一個TCP連接占用的內存實際是大小混用的,根據傳輸的文件大小以及網絡狀況動態調整。那么當前是什么情況呢,是有很多的長連接,而且每個請求的數據都很小,也就是說很有大量TCP連接只占了10K左右的內存,所以可以嘗試更大的並發。
好了,我順着思路往下想,“Out of socket memory”除了業務系統惡意丟棄請求、或者孤兒套接字太多、或者fd(已經優化的很大了,不存在)用完了,就可能是為新的soket分配內存資源內存不夠用了,因為在之前測試到30萬左右的連接的時候出過這個問題,查看內存基本跑滿,當時是把ats的logbuffer改小(動態連接一個url有時到45K的長度,於是當時把log buffer改的特別大)后就不報了,后來繼續跑到50萬左右又報錯了,內存基本跑滿,后把內存cache從30G調到了15G,再騰出15G給TCP連接及其與資源使用,跑到70萬左右又不行了,大量這個錯誤。因為當前內存使用的很雜,有ats的內存緩存,有大量的孤兒Orphan soket(占用64K左右內存),還有大量的沒有釋放的TCP連接,還有ats的log等線程使用的內存,七七八八算下來,TCP能使用的內存不多,長連接、小鏈接、大鏈接的比例也不好計算,只能按照經驗去嘗試,目前看跑到70萬已經到頭了吧。
可是后來又想,系統對於剛開始建連接的時候可能是默認的內存占用,之后再動態調整,按照當前域名質量情況,大多數都是小的不能再小的請求,我是否可以更改默認TCP的讀寫緩存呢,於是調整,讀寫默認緩存各變為原來的一半分別是43K和32K,第二天晚高峰檢查,跑到86萬,沒有出現問題,好了到此為止,不再測了。
總結:其實系統單純能跑多大並發在乎全局fd和內存,但大並發下還能繼續保持業務正常服務就是技術活兒了,每個業務系統的參數、操作系統的參數都得琢磨嘗試,其余方面的優化小記有空再寫。
本文出自 “奔跑的linux” 博客,請務必保留此出處http://benpaozhe.blog.51cto.com/10239098/1752675







