天天看點

[開發]resin+spring+struts配搭線上上常見的三個問題

現象1:通路頁面出現500錯誤,錯誤描述為:java.lang.noclassdeffounderror,後面跟的類名各式各樣不一一列舉了。

現象2:resin被wathcdog自動重新開機,日志中表明這是因為:resin shutdown from out of file descriptors。

分析:由于linux預設檔案句柄限制為1024(通過指令ulimit –n來檢視),是以當web server應對高負載起了大量線程,incoming socket connections和outgoing socket connections都很多,而且背景代碼也可能涉及大量句柄打開,尤其是struts+spring組合。

是以當句柄數迅速到達1024的限制後,無法打開新句柄,于是乎檔案打不開、類定義找不到,諸如此類的錯誤就出現了。

解決:

短期政策是調大linux下對檔案句柄數限制。操作如附錄1所示。對于這個數字,一般建議是32667,也可以設定的更大,我們直接調為51200。

現象:resin被持續通路一段時間後,比如一天,就會報告如下500錯誤,導緻所有頁面不能通路:

    outofmemoryerror:permgen space

此時,就隻能重新開機機器了,重新開機resin都沒用。

分析:因為線上用了spring+struts,這些架構用到大量動态class,classloader是把這部分記憶體放在permgen space裡的。而jvm的gc是不會清理permgen space的。這樣很容易導緻線上應用報告permgen space記憶體溢出。

解決:通過在resin.xml中增加jvm-arg一系列參數,調大“permsize”和“maxpermsize”這兩個參數來盡量避免出現jvm記憶體永久儲存區域溢出錯誤。permsize預設值參考附錄2。修改情況參見附錄3。

現象:resin報告如下500錯誤,導緻所有頁面不能通路:

    outofmemoryerror:java heap space

此時重新開機resin還可以恢複。

分析:jvm預設的最大可用記憶體(-xmx參數)和初始堆大小(-xms參數)都偏小,很容易限制住伺服器的能力。當java架構的能力還沒有發揮出來時,就已經被系統預設的各種參數限制住了,導緻各種各樣的異常。

解決:通過在resin.xml中增加jvm-arg一系列參數,調大“xms”和“xmx”以及“xmn”這三個參數。修改情況參見附錄3。xmn附錄4。

其中xmx的值可以設定得很大,比如4096mb,跟你的實體記憶體大小差不太多都行,64位linux支援得住。xmn的值是xmx數值的1/4。

編輯/etc/profile,加入

ulimit -n 51200

有人認為設定為4096就可以,但在網絡伺服器上此數字最好調成幾萬,不然流量沖上來太容易沖破。

還有設定指令是:ulimit –shn 51200,-s、-h這兩個參數的說明如下:

-h 設定硬體資源限制。

-s 設定軟體資源限制。

-n size:設定核心可以同時打開的檔案描述符的最大值。

沒有給resin.xml加permsize的情況下,預設計算規則是:

“jvm使用-xx:permsize設定非堆記憶體初始值,預設是實體記憶體的1/64;由xx:maxpermsize設定最大非堆記憶體的大小,預設是實體記憶體的1/4。”

那麼,如果是實體記憶體4gb,那麼64分之一就是64mb,這就是permsize預設值,也就是永生代記憶體初始大小;

四分之一是1024mb,這就是maxpermsize預設大小。

優化規則:server端的jvm最好将-xms和-xmx設為相同值。為了優化gc,最好讓-xmn值約等于-xmx的1/4。

線上resin 4.0.15的resin.xml中增加如下配置節點:

<server-default>

    <jvm-arg>-xms4096m</jvm-arg>

    <jvm-arg>-xmx4096m</jvm-arg>

    <jvm-arg>-xmn1024m</jvm-arg>

    <jvm-arg>-xx:permsize=128m</jvm-arg>

<jvm-arg>-xx:maxpermsize=256m</jvm-arg>

    <thread-max>1024</thread-max>

    <socket-timeout>30s</socket-timeout>

    <keepalive-max>512</keepalive-max>

    <keepalive-timeout>60s</keepalive-timeout>

</server-default>

jvm的-xmn參數含義是young generation的heap size。

jvm有2個gc線程。第一個線程負責回收heap的young區。第二個線程在heap不足時,周遊heap,将young 區更新為older區。older區的大小等于-xmx減去-xmn,不能将-xms的值設的過大,因為第二個線程被迫運作會降低jvm的性能。