很容易忽略的ETS表個數限制問題
最近經常碰到ets表使用的數目超過系統的限制導致Erlang應用異常的案例。 比如說神鋒同學報告說在ssh模組裡面,最多隻能開啟500個左右連結,系統空閒的很,但是無法繼續加大連結。 浩庭同學報告說mnesia的事務只能開1千多,多了就上不去了。這些問題看起來沒有關聯。但是其實和ets都有很大的關係,而且會報system_limit錯誤。
Erlang系統的限制見這裡: http://www.erlang.org/doc/efficiency_guide/advanced.html#id215064
其中和ets相關的:
Ets table 記憶體消耗
Initially 768 words + the size of each element (6 words + size of Erlang data). The table will grow when necessary.
Ets-tables
The default is 1400, can be changed with the environment variable ERL_MAX_ETS_TABLES.
這個值非常的偏保守,我們通常的伺服器都有幾十G的記憶體,因為ETS基本是消耗記憶體的,所以我們不介意都開大點。
回到前面的問題,ssh出問題的原因是它每個連結需要3個ets, 而mnesia一個事務也要消耗1個ets表。
知道了問題的本質就很容易解決問題:
erl -env ERL_MAX_ETS_TABLES NNNNN就好了。
再來順手看下ejabberd的配置檔案的說明:
# ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
#
# The number of concurrent ETS and Mnesia tables is limited. When the limit is
# reached, errors will appear in the logs:
# ** Too many db tables **
# You can safely increase this limit when starting ejabberd. It impacts memory
# consumption but the difference will be quite small.
#
# Default: 1400
#
#ERL_MAX_ETS_TABLES=1400
但是如何知道N設成多大比較合適呢?
erl shell下按下CTRL+C 再按下i就告訴你現在這些核心資源包括ets的使用情況,具體見以下程式碼。 你一看用的差不多了,就搞大點。
void info(int to, void *to_arg) { erts_memory(&to, to_arg, NULL, THE_NON_VALUE); atom_info(to, to_arg); module_info(to, to_arg); export_info(to, to_arg); register_info(to, to_arg); erts_fun_info(to, to_arg); erts_node_table_info(to, to_arg); erts_dist_table_info(to, to_arg); erts_allocated_areas(&to, to_arg, NULL); erts_allocator_info(to, to_arg); }
其實還有一個更簡單的方法用crashdump viewer看下實際系統中有多少程序,每個程序消耗多少port和ets表。
我來說下大概的步驟:
1. 產生crashdump: 在實際執行的系統中按下CTRL+C再按大寫的A,看到系統退出,生成我們系統執行期的快照。
2. 執行webtool: webtool:start() 他會告訴我們web地址,開啟瀏覽器,開啟該地址。
3. 在webtool中開啟crashdump viewer模組,載入我們的crashdump檔案進行分析,得到系統執行期的友好的解釋。
4. 在程序這一欄裡面可以看到每個程序的狀態和使用的資源。
根據這些資訊稍微估算下系統需要開多少process和port,提前規劃好。
祝玩的開心!