作為一個師父離職早的野生程序員,業務方面還可以達到忽悠別人的水平,但上升到性能層面那就是硬傷。
真是天上掉餡餅,公司分配了一個測試性能的任務,真是感覺我的天空星星都亮了。
高並發主要限制因素:CPU、網絡流量、內存、系統配置
CPU
用top看cpu利用率,按1查看每個cpu線程的工作情況;這里面會顯示出cpu的空閑、利用率、軟中斷等狀態
如果某個cpu線程使用率經常達到100%,那cpu就成了瓶頸,通常為了實現高並發,負載比較大的服務程序會自己綁定cpu,使自己的任務分配到多個cpu線程中去,以保證程序穩定運行
綁定CPU的方法:
nCPUIndex 表示 CPU 序號,從 0 開始編號。
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(nCPUIndex, &mask);
sched_setaffinity(m_hThread, sizeof(mask), &mask);
網卡流量
對於流媒體服務器來說,網卡絕對是主要瓶頸,即使是萬兆網卡,面對1Mbps的碼流,並發也只有1萬;
網卡流量主要通過dstat -N來指定多網卡進行監控,在單機測試過程中,就需要CCIE的支持了:
(1)首先用bond(mod4)綁定多個網卡,但是相應的萬兆交換機也需要與服務器這邊一致。
這邊有個知識點就是“多網卡綁定的七種模式”,好的交換機支持更多的網口負載方式,會讓各網口流量基本均衡。
如果配置差錯,在dstat統計的過程中就會發現,有些網卡流量滿了,但是有些卻沒有流量,導致測試實例大量掉線;
dstat功能很全,cpu、內存都可以指定,比如read列流量高,就表明程序讀寫磁盤的操作比較頻繁。
(2)另外,網卡cpu中斷也最好要進行確認:
查看當前網卡的終端號:cat /proc/interrupts | grep eth1
查看當前網卡分配的CPU(98是第一步的結果):cat /proc/irq/98/smp_affinity_list
將比較空閑的CPU分配給該網卡:echo 1,2,3 >/proc/irq/98/smp_affinity_list
(3)為了省事,可以使用:yum install irqbalance 分配硬件中斷效果也不錯。
內存
可以用top、free -m等查看,反正耗得太多就是程序的問題了。free的各個值也可以看出程序的運行原理。
[root@cdn02 ~]# free -m
total used free shared buffers cached
Mem: 31993 1596 30397 0 12 22
-/+ buffers/cache: 1562 30431
Swap: 15999 7 15992
otal——總物理內存
used——已使用內存,一般情況這個值會比較大,因為這個值包括了cache+應用程序使用的內存
free——完全未被使用的內存
shared——應用程序共享內存
buffers——緩存,主要用於目錄方面,inode值等(ls大目錄可看到這個值增加)
cached——緩存,用於已打開的文件
note:
total=used+free
used=buffers+cached (maybe add shared also)
第二行描述應用程序的內存使用:
前個值表示-buffers/cache——應用程序使用的內存大小,used減去緩存值
后個值表示+buffers/cache——所有可供應用程序使用的內存大小,free加上緩存值
note:
-buffers/cache=used-buffers-cached
+buffers/cache=free+buffers+cached
第三行表示swap的使用:
used——已使用
free——未使用
系統參數
之前都是玩虛擬機,
文件描述符限制神馬的一般配置成65535也就沒發現什么問題,
也不會認為處於TIME_WAIT狀態的socket有什么不好
但是這些對於高並發的服務器來說卻是一個不小的 問題
頻繁的http服務會建立大量的短連接,就會有大量的TIME_WAIT在2ML的超時時間內,占用描述符,導致可用的描述符數減少。
如果恰巧配置的系統最大描述符數又很小,性能當然也就上不去。
系統配置主要是修改:/etc/sysctl.conf 文件,修改之后sysctl -p進行更新
net.ipv4.tcp_max_tw_buckets = 6000
timewait 的數量,默認是180000。
net.ipv4.ip_local_port_range = 1024 65000
允許系統打開的端口范圍。
net.ipv4.tcp_tw_recycle = 1
啟用timewait 快速回收。
net.ipv4.tcp_tw_reuse = 1
開啟重用。允許將TIME-WAIT sockets 重新用於新的TCP 連接。
net.ipv4.tcp_syncookies = 1
開啟SYN Cookies,當出現SYN 等待隊列溢出時,啟用cookies 來處理。
net.core.somaxconn = 262144
web 應用中listen 函數的backlog 默認會給我們內核參數的net.core.somaxconn 限制到128,而nginx 定義的NGX_LISTEN_BACKLOG 默認為511,所以有必要調整這個值。
net.core.netdev_max_backlog = 262144
每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目。
net.ipv4.tcp_max_orphans = 262144
系統中最多有多少個TCP 套接字不被關聯到任何一個用戶文件句柄上。如果超過這個數字,孤兒連接將即刻被復位並打印出警告信息。這個限制僅僅是為了防止簡單的DoS 攻擊,不能過分依靠它或者人為地減小這個值,更應該增加這個值(如果增加了內存之后)。
net.ipv4.tcp_max_syn_backlog = 262144
記錄的那些尚未收到客戶端確認信息的連接請求的最大值。對於有128M 內存的系統而言,缺省值是1024,小內存的系統則是128。
net.ipv4.tcp_timestamps = 0
時間戳可以避免序列號的卷繞。一個1Gbps 的鏈路肯定會遇到以前用過的序列號。時間戳能夠讓內核接受這種“異常”的數據包。這里需要將其關掉。
net.ipv4.tcp_synack_retries = 1
為了打開對端的連接,內核需要發送一個SYN 並附帶一個回應前面一個SYN 的ACK。也就是所謂三次握手中的第二次握手。這個設置決定了內核放棄連接之前發送SYN+ACK 包的數量。
net.ipv4.tcp_syn_retries = 1
在內核放棄建立連接之前發送SYN 包的數量。
net.ipv4.tcp_fin_timeout = 1
如果套接字由本端要求關閉,這個參數決定了它保持在FIN-WAIT-2 狀態的時間。對端可以出錯並永遠不關閉連接,甚至意外當機。缺省值是60 秒。2.2 內核的通常值是180 秒,3你可以按這個設置,但要記住的是,即使你的機器是一個輕載的WEB 服務器,也有因為大量的死套接字而內存溢出的風險,FIN- WAIT-2 的危險性比FIN-WAIT-1 要小,因為它最多只能吃掉1.5K 內存,但是它們的生存期長些。
net.ipv4.tcp_keepalive_time = 30
當keepalive 起用的時候,TCP 發送keepalive 消息的頻度。缺省是2 小時。
應用程序本身的配置
比如nginx,最好根據cpu的線程數去配置worker;要開啟epoll模式,要開啟sendfile等等就不說了。