高性能硬件上的程序部署策略:
硬件系统为4个CPU、16GB物理内存,操作系统为64位CentOS,Resin作为web服务器。管理员选用了64位的JDK1.5,并通过-Xmx和-Xms的参数将Java堆固定在12GB。
高性能硬件上部署程序,目前主要由两种方式:
1.通过64位JDK来使用大内存
2.使用若干个32位虚拟机建立逻辑集群来利用硬件资源
对于用户交互性强、对停顿时间敏感的系统,可以给Java虚拟机分配超大堆的前提是有把握应用程序的Full GC频率控制得足够低,至少要低到不会影响用户使用,譬如十几个小时甚至一天才出现一次Full GC,这样可以通过在深夜执行定时任务的方式触发Full GC甚至自动重启服务器来保持内存可用空间在一个稳定的水平
控制Full GC频率的关键是看应用中绝大多数对象能否符合 朝生夕灭 的原则,即大多数对象的生存时间不应太长,尤其是不能有成批量的、长生存时间的大对象产生,这样才能保障老年代空间的稳定
如果计划使用64位JDK来管理大内存,还需要考虑下面可能面临的问题:
1.内存回收导致长时间停顿
2.现阶段,64位JDK的性能测试结果普遍低于32位JDK
3.需要保证程序足够稳定,因为这种应用要是产生堆溢出几乎就无法产生堆转储快照,哪怕产生了快照也几乎无法进行分析
4.相同程序在64位JDK消耗的内存一般比32位JDK大,这是由于指针膨胀,以及数据类型对齐补白等因素导致的
如果使用第二种方式,使用多个32位虚拟机建立逻辑集群来利用硬件资源。具体做法是在一台物理机器上启动多个应用服务器进程,每个服务器进程分配不同端口,然后在前端搭建一个负载均衡器,以反向代理的方式来分配访问请求。
使用第二种逻辑集群的方式部署程序,可能会遇到下面一些问题:
1.尽量避免节点竞争全局的资源,最典型的就是磁盘竞争,各个节点如果同时访问某个磁盘文件的话,容易导致IO异常
2.很难最高效领某些资源池,比如连接池,一般都是在各个节点建立自己独立的连接池,这样有可能导致一些节点池满了而另外一些节点仍有较多空余。尽管可以使用集中式的JNDI,但这个有一定复杂性并且可能带来额外的性能开销
3.各个节点仍然不可避免地受到32位的内存限制,在32位Windows平台中每个进程只能使用2GB内存,考虑到堆以外的内存开销,堆一般最多只能开到1.5GB。在某些Linux或Uninx系统中,可以提升到3GB乃至接近4GB的内存,但32位中仍然受最高4G内存的限制
4.大量使用本地缓存的应用,在逻辑集群中会造成较大的内存浪费,因为每个逻辑节点上都有一份缓存,这时候可以考虑把本地缓存改为集中式缓存
回到上面的案例中,最后的部署方案调整为建立5个32位JDK的逻辑集群,每个进程按2GB内存计算(堆固定为1.5),占用了10GB内存。另外建立一个Apache服务作为前端均衡代理访问门户。考虑到用户对响应速度比较关心,并且文档服务的主要压力集中在磁盘和内存访问,CPU资源敏感度较低,因此改为CMS收集器进行垃圾回收。