一、RabbitMQ內(nèi)存占用排查
1.定位 linux 系統(tǒng)內(nèi)存占用最高進(jìn)程
(1)輸入 top 指令
nqs@nqs-yq-haitao-order-1488355883912:~$ top

然后輸入大寫(xiě)的 M(Shift+m),基于內(nèi)存占用倒序,找到占用最大內(nèi)存的進(jìn)程,如果內(nèi)存占用最大的為 beam.smp 則為 RabbitMQ 進(jìn)程占用。
2.定位 RabbitMQ 內(nèi)部組建內(nèi)存占用情況
(1)進(jìn)入 RabbitMQ 指令目錄
nqs@nqs-yq-haitao-order-1488355883912:~$ cd ~/rabbitmq_server-3.6.6/sbin/
(2) 查看 RabbitMQ 內(nèi)存占用情況
nqs@nqs-yq-haitao-order-1488355883912:~/rabbitmq_server-3.6.6/sbin$ ./rabbitmqctl status

內(nèi)存參數(shù)詳解:
(1)內(nèi)存占用總數(shù)
參數(shù):
total
描述:
RabbitMQ 進(jìn)程內(nèi)存總占用量,單位 B(字節(jié))
(2)RabbitMQ 連接
參數(shù):
connection_readers
connection_writers
connection_channels
connection_other
描述:
? 這部分主要包含了連接和通道(channel)所消耗的內(nèi)存,也包含了SSL系統(tǒng)所使用的內(nèi)存。
(3)隊(duì)列
參數(shù):
queue_procs
queue_slave_procs
描述:
? 隊(duì)列占用的內(nèi)存指的是隊(duì)列進(jìn)程消耗的,并不包含消息體(在二進(jìn)制中)。當(dāng)內(nèi)存不足時(shí),這部分的內(nèi)存將交換到磁盤(pán)上。
(4)插件
參數(shù):
plugins
描述:
插件使用的內(nèi)存不包含連接rabbit服務(wù)器的Erlang客戶(hù)端和數(shù)據(jù)庫(kù)所占用的部分,通常包含像一些協(xié)議插件如STOMP和MQTT。
注:有出現(xiàn)過(guò)隊(duì)列數(shù)量配置過(guò)多 RabbitMQ_Manager插件內(nèi)存占用過(guò)高的情況。
(5)其它進(jìn)程內(nèi)存
參數(shù):
other_proc
描述:
? 除了上面所提到的以外的進(jìn)程所消耗的部分,這里的進(jìn)程是erlang虛擬機(jī)中的概念,最近被GC回收的內(nèi)存會(huì)展現(xiàn)在這里。
(6)Mnesia
參數(shù):
mnesia
描述:
? Mnesia保存了一份磁盤(pán)上的數(shù)據(jù)拷貝到內(nèi)存,意味著當(dāng)有大量隊(duì)列、交換機(jī)、綁定、用戶(hù)信息或虛擬主機(jī)時(shí)會(huì)消耗大量的內(nèi)存。
(7)管理數(shù)據(jù)庫(kù)
參數(shù):
mgmt_db
描述:
? 前提是啟用了管理插件,在集群中它只會(huì)出現(xiàn)在一個(gè)節(jié)點(diǎn)中。
(8)message store索引
參數(shù):
msg_index
描述:
? 保存了所有消息的索引,包括那些被交換到磁盤(pán)上的消息。
(9)其它ETS表
參數(shù):
other_ets
描述:
除了上面三個(gè)集合以外的內(nèi)存表。
(10)二進(jìn)制
參數(shù):
binary
描述:
erlang虛擬機(jī)所使用的共享二進(jìn)制數(shù)據(jù),消息體的內(nèi)存消耗包含在這部分。
(11)代碼
參數(shù):
code
描述:
代碼所消耗的內(nèi)存,一般為常量。
(12)Atoms
參數(shù):
atom
描述:
atoms消耗的內(nèi)存,一般為常量。
(13)其它系統(tǒng)內(nèi)存
參數(shù):
other_system
描述:
Erlang所消耗的其他內(nèi)存,比如可用文件描述符的統(tǒng)計(jì)。
3.RabbitMQ 流控閥值設(shè)置
? 目前官方默認(rèn)內(nèi)存流控閥值設(shè)置為0.4,即RabbitMQ 進(jìn)程內(nèi)存占用到系統(tǒng)總內(nèi)存的百分之四十生產(chǎn)者會(huì)發(fā)生流控。
? RabbitMQ 流控機(jī)制主要是一個(gè)自身保護(hù)機(jī)制,由于 RabbitMQ 是基于Erlang 開(kāi)發(fā),RabbitMQ 將每個(gè)隊(duì)列設(shè)計(jì)為一個(gè) Erlang 進(jìn)程,Erlang 進(jìn)程GC也是采用分代策略,當(dāng)新老生代一起參與Major GC時(shí),Erlang虛擬機(jī)會(huì)新開(kāi)內(nèi)存,根據(jù)root set將存活的對(duì)象拷貝至新空間,這個(gè)過(guò)程會(huì)造成新老內(nèi)存空間同時(shí)存在,極端情況下,一個(gè)隊(duì)列可能短期內(nèi)需要兩倍的內(nèi)存占用量,所以?xún)?nèi)存流控閥值設(shè)置為0.4相對(duì)是一個(gè)比較安全的值,設(shè)置太高,有可能系統(tǒng)內(nèi)存被全部占用導(dǎo)致系統(tǒng)進(jìn)程 kill RabbitMQ進(jìn)程,設(shè)置過(guò)低導(dǎo)致內(nèi)存使用率不高。
二、Erlang 進(jìn)程內(nèi)存占用排查
1.進(jìn)入 Erlang 終端
nqs@nqs-yq-haitao-order-1488355883912:~$ erl
2.查看內(nèi)存占用
1> erlang:memory().

