【性能調優】模擬websocket百萬終端長連接

IM需要在其中一個分區進行線上全鏈路壓測,模擬100w終端用戶連接,並根據線上各websocket和http請求按照比例qps x2併發請求。通宵達旦趕項目1周,但是很多問題仍未找到答案,不過先記錄mark一下過程的問題

測試鏈路

jmeter - SLB(2) - nginx(4) - ingress(5) - pod - im服務

測試場景

  • 模擬100w終端保持心跳並接收消息
  • 模擬ws和http羣聊(發送羣聊,廣播消息到該羣組中所有用戶)
  • 模擬其他非廣播ws和http請求

單肉雞模擬終端連接數

在一臺8核 16g的肉雞中,可以模擬多大的終端數?

  1. 模擬2w連接時,連接數無法上升到2w,僅能連接成功6k左右,jmeter返回大量的 end of stream
    ![!](https://img-blog.csdnimg.cn/20200314042221303.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xsdW96aDIwMTU=,size_16,color_FFFFFF,t_70)

  2. 調整肉雞的配置信息

net.ipv4.tcp_max_tw_buckets = 200000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 11000   61000
fs.file-max = 1000000
net.ipv4.ip_conntrack_max = 2000000
net.ipv4.netfilter.ip_conntrack_max = 2000000
net.nf_conntrack_max = 2000000
net.netfilter.nf_conntrack_max = 2000000
net.ipv4.tcp_max_orphans = 500000
net.ipv4.tcp_mem = 786432 2097152 3145728
net.ipv4.tcp_rmem = 4096 4096 16777216
net.ipv4.tcp_wmem = 4096 4096 16777216

此時連接數可以上到1w

  1. 保持1w的終端連接,可以長時間的正常連接並保持心跳,但在接收羣聊廣播的消息時,仍出現end of stream 和16g內存跑滿等問題

  2. 同時在模擬發送請求時,出現jmeter 出現WebSocket I/O error: Read timed out 的報錯信息,將源碼打印日誌並build打包時,又出現了另外一個local class incompatible 的錯誤
    在這裏插入圖片描述
    增加serialVersionUID的強制定義 private static final long serialVersionUID = -4014547742856395088L; ,發現仍然報此錯誤,後面發現是因爲控制端和肉雞的ws jar包版本不一致導致此問題的出現

  3. 在JMeter WebSocket Samplers源碼issue中作者也提及這些問題在1.2.26版本github issue中已解決
    在這裏插入圖片描述
    確實有一定的改善,但是模擬1.5w終端時仍有少量的錯誤

  4. 此時連接數仍不能達到1.5w,從鏈路中排查問題,發現單SLB個連接數能達到1w,使用2個SLB連接數仍然爲1w,定位是此時連接的是阿里外網的SLB導致

  5. 模擬1.5w終端連接後,模擬ws發送羣聊消息,各個終端接收廣播的消息,jmeter又出現end of streamread timeout 的問題,定位問題可能是因爲讀幀的問題
    在這裏插入圖片描述
    在jmeter腳本中增加 WebSocket Single Read Sampler 接收數據包,上面問題得到一定的緩解,但仍會出現

  6. 單個肉雞模擬1w終端連接,試驗後並沒有問題,可正常保持心跳並接收廣播信息,穩妥起見,最終決定單個肉雞模擬1w連接

100w終端連接

  1. 模擬50w終端連接(50臺肉雞,每臺模擬1w終端),使用的是GUI模式,此時控制端卡死,只能在各個肉雞非GUI模式全部運行
JVM_ARGS="-Xms6g -Xmx6g" /root/apache-jmeter-5.1.1/bin/jmeter -n  -t /root/apache-jmeter-5.1.1/bin/im_enter_room.jmx &
  1. 模擬50w終端連接,模擬ws羣聊(tps2200,廣播下行包數量3000w/min),長時間運行(>1h)並沒有任何問題(此時jmeter、nginx、服務均正常)

  2. 在步驟1的基礎上,增加連接50w用戶,此時新增的50w用戶僅連接成功25w左右,多次試驗均爲此數值,排查發現一個終端nginx需要保持2個連接,每個連接需要4個worker_connections,現在有8個8核的nginx(每個SLB4個),nginx中worker_connections的值爲10w,那麼能夠支持的連接數剛好是80w,將worker_connections的值修改爲100w,連接數可正常達到100w

如果nginx 中worker_connections 值設置是1024,worker_processes 值設置是4,按反向代理模式下最大連接數的理論計算公式:
最大連接數 = worker_processes * worker_connections/4

  1. 正常連接100w終端後,進行模擬ws羣聊時,出現大批量的掉線,nginx在短時間內OOM
    在這裏插入圖片描述
    且jmeter端報錯爲
    there is no connection to re-use 2020-03-12 00:02:09,587 ERROR e.l.j.w.SingleReadWebSocketSampler: Sampler 'WebSocket Single Read Sampler': there is no connection to re-use

  2. 經過理論和實踐,對配置信息進行調整如下
    proxy_buffer
    針對單個連接的資源配額需要管控,一個最快改動方式是把 proxy_buffering 設置爲 off。在壓測環境修改了這個值以後,以及調小了 proxy_buffer_size的值以後,內存穩定在了 20G 左右,沒有再飆升過。後續可以開啓 proxy_buffering,調整proxy_buffers 的大小可以在內存消耗和性能方面取得更好的平衡
    worker_connections
    前面也提到將worker_connections的值設置爲100w,但是100w需要預先分配大量的內存,將nginx升級配置16核,並將worker_connections的值設置爲10w,按照計算可以支撐160w連接
    配置爲1個SLB(支持100w併發連接)-> 4個nginx(32C 64G) ->5個ingress(32C 64G)
    nginx的net.ipv4.ip_local_port_range
    服務器某個端口可以連接的最大tcp數量是由四元組成:src_ip(本地ip),src_port(本地端口),dst_ip(客戶端ip),dst_port(客戶端端口)
    理論上在src_ip,src_port固定的情況下,一個客戶端Ip理論上最多有65535個連接數。ip_local_port_range這個參數控制的就是dst_port的範圍
    4個nginx和5個ingress,那麼將dst_port的值設置爲1024-65536,理論上可以支撐的連接數(65535-1024)* 5 *4 = 120w
    worker_rlimit_nofile
    進程的最大打開文件數限制,這樣nginx就不會有“too many open files”問題了。不能超過最大文件打開數在linux終端中輸入ulimit -a進行查看
    在這裏插入圖片描述

業務請求

可進行ws羣聊(tps2200)和http羣聊(wps1000)測試,但增加ws獲取房間歷史消息和獲取成員列表的接口請求時,,nginx內存飆升,短時間內OOM
抓包發現jmeter肉雞出現大量零窗口,同時使用命令 ss -nt 發現每個端口緩存在持續飆升,這兩個接口返回的數據量太大導致jmeter發送請求端肉雞端口緩存飆升,同時拖垮nginx,降低請求tps已經增加等待時間等操作後,可正常請求,並達到預期的效果
在這裏插入圖片描述
在這裏插入圖片描述

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