短信服务,运用了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?目前问题依然没有找到。