Whatsapp已經使用Erlang在生產環境跑到96GB內存單機 3M長連接,參加:WhatsApp的Erlang世界。畢竟業務級別能達到Whatsapp那樣極少,現在只有千萬級,單機太多掛一台影響太大,再者就是沒有多線接入,每個機房都得扔那么幾台機器吧,所以1M就能滿足要求。
Erlang 作為長連接網關有着天生的優勢:
- 擅長與IO密集型業務,也要求將網關設計盡量簡單,認證完后,簡單解析報頭,就直接將請求轉發給后端服務處理
- 網絡層有beam c 實現得非常高效 ,erlang 代碼只是簡單流程控制,也就是說代碼性能很接近優化的很好c程序
- 代碼簡單,易維護,erlang 進程和連接一對一關系,代碼500行左右
- 基於進程GC,node 內存多大也不用擔心stop of word
- 熱升級,網關設計本盡量簡單,減少升級,但也不可避免,熱升級保證不斷連接
- 穩定,beam 足夠穩定,即使天天更新的服務,連續一兩年不重啟也正常
- 多語言混合,后端可很容易使用其他語言實現
劣勢:CPU密集型業務,性能差,如果不想用c解包,盡量使用二進制協議,盡量將包協議標識放在包體固定位置,方便dispatch
1. 測試環境
- 服務端: R620 2*(E5-2620 6核心12線程)/mem:128GB
- 客戶端:R620 2*(E5-2620 6核心12線程)/mem:48GB(5台*5 IP,共25IP)
2. 調優
1. beam 啟動參數
+sbt db 綁定調度器與CPU的親緣性
+P 2000000 進程數限制(合適即可)
+K true 啟用epoll
+sbwt none 關閉beam 調度器 spinlock,降低CPU
+swt low 提高調度器喚醒靈敏度,避免長時間運行睡死問題
參考我另外一篇:erlang cpu 相關參數調整
2. Erlang 網絡庫:ranch 需要修改
- 配置acceptors 數量1024,backlog 32768
同時系統backlog調整: net.core.somaxconn, net.core.netdev_max_backlog, net.ipv4.tcp_max_syn_backlog 32768
- 刪除新加連接時的 ranch_sup 和 connection monitor,占用內存且用處不大,同時單進程熱點問題,也造成backlog 無法及時處理
- acceptor 設置 process_flag(prority, high),否則因為公平調度問題,即使CPU不高,backlog 無法及時得到處理
3. Erlang內存占用
因為Erlang GC 基於進程,每個連接對應一個進程,每個連接的業務量都很小。那樣就會造成一種現象數百w進程內都有一點垃圾,無法得到GC。
使用hibernate,erlang:hibernate 會清空但前調用棧,並強制GC,下次進程收到消息后,會通過參數MFA繼續執行。
使用gen_server 簡單的在沒有個包處理完后,都加上hibernate, CPU無明顯增加情況下,可將內存使用降低到1/3 以下,非常值得使用。
3. 壓測場景
- 客戶端在5台機器,25個IP,開啟 tcp_tw_reuse tcp_tw_recycle 后每個IP穩定跑6w連接還是沒問題的。
- 6K/s 登陸、認證、心跳、退出 操作
- 1w/s 消息推送、ack
- 運行12 小時
4. 結果
ss -s Total: 1500254 (kernel 1500317) TCP: 1500090 (estab 1500077, closed 0, orphaned 0, synrecv 0, timewait 0/0), ports 74 Transport Total IP IPv6 * 1500317 - - RAW 0 0 0 UDP 0 0 0 TCP 1500090 1500090 0 INET 1500090 1500090 0 FRAG 0 0 0
網關機器:
- CPU 500%
- 網卡 6w/s tcp packet in/out
- node mem 12GB (內部memory(total) 顯示實際使用9GB)
- kernel mem 11GB
- 也就是150w連接,使用了23GB內存,每個連接占用15KB,約一半是內核使用,erlang 使用內存並不多。
- 在如此業務量壓力下,500% CPU表現也不俗,隨無法和c相比,但其多核擴展性好。
- 服務器有24核心,但環境其他服務、客戶端IP數限制,沒有繼續增大壓力,理論上單機200~300w 連接,5w/s 消息推送 應該不是問題。