1,使用異步通信
異步通信顯然可以更快的返回響應。從實(shí)際經(jīng)驗看,對高吞吐服務(wù)器更大的好處是,系統中的某一服務(wù)出現問(wèn)題后往往出現雪崩似的服務(wù)宕機。這很多都是由于采用同步通信,需要等待其他服務(wù)同步通信結束后,其占用資源才能得到釋放。而這些資源往往是socket連接、線(xiàn)程、數據庫連接等比較重的資源。因此請慎重使用同步通信。如果你真的需要他,可以用個(gè)mock同步。正如Tim Yang所說(shuō):很多遠程服務(wù)調用是在關(guān)鍵路徑中,它可以容忍失敗,但是不能容忍堵塞。
2,使用NIO
NIO幾乎是Java cluster的基石。大量分布式開(kāi)源項目都基于此項技術(shù)。其好處是用較低的系統開(kāi)銷(xiāo)處理大量消息。在Intel(R) Pentium(R) 4 CPU 3.00GHz/1G內存的普通PC上跑基于NIO/TCP的RTSP測試,每秒處理1K個(gè)RTSP消息是沒(méi)有問(wèn)題的。關(guān)于NIO的架構可以參考開(kāi)源項目MINA,但要注意的是,不要直接用處理NIO消息的線(xiàn)程處理邏輯。
3,盡量不使用鎖
如果你在高性能服務(wù)器邏輯中看到同步鎖,就要小心了。我們希望服務(wù)器可以同時(shí)并發(fā)的盡量多的處理請求,而同步鎖恰恰摁住了業(yè)務(wù)的咽喉。同時(shí)如果線(xiàn)程設計有問(wèn)題而導致大量線(xiàn)程爭奪同一把鎖,最壞的情況(超過(guò)1K+線(xiàn)程)我曾見(jiàn)過(guò)JVM要用幾個(gè)小時(shí)來(lái)調度一個(gè)線(xiàn)程占鎖(為什么?請牛人解釋?zhuān)?。解決的辦法就是:1,盡量不用??赡苊??在一定程度上是可能的,比如我曾使用一致性哈希算法解決資源sticky的問(wèn)題。用算法替代同步,是一個(gè)思路;2,盡量減少鎖的范圍,事同步鎖影響的邏輯越少越好。效果也很明顯;3,使用數據庫更新替代同步也是一個(gè)思路,雖然我自己不是很喜歡,但是從實(shí)際效果看使用數據庫,特別是用存儲過(guò)程。在壓力不大的情況也是個(gè)簡(jiǎn)單有效的方法。
4,減少GC
Full GC對Java服務(wù)器性能的影響是致命的,特別是當JVM管理著(zhù)較大內存時(shí)。即使是在小型應用,例如Old區只分配512M內存,一次Full GC都可能耗時(shí)2~3秒,這意味著(zhù)你所有的服務(wù)都會(huì )中斷。盡量減少Full GC的次數絕對是我們的目標。
首先,合理的配置GC參數,采用ParallelGC和 ConcMarkSweepGC,即并發(fā)和增量GC。CMS,全稱(chēng)Concurrent Low Pause Collector,CMS用兩次短暫停來(lái)替代串行標記整理算法的長(cháng)暫停。
第二,打出GC log,在性能測試階段,檢查你的GC是否OK。系統在線(xiàn)測試時(shí)也可以提供寶貴的track。
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
給出一個(gè)實(shí)際服務(wù)器GC參數為例,
1
JAVA_OPTS=" -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+DisableExplicitGC
2
JAVA_OPTS=" -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=8
3
JAVA_OPTS="-Xms256m -Xmx640m -XX:NewSize=128m -XX:MaxNewSize=256m -Xss128k
4
JAVA_OPTS=" -XX:PermSize=64m -XX:MaxPermSize=128m
5
JAVA_OPTS=" -XX:SurvivorRatio=14 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=16
5,數據庫前Cache
用queue緩存數據,一次寫(xiě)入多個(gè)數據??梢杂枚鄠€(gè)線(xiàn)程同時(shí)寫(xiě)入數據庫。在實(shí)際系統中,用多個(gè)線(xiàn)程同時(shí)讀取cache并寫(xiě)入Mysql是效率很高的。
6,增加數據庫索引
看起來(lái)很弱對吧?可是我真的遇到過(guò)靠加個(gè)簡(jiǎn)單的索引解決過(guò)一個(gè)很?chē)乐氐男阅軉?wèn)題。系統瓶頸的多數問(wèn)題都存在于數據庫和線(xiàn)程的使用不當上,所以還是要強調一下。
7,Master-Slave Mysql
Mysql有一篇很有名的文章來(lái)解釋在Master-Slave結構下提高讀效率的文章。大致就是說(shuō)Mysql基準測試下max_read=1200次/s。在讀寫(xiě)比例為9:1的情況下,通常寫(xiě)的時(shí)間比讀的時(shí)間多一倍。假設有N個(gè)slave,如果只用slave來(lái)讀,公式如下:
Max reads = 1200 – 2 * writes
Max Reads = 9 * writes / (N + 1) (讀為9倍的寫(xiě),平均到N+1個(gè)Mysql上)
9 * writes / (N + 1) + 2 *writes = 1200
Writes = 1200/ (2 + 9/(N+1))
結論是N=1,每秒增加到184次寫(xiě)
N = 8,增加到400次寫(xiě)
其中需要考慮的是復制多份binlog所占的網(wǎng)絡(luò )帶寬和對Master Mysql的影響。但我們在實(shí)際應用中認為mysql master-slave binlog增量同步是非常迅速且沒(méi)有察覺(jué)到對性能的負面影響。但一般來(lái)說(shuō),既然memcached可以很好解決read問(wèn)題,很少有team做這么大規模的mysql cluster。但小于等于4個(gè)還是可以考慮的。
總結,合理的使用異步通信,線(xiàn)程調度,優(yōu)化GC和解決數據庫瓶頸往往可以是構建高性能高并發(fā)Java消息處理服務(wù)器的利器。但這僅限于邏輯業(yè)務(wù)相對簡(jiǎn)單的即時(shí)通信系統,如果是設計大量cache調度,比如網(wǎng)頁(yè)調度?;蛘呤窃O計海量數據處理服務(wù)器,則需要考慮更多的問(wèn)題。
本文純屬原創(chuàng ),基于實(shí)際系統經(jīng)驗,歡迎轉載,請注明原網(wǎng)址;
我的新浪博客:http://blog.sina.com.cn/u/1793692835
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。