生活随笔
收集整理的這篇文章主要介紹了
监视Rails进程内存泄漏的技巧
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Rails應用比較容易遇到的兩類性能問題:一類是Rails執行很慢,CPU消耗過高;另一類是Rails進程內存泄漏。解決這兩類問題都需要你首先能夠精確定位出現問題的代碼,然后才知道如何對癥下藥。?
一、如何監控Rails進程的執行性能?
定位消耗CPU高,執行速度緩慢的Rails代碼,是相當容易的事情,僅僅需要你對production.log做一點統計分析,抽取出來執行時間最長的請求,問題就昭然若揭了。由于production.log對Rails請求的執行時間做了詳細的統計,例如:?
Ruby代碼
??
Completed?in?0.00693?(144?reqs/sec)?|?Rendering:?0.00489?(70%)?|?DB:?0.00000?(0%)?|?200?OK?[http://www.iteye.com/]??Completed?in?0.17238?(5?reqs/sec)?|?Rendering:?0.10011?(58%)?|?DB:?0.06244?(36%)?|?200?OK?[http://www.iteye.com/topic/49441?page=7]??Completed?in?0.20508?(4?reqs/sec)?|?Rendering:?0.19373?(94%)?|?DB:?0.00645?(3%)?|?200?OK?[http://www.iteye.com/news/1586]??
所以我們只需要寫一行shell命令,就搞定了!他把最耗時的前500個請求篩選出來,保存到timing.log里面。?
Ruby代碼
??
grep?"200?OK"?production.log?|?awk?'{print?"ALL:?"?$3?"??View:?"?$8?"?DB:?"?$12?"??URL:?"?$17?}'?\??|?sort?-r?|?head?-n?500?>?timing.log??
排序好的結果例如:?
Ruby代碼
??
ALL:?5.51774??View:?5.38277?DB:?0.13338??URL:?[http://www.iteye.com/wiki/topic/131966]??ALL:?5.51316??View:?5.31300?DB:?0.19400??URL:?[http://www.iteye.com/wiki/topic/145383]??ALL:?5.51311??View:?5.39321?DB:?0.11234??URL:?[http://www.iteye.com/wiki/topic/160370]??ALL:?5.51135??View:?5.37604?DB:?0.12652??URL:?[http://www.iteye.com/wiki/topic/233365]??ALL:?5.49881??View:?5.35998?DB:?0.10637??URL:?[http://www.iteye.com/wiki/topic/265217]??
哪些請求執行的慢,一目了然。 當然除此之外,我們還可以實時監控,在top監視窗口顯示Rails當前正在執行的請求URL。?
二、如何監控Rails進程的內存泄漏?
監控CPU是很容易的事情,但要監控Rails進程的內存泄漏,卻非常困難,原因在于production.log里面并沒有記錄進程的內存變化狀況,甚至你找不到任何ruby API可以用來直接查詢到進程使用的物理內存。實際上,要獲取一個進程的物理內存是一個平臺相關的操作,每個操作系統都會自己特定的API,并不通用,即使用C語言來編碼,也不是一件容易的事情。?
不過對于Linux操作系統來說,我們有一個捷徑可以獲取進程的內存狀況。Linux的/proc文件系統是內核的映象,/proc/進程pid/status 文件記錄了這個進程的狀態信息,例如:?
Ruby代碼
??
Name:???dispatch.fcgi??State:??S?(sleeping)??SleepAVG:???????135%??Tgid:???26645??Pid:????26645??PPid:???1??TracerPid:??????0??Uid:????1002????1002????1002????1002??Gid:????100?????100?????100?????100??FDSize:?64??Groups:?14?16?17?33?100???VmSize:???245680?kB??VmLck:?????????0?kB??VmRSS:????209104?kB??VmData:???205116?kB??VmStk:???????824?kB??VmExe:???????764?kB??VmLib:??????4220?kB??Threads:????????1??SigPnd:?0000000000000000??ShdPnd:?0000000000000000??SigBlk:?0000000000000000??SigIgn:?0000000000001000??SigCgt:?0000000002006e47??CapInh:?0000000000000000??CapPrm:?0000000000000000??CapEff:?0000000000000000??
注意第14行VmRSS,記錄了該進程使用的常駐物理內存(Residence),這個就是該進程實際占用的物理內存了。因此只要我們讀取該文件第14行,就可以得到內存信息。?
所以我們的任務變成了:在Rails處理請求之前記錄內存,等Rails處理完請求之后,再記錄內存,計算內存的變化狀況,寫入到production.log里面去。完成這個工作,只需要我們在Rails應用的app/controllers/application.rb里面添加幾行代碼:?
Ruby代碼
??
??around_filter?:record_memory????def?record_memory??????process_status?=?File.open("/proc/#{Process.pid}/status")??????13.times?{?process_status.gets?}??????rss_before_action?=?process_status.gets.split[1].to_i??????process_status.close??????yield??????process_status?=?File.open("/proc/#{Process.pid}/status")??????13.times?{?process_status.gets?}??????rss_after_action?=?process_status.gets.split[1].to_i??????process_status.close??????logger.info("CONSUME?MEMORY:???KB\tNow:?????end??
我們定義了一個AroundFilter,記錄一下處理請求前后的內存變化。有了這個信息,我們接下來的事情就簡單了,只需要從production.log里面抽取出來這行log,進行統計分析就可以了,這也僅僅只需要一行shell就搞定了:?
Ruby代碼
??
grep?"CONSUME?MEMORY"?production.log?|?grep?-v?"CONSUME?MEMORY:?0"?|??\???grep?-v?"CONSUME?MEMORY:?-"?|??awk?'{print?$3?"\t"?$6?"\t"?$8?}'?|?sort?-r?-n?|?\???head?-n?500?>?memory.log???
抽取內存記錄,去掉內存沒有增加,去掉內存減少(發生了GC)的請求,然后對那些處理請求之后內存上升的記錄進行排序,取出來前500條記錄保存到memory.log里面,結果如下所示:?
Ruby代碼
??
增加數?內存占用????請求URL??-----------------------------------------------??9528??175264??http://www.iteye.com/topic/304594??9524??129512??http://knityster.iteye.com/blog/172990??9496??147544??http://www.iteye.com/forums/??9492??197800??http://duyiwuer.iteye.com/rss??9452??146668??http://www.iteye.com/forums??9452??133844??http://wildlife.iteye.com/blog/47693??9440??157824??http://www.iteye.com/rss/blogs??9424??204664??http://www.iteye.com/wiki/topic/251964??9384??142200??http://towerhe.iteye.com/blog/93704??9380??165372??http://www.iteye.com/wiki/topic/77434??9368??207460??http://superleo.iteye.com/rss??
第一列是訪問了一個請求以后,Rails進程的內存上升了9MB多,第二列是處理完請求,Rails進程當前實際占了170多MB內存,第三列是處理了什么請求。?
根據這個統計結果,你可以很容易找出那些造成你Rails進程內存泄漏的罪魁禍首,哪些請求一訪問你的Rails進程內存就飚升已經是一目了然的事情了,這是不是很簡單?事實上通過這個辦法,JavaEye僅用了半個多小時,就解決了曾經困擾了半年多的內存泄漏問題,辦法雖土,卻很有效!
總結
以上是生活随笔為你收集整理的监视Rails进程内存泄漏的技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。