3.查看進(jìn)程數(shù)量
? 如果內(nèi)存占用情況主要為Erlang進(jìn)程,查詢(xún)下 Erlang 進(jìn)程數(shù),確定是否由于過(guò)多進(jìn)程造成。
2> erlang:system_info(process_count).

4.查看進(jìn)程占用內(nèi)存信息
? 基于內(nèi)存占用降序獲取前20條進(jìn)程記錄信息
3> spawn(fun()->etop:start([{output,text},{interval,5},{lines,20},{sort,memory}])end).
注:
output:指定輸出方式
interval:內(nèi)存信息刷新間隔時(shí)間
lines:顯示內(nèi)存記錄行數(shù)
sort:排序規(guī)則(上文指令基于內(nèi)存用量倒排)

5.查看指定進(jìn)程詳情
1> erlang:process_info(pid(0,26,0)).
注:0,26,0 為上圖中進(jìn)程 id,不過(guò)由于"."是指令結(jié)束字符所以"."替換為","

| 參數(shù)名稱(chēng) | 描述 |
|---|---|
| dictionary | 進(jìn)程字典中所有的數(shù)據(jù)項(xiàng) |
| registerd_name | 注冊(cè)的名字 |
| status | 進(jìn)程狀態(tài) |
| links | 所有鏈接進(jìn)程 |
| monitored_by | 所有監(jiān)控當(dāng)前進(jìn)程的進(jìn)程 |
| monitors | 所有被當(dāng)前進(jìn)程監(jiān)控的進(jìn)程 |
| trap_exit | 是否捕獲exit信號(hào) |
| current_function | 當(dāng)前進(jìn)程執(zhí)行的函數(shù),{M, F, A} |
| current_location | 進(jìn)程在模塊中的位置,{M, F, A, [{file, FileName}, {line, Num}]} |
| current_stacktrace | 以current_location的格式列出堆棧跟蹤信息 |
| initial_call | 進(jìn)程初始入口函數(shù),如spawn時(shí)的入口函數(shù),{M, F, A} |
| memory | 進(jìn)程占用的內(nèi)存大小(包含所有堆,棧等),以bytes為單位 |
| message_queue_len | 進(jìn)程郵箱中的待處理消息個(gè)數(shù) |
| messages | 返回進(jìn)程郵箱中的所有消息,該調(diào)用之前務(wù)必通過(guò)message_queue_len確認(rèn)消息條數(shù),否則消息過(guò)多時(shí),調(diào)用非常危險(xiǎn) |
| reductions | 進(jìn)程規(guī)約數(shù) |