短信服務,運用了thrift框架。html
thrift,是 Facebook 實現的一種高效的、支持多種編程語言的遠程服務調用的框架。而推出最初,其存在不少問題,見如下連接java
http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/ thrift學習入門linux
http://yanyiwu.com/work/2014/10/17/thrift-source-code-illustration.html thrift源碼解析apache
http://blog.csdn.net/shijun_zhang/article/details/6863836 thrift rpc 使用常見問題解答和經驗編程
因此,thrift的client最好是以鏈接池來進行管理,防止過多的client同時請求帶來的問題。而thrift的server的選擇,則要根據要提供的服務進行選擇。數組
對應的server(java版)主要有服務器
一、TSimpleServer 通常僅做爲測試用
二、TNonblockingServer 非阻塞式,用nio進行通訊,但依然只有一個進程處理請求
三、THsHaServer 混合模式,半同步/半異步。它使用一個單獨的線程來處理網絡I/O,一個獨立的worker線程池來處理消息。
四、TThreadedSelectorServer 容許你用多個線程來處理網絡I/O。它維護了兩個線程池,一個用來處理網絡I/O,另外一個用來進行請求的處理。當網絡I/O是瓶頸的時候, TThreadedSelectorServer比THsHaServer的表現要好
五、TThreadPoolServer 相似於線程池了,有一個專用的線程用來接受鏈接。一旦接受了一個鏈接,它就會被放入ThreadPoolExecutor中的一個worker線程裏處理。可是worker線程被綁定到特定的客戶端鏈接上,直到它關閉。
網絡
具體區別,請查看 框架
http://blog.csdn.net/azhao_dn/article/details/8898610異步
http://m.blog.csdn.net/blog/hjx_1000/42779915
咱們的短信服務,由於多了一家運營商,並且又分生產跟營銷不一樣的渠道,再考慮到可擴展性,即後期會加入別的運營商,因此將短信服務進行了簡單的重構。
提供兩個接口,發送營銷短信、發送生產短信,而後根據傳入的cpid(標誌着發送短信的場合),找到對應的渠道信息,再找到對應的operator,從而調用該operator對應的發送短信的方法。
未進行重構前,還一直沒關注其佔用內存狀況,也沒有報內存溢出。
重構後,一開始還比較穩定,用了幾天以後,出現了內存溢出,一直到如今,出現的愈來愈頻繁。
用 ps -aux | grep sms 查看該服務佔用內存一直增長。即便gc後,也依然減小的不多。
用 jmap -histo pid > jvm.log,打印出內存中相關的內容,
num #instances #bytes class name
----------------------------------------------
1: 2179572 34873152 java.lang.Object
2: 63701 33237280 [C
3: 242114 29053680 java.net.SocksSocketImpl
4: 241711 27071632 sun.nio.ch.SocketChannelImpl
5: 241711 11602128 sun.nio.ch.SocketAdaptor
6: 30834 7792856 [B
7: 242115 7747680 java.net.Inet4Address
8: 241712 7734784 [Ljava.nio.channels.SelectionKey;
9: 45748 6613624 <constMethodKlass>
10: 45748 6231856 <methodKlass>
11: 242580 5821920 java.io.FileDescriptor
12: 241712 5801088 java.net.InetSocketAddress
13: 3993 4316064 <constantPoolKlass>
14: 242696 3883136 java.util.concurrent.atomic.AtomicInteger
15: 241712 3867392 sun.nio.ch.OptionAdaptor
16: 241712 3867392 sun.nio.ch.SocketOptsImpl$IP$TCP
17: 241711 3867376 sun.nio.ch.SocketChannelImpl$1
18: 241264 3860224 java.nio.channels.spi.AbstractInterruptibleChannel$1
19: 69769 3599896 <symbolKlass>
20: 16811 3220440 [I
除了socket相關的,基本都是char,String,int等數組之類的。
查詢內存狀況的相關工具介紹,參考此連接 http://blog.csdn.net/zhujiongming/article/details/8510462
用jstat -gc pid,關注gc狀況,偶然間抓住了gc先後的jvm.log,進行對比後,發現socket相關的對象基本沒有減小,初步懷疑thrift基於socket通訊,沒有關閉socket?可是後臺是一個線程池,不解。還須要對thrift原理一級socket通訊原理進行學習。
後來在本地跑thrift server,沒有任何請求,佔用內存以下圖所示,頂峯時甚至達到過400-500M,並且,測試機上的thrift server也內存溢出過,請求量幾乎沒有。
thrift一直再監聽是否有請求,佔用大量內存?
能夠選擇jdk自帶的jconsole以及jvirtualvm來監控內存使用狀況,jvirtualvm能夠dump出當時內存的內容,能夠分析看到裏面具體的信息,好比String是什麼內容等。可是依然沒有收穫。
後來選用jprofiler,遠程監控服務器,須要加入以下配置-agentpath:/data/jprofiler9/bin/linux-x64/libjprofilerti.so=port=8849,這樣就能夠經過8849端口,用jprofiler客戶端遠程監控服務器的內存狀況了。
咱們也能夠加入gc日誌,分析gc狀況 -Xloggc:/data/logs/sms/gclogs/gc.log
加入堆內存溢出時,導出dump文件,保留當時內存內容 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/sms/outofmemory.hprof
jvm參數設置以及GC策略,參考此連接 http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html ,後期須要深刻學習一下。
後來發現,報內存溢出時,400M的內存,只是佔用了幾十M?目前問題依然沒有找到。