背景:{active, once} 的性能瓶頸
- 每次收包後需重新
inet:setopts(S, [{active, once}]) 才能繼續收包
- 每次調用觸發
epoll_ctl 系統調用,高併發下大量 epoll_ctl 會阻塞 epoll_wait 線程,降低網絡吞吐
{active, N} 機制
- 一次性授權接收
N 個數據包,計數器遞減
- 計數器歸零或顯式設為 0 時,Socket 轉入被動模式,進程收到
{tcp_passive, Socket} 消息
- 再次
inet:setopts(S, [{active, N}]) 重新授權
N 範圍 -32768..32767,負值減少計數器
實戰模式:定時 + 計數雙重保護
inet:setopts(Socket, [{active, 300}]),
erlang:send_after(30*1000, self(), release_passive).
handle_info(release_passive, State) ->
inet:setopts(Socket, [{active, 300}]),
{noreply, State};
handle_info({tcp_passive, Socket}, State) ->
inet:setopts(Socket, [{active, 300}]),
{noreply, State}.
- 30 秒內最多處理 300 包,超限自動進入被動模式
- 可加計數器:若短時間內多次觸發
tcp_passive,判定為異常/攻擊,主動關閉連接
優勢總結
- 減少
epoll_ctl 頻率,提升高併發性能
- 應用層可靈活控制流量窗口
- 被動模式通知機制天然支持背壓處理