EMQ學習---客戶鏈接資源消耗
Erlang進程消耗
EMQ對客戶端鏈接使用鏈接進程(emqtt_client)和session進程(emqtt_session)分開的策略。 當一個mqtt的客戶端連接到EMQ的服務器上的時候,首先會建立一個負責管理連接的進程(emqtt_client),當驗證客戶端有效後會建立另一個進程(emqtt_session),負責該客戶端的會話。
在EMQ中,每一個clientID只能登錄一次,因此後登錄的客戶端會將先登錄的客戶端踢下線。
主要內存消耗(一個connection大約占10K內存)
數據表
當一個客戶端成功完成了驗證,EMQ會在mqtt_session中添加一個表項目,同時會在mqtt_local_session和mqtt_client這兩張ets表中添加表項目。
進程上下文
鏈接進程(emqtt_client)負責接收客戶端發來的數據和接受服務器內部要發送給客戶端的數據,並使用編解碼器進行編解碼,因此鏈接進程的上下文消耗,主要取決接收到的數據包大小和將要發送的數據包大小和數量。
session進程(emqtt_session)會保持一個inflight隊列,用來對QoS大於0的消息進行應答等待,默認會保存32個消息在等待應答,如果超過這個量級就會放入等待隊列。因此session進程(emqtt_session)的主要內存消耗,取決於多少等待應答的消息,以及這些需要應答消息的數據包的大小。
主要CPU消耗
定時器
鏈接進程(emqtt_client),默認會啟動一個心跳定時器,定期的檢查鏈接是否存活。session進程(emqtt_session)同樣會開啟一個重新發送定時器,用來檢查QoS大於0的消息的infligt響應,當客戶端發布QoS為2的消息時還會開啟另外一個定時器,用來檢測REPL信息的響應,當然session進程(emqtt_session)有可能會在客戶端離線後保持一段時間,因此在這段時間會建立一個超時退出的定時器。因此session進程(emqtt_session)在某一個時刻會同時存在三個定時器。
監控
session進程(emqtt_session)為了發現鏈接進程的退出,會建立一個針對鏈接進程的監控。而在客戶端上線成功後後在向mqtt_local_session和mqtt_client這兩張ets表中添加項目的時候,會分別建立兩個監控,用來監控session進程(emqtt_session)和鏈接進程(emqtt_client)的退出。
進程消息
因為EMQ使用了鏈接進程(emqtt_client)和session進程(emqtt_session)分開的策略,因此產生進程消息傳遞是無法避免的。因為session進程(emqtt_session)會負責接收服務器發送給客戶端的消息,並進行預先處理,處理完之後再交付給鏈接進(emqtt_client)程進行發送。
當使用持久化session的時候,session進程(emqtt_session)的查找和恢復時也會產生大量的進程消息。
總結
從上面的介紹中,可以看出,在部署一個EMQ服務器前需要考慮,一個客戶端平均消息的量級,QoS占比和數據包大小,同時根據有多少客戶端進行CPU頻率和數量的選擇(參考Actor模型中的調度部分)。
當運營一個EMQ服務器的時候,如果在消息量級和客戶端數量沒有明顯變化的情況下,CPU突然飆升,就要去考慮下是否出現客戶端頻繁上下線的情況。當然這只是一個簡單的例子,還有很多情況在此就不一一列舉了
EMQ學習---客戶鏈接資源消耗