這次使用經常使用的順手的 netty NIO框架(netty-3.6.5.Final),封裝的很好,接口很全面,就像它現在的域名 netty.io,專注于網絡IO。
整個過程沒有什么技術含量,淺顯分析過就更顯得有些枯燥無聊,準備好,硬著頭皮吧。
測試服務器配置
運行在VMWare Workstation 9中,64位Centos 6.2系統,分配14.9G內存左右,4核。
已安裝有Java7版本:
javaversion"1.7.0_21" Java(TM)SERuntimeEnvironment(build1.7.0_21-b11) JavaHotSpot(TM)64-BitServerVM(build23.21-b01,mixedmode)
測試端
測試端和以前一樣的程序,翻看前幾篇博客就可以看到client5.c的源碼。
在/etc/sysctl.conf中添加如下配置:
fs.file-max=1048576 net.ipv4.ip_local_port_range=102465535 net.ipv4.tcp_mem=78643220971523145728 net.ipv4.tcp_rmem=4096409616777216 net.ipv4.tcp_wmem=4096409616777216 net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_tw_recycle=1
服務器程序
這次也是很簡單吶,沒有業務功能,客戶端HTTP請求,服務端輸出chunked編碼內容。
入口HttpChunkedServer.java: 唯一的自定義處理器HttpChunkedServerHandler.java: 啟動腳本start.sh 達到100萬并發連接時的一些信息
每次服務器端達到一百萬個并發持久連接之后,然后關掉測試端程序,斷開所有的連接,等到服務器端日志輸出在線用戶為0時,再次重復以上步驟。在這反反復復的情況下,觀察內存等信息的一些情況。以某次斷開所有測試端為例后,當前系統占用為(設置為 list_free_1):
totalusedfreesharedbufferscached Mem:1518977367453018120 -/ buffers/cache:75977592 Swap:40959483147
通過top觀察,其進程相關信息
PIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME COMMAND 4925root2008206m4.3g2776S0.328.850:18.66java
在啟動腳本start.sh中,我們設置堆內存為6G。
ps aux|grep java命令獲得信息:
root492538.028.884034444484764?Sl15:2650:18java-server…HttpChunkedServer8000
RSS占用內存為4484764K/1024K=4379M
然后再次啟動測試端,在服務器接收到 online user 1023749時, ps aux|grep java內容為:
root492543.628.484034444422824?Sl15:2662:53java-server…
查看當前網絡信息統計
ss-s Total:1024050(kernel1024084) TCP:1023769(estab1023754,closed2,orphaned0,synrecv0,timewait0/0),ports12 TransportTotalIPIPv6 *1024084– RAW000 UDP761 TCP1023767121023755 INET1023774181023756 FRAG000
通過top查看一下
top-p4925 top-17:51:30up3:02,4users,loadaverage:1.03,1.80,1.19 Tasks:1total,0running,1sleeping,0stopped,0zombie Cpu0:0.96%sy,0.0%ni,52.9%id,1.0%wa,13.6%hi,29.0%si,0.0%st Cpu1:1.45%sy,0.0%ni,80.1%id,1.9%wa,0.0%hi,12.0%si,0.0%st Cpu2:1.54%sy,0.0%ni,80.5%id,4.3%wa,0.0%hi,9.3%si,0.0%st Cpu3:1.94%sy,0.0%ni,84.4%id,3.2%wa,0.0%hi,6.2%si,0.0%st Mem:15554336ktotal,15268728kused,285608kfree,3904kbuffers Swap:4194296ktotal,1082592kused,3111704kfree,37968kcached PIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME COMMAND 4925root2008206m4.2g2220S3.328.462:53.66java
四核都被占用了,每一個核心不太平均。這是在虛擬機中得到結果,可能真實服務器會更好一些。 因為不是CPU密集型應用,CPU不是問題,無須多加關注。
系統內存狀況
free-m totalusedfreesharedbufferscached Mem:15189149262630556 -/ buffers/cache:14864324 Swap:409510573038
物理內存已經無法滿足要求了,占用了1057M虛擬內存。
查看一下堆內存情況
jmap-heap4925 AttachingtoprocessID4925,pleasewait… Debuggerattachedsuccessfully. Servercompilerdetected. JVMversionis23.21-b01 usingparallelthreadsinthenewgeneration. usingthread-localobjectallocation. ConcurrentMark-SweepGC HeapConfiguration: MinHeapFreeRatio=40 MaxHeapFreeRatio=70 MaxHeapSize=6442450944(6144.0MB) NewSize=629145600(600.0MB) MaxNewSize=629145600(600.0MB) OldSize=5439488(5.1875MB) NewRatio=2 SurvivorRatio=1 PermSize=52428800(50.0MB) MaxPermSize=52428800(50.0MB) G1HeapRegionSize=0(0.0MB) HeapUsage: NewGeneration(Eden 1SurvivorSpace): capacity=419430400(400.0MB) used=308798864(294.49354553222656MB) free=110631536(105.50645446777344MB) 73.62338638305664íEdenSpace: capacity=209715200(200.0MB) used=103375232(98.5863037109375MB) free=106339968(101.4136962890625MB) 49.29315185546875íFromSpace: capacity=209715200(200.0MB) used=205423632(195.90724182128906MB) free=4291568(4.0927581787109375MB) 97.95362091064453íToSpace: capacity=209715200(200.0MB) used=0(0.0MB) free=209715200(200.0MB) 0.0íconcurrentmark-sweepgeneration: capacity=5813305344(5544.0MB) used=4213515472(4018.321487426758MB) free=1599789872(1525.6785125732422MB) 72.48054631000646íPermGeneration: capacity=52428800(50.0MB) used=5505696(5.250640869140625MB) free=46923104(44.749359130859375MB) 10.50128173828125í 1439internedStringsoccupying110936bytes.
老生代占用內存為72%%uFF0C較為合理,畢竟系統已經處理100萬個連接。
再次斷開所有測試端,看看系統內存(free -m)
totalusedfreesharedbufferscached Mem:1518977237466013120 -/ buffers/cache:75897599 Swap:40959503145
記為 list_free_2。
list_free_1和 list_free_2兩次都釋放后的內存比較結果,系統可用物理已經內存已經降到7589M,先前可是7597M物理內存。
總之,我們的JAVA測試程序在內存占用方面已經,最低需要7589 950 = 8.6G內存為最低需求內存吧。
GC日志
我們在啟動腳本處設置的一大串參數,到底是否達到目標,還得從gc日志處獲得具體效果,推薦使用 GCViewer。
GC事件概覽:
其它:
總之:
只進行了一次Full GC,代價太高,停頓了12秒。
PartNew成為了停頓大戶,導致整個系統停頓了41秒之久,不可接受。
當前JVM調優喜憂參半,還得繼續努力等
小結
Java與與Erlang、C相比,比較麻煩的事情,需要在程序一開始就得準備好它的堆棧到底需要多大空間,換個說法就是JVM啟動參數設置堆內 存大小,設置合適的垃圾回收機制,若以后程序需要更多內存,需停止程序,編輯啟動參數,然后再次啟動。總之一句話,就是麻煩。單單JVM的調優,就得持續 不斷的根據檢測、信息、日志等進行適當微調。
JVM需要提前指定堆大小,相比Erlang/C,這可能是個麻煩
GC(垃圾回收),相對比麻煩,需要持續不斷的根據日志、JVM堆棧信息、運行時情況進行JVM參數微調
設置一個最大連接目標,多次測試達到頂峰,然后釋放所有連接,反復觀察內存占用,獲得一個較為合適的系統運行內存值
Eclipse Memory Analyzer結合jmap導出堆棧DUMP文件,分析內存泄漏,還是很方便的
想修改運行時內容,或者稱之為熱加載,默認不可能
真實機器上會有更好的反映
吐槽一下:
JAVA OSGI,相對比Erlang來說,需要人轉換思路,不是那么原生的東西,總是有些別扭,社區或商業公司對此的修修補補,不過是實現一些面向對象所不具備的熱加載的企業特性。
測試源代碼, 下載just_test。
更多關于云服務器,域名注冊,虛擬主機的問題,請訪問三五互聯官網:www.shinetop.cn