提高系統(tǒng)性能可以從幾個(gè)方面考慮
?1.JVM虛擬機(jī)配置
???? JEE容器中運(yùn)行的JVM參數(shù)配置參數(shù)的正確使用直接關(guān)系到整個(gè)系統(tǒng)的性能和處理能力
????? 1.1.HeapSize 堆的大小
????? 1.2.GarbageCollector 通過配置相關(guān)的參數(shù)進(jìn)行Java中的垃圾收集器的4個(gè)算法(策略)進(jìn)行使用剪返。
????? 1.3.StackSize 棧是JVM的內(nèi)存指令區(qū),每個(gè)線程都有他自己的Stack,Stack的大小限制著線程的數(shù)量泌辫。
?????? 1.4.DeBug/Log 在JVM中還可以設(shè)置對(duì)JVM運(yùn)行時(shí)的日志和JVM掛掉后的日志輸出随夸,這點(diǎn)非常的關(guān)鍵,根據(jù)各類JVM的日志輸出才能配置合適的參數(shù)震放。
2.JDBC
???? 針對(duì)MySQL的JDBC的參數(shù)在之前的文章中也有介紹過宾毒,在單臺(tái)機(jī)器或者集群的環(huán)境下合理的使用JDBC中的配置參數(shù)對(duì)操作數(shù)據(jù)庫也有很大的影響。 一些所謂高性能的 Java ORM開源框架也就是打開了很多JDBC中的默認(rèn)參數(shù):
???????2.1.例如:autoReconnect殿遂、prepStmtCacheSize诈铛、cachePrepStmts、useNewIO墨礁、blobSendChunkSize 等幢竹,
??????? 2.2例如集群環(huán)境下:roundRobinLoadBalance、failOverReadOnly恩静、autoReconnectForPools焕毫、secondsBeforeRetryMaster。 具體內(nèi)容可以參閱MySQL的JDBC官方使用手冊(cè): http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-jdbc-reference
3.數(shù)據(jù)庫連接池(DataSource)
????應(yīng)用程序與數(shù)據(jù)庫連接頻繁的交互會(huì)給系統(tǒng)帶來瓶頸和大量的開銷會(huì)影響到系統(tǒng)的性能驶乾,JDBC連接池負(fù)責(zé)分配邑飒、管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫連接级乐,而再不是重新建立一個(gè)連接疙咸,因此應(yīng)用程序不需要頻繁的與數(shù)據(jù)庫開關(guān)連接,并且可以釋放空閑時(shí)間超過最大空閑時(shí)間的數(shù)據(jù)庫連接來避免因?yàn)闆]有釋放數(shù)據(jù)庫連接而引起的數(shù)據(jù)庫連接遺漏风科。這項(xiàng)技術(shù)能明顯提高對(duì)數(shù)據(jù)庫操作的性能撒轮。
???? 在此我認(rèn)為有一點(diǎn)需要說明:
????? 連接池的使用也是需要關(guān)閉乞旦,因?yàn)樵跀?shù)據(jù)庫連接池啟動(dòng)的時(shí)候就預(yù)先和數(shù)據(jù)庫獲得了相應(yīng)的連接,之后不再需要應(yīng)用程序直接的和數(shù)據(jù)庫打交道题山,因?yàn)閼?yīng)用程序使用數(shù)據(jù)庫連接池是一個(gè)“借”的概念兰粉,應(yīng)用程序從數(shù)據(jù)庫連接池中獲得資源是“借出”,還需要還回去顶瞳,就好比有20個(gè)水桶放在這里亲桦,需要拿水的人都可以使用這些木桶從水池里面拿水,如果20個(gè)人都拿完水浊仆,不將水桶還回原地,那么后面來的人再需要拿水豫领,只能在旁邊等待有人將木桶還回去抡柿,之前的人用完后需要放回去,不然后面的人就會(huì)一直等待等恐,造成資源堵塞洲劣,同理,應(yīng)用程序獲取數(shù)據(jù)庫連接的時(shí)候Connection連接對(duì)象的時(shí)候是從“池”中分配一個(gè)數(shù)據(jù)庫連接出去课蔬,在使用完畢后囱稽,歸還這個(gè)數(shù)據(jù)庫連接,這樣才能保持?jǐn)?shù)據(jù)庫的連接“有借有還”準(zhǔn)則二跋。
????? 參考資料: http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-connection-pooling
?4.數(shù)據(jù)存取
??? 數(shù)據(jù)庫服務(wù)器的優(yōu)化和數(shù)據(jù)的存取战惊,什么類型的數(shù)據(jù)放在什么地方更好是值得去思考的問題,將來的存儲(chǔ)很可能是混用的扎即,Cache吞获,NOSQL,DFS谚鄙,??? DataBase 在一個(gè)系統(tǒng)中都會(huì)有各拷,生活的餐具和平日里穿衣服需要擺放在家里,但是不會(huì)用同一種類型的家具存放闷营,貌似沒有那個(gè)人家把餐具和衣服放在同一個(gè)柜子里面的烤黍。這就像是系統(tǒng)中不同類型的數(shù)據(jù)一樣,對(duì)不同類型的數(shù)據(jù)需要使用合適的存儲(chǔ)環(huán)境傻盟。文件和圖片的存儲(chǔ)速蕊,首先按照訪問的熱度分類,或者按照文件的大小莫杈。強(qiáng)關(guān)系類型并且需要事務(wù)支持的采用傳統(tǒng)的數(shù)據(jù)庫互例,弱關(guān)系型不需要事務(wù)支持的可以考慮NOSQL,海量文件存儲(chǔ)可以考慮一下支持網(wǎng)絡(luò)存儲(chǔ)的DFS筝闹,至于緩存要看你單個(gè)數(shù)據(jù)存儲(chǔ)的大小和讀寫的比例媳叨。
???? 還有一點(diǎn)值得注意就是數(shù)據(jù)讀寫分離腥光,無論在DataBase還是NOSQL的環(huán)境中大部分都是讀大于寫,因此在設(shè)計(jì)時(shí)還需考慮 不僅僅需要讓數(shù)據(jù)的讀分散在多臺(tái)機(jī)器上糊秆,還需要考慮多臺(tái)機(jī)器之間的數(shù)據(jù)一致性武福,MySQL的一主多從,在加上MySQL-Proxy或者借用JDBC中的一些參數(shù)(roundRobinLoadBalance痘番、failOverReadOnly捉片、autoReconnectForPools、secondsBeforeRetryMaster)對(duì)后續(xù)應(yīng)用程序開發(fā)汞舱,可以將讀和寫分離伍纫,將大量讀的壓力分散在多臺(tái)機(jī)器上,并且還保證了數(shù)據(jù)的一致性昂芜。
?5.緩存
??? ?在宏觀上看緩存一般分為2種:本地緩存和分布式緩存
??????5.1.本地緩存莹规,對(duì)于Java的本地緩存而言就是講數(shù)據(jù)放入靜態(tài)(static)的數(shù)據(jù)結(jié)合中,然后需要用的時(shí)候就從靜態(tài)數(shù)據(jù)結(jié)合中拿出來,對(duì)于高并發(fā)的環(huán)境建議使用 ConcurrentHashMap或者CopyOnWriteArrayList作為本地緩存泌神。緩存的使用更具體點(diǎn)說就是對(duì)系統(tǒng)內(nèi)存的使用良漱,使用多少內(nèi)存的資源需要有一個(gè)適當(dāng)比例,如果超過適當(dāng)?shù)氖褂么鎯?chǔ)訪問欢际,將會(huì)適得其反母市,導(dǎo)致整個(gè)系統(tǒng)的運(yùn)行效率低下。
???????5.2.分布式緩存损趋,一般用于分布式的環(huán)境患久,將每臺(tái)機(jī)器上的緩存進(jìn)行集中化的存儲(chǔ),并且不僅僅用于緩存的使用范疇浑槽,還可以作為分布式系統(tǒng)數(shù)據(jù)同步/傳輸?shù)囊环N手段墙杯,一般被使用最多的就是Memcached和Redis。 數(shù)據(jù)存儲(chǔ)在不同的介質(zhì)上讀/寫得到的效率是不同的括荡,在系統(tǒng)中如何善用緩存高镐,讓你的數(shù)據(jù)更靠近c(diǎn)pu,下面有一張圖你需要永遠(yuǎn)牢記在心里畸冲,來自Google的技術(shù)大牛Jeff Dean(Ref)的杰作
6.并發(fā)/多線程
?? ?在高并發(fā)環(huán)境下建議開發(fā)者使用JDK中自帶的并發(fā)包(java.util.concurrent)嫉髓,在JDK1.5以后使用java.util.concurrent下的工具類可以簡(jiǎn)化多線程開發(fā),在java.util.concurrent的工具中主要分為以下幾個(gè)主要部分:
??? ?6.1.線程池邑闲,線程池的接口(Executor算行、ExecutorService)與實(shí)現(xiàn)類(ThreadPoolExecutor、 ScheduledThreadPoolExecutor)苫耸,利用jdk自帶的線程池框架可以管理任務(wù)的排隊(duì)和安排州邢,并允許受控制的關(guān)閉。因?yàn)檫\(yùn)行一個(gè)線程需要消耗系統(tǒng)CPU資源褪子,而創(chuàng)建量淌、結(jié)束一個(gè)線程也對(duì)系統(tǒng)CPU資源有開銷骗村,使用線程池不僅僅可以有效的管理多線程的使用,還是可以提高線程的運(yùn)行效率呀枢。
??? ?6.2.本地隊(duì)列胚股,提供了高效的、可伸縮的裙秋、線程安全的非阻塞 FIFO 隊(duì)列琅拌。java.util.concurrent 中的五個(gè)實(shí)現(xiàn)都支持?jǐn)U展的 BlockingQueue 接口,該接口定義了 put 和 take 的阻塞版本:LinkedBlockingQueue摘刑、ArrayBlockingQueue进宝、SynchronousQueue、PriorityBlockingQueue 和 DelayQueue枷恕。這些不同的類覆蓋了生產(chǎn)者-使用者即彪、消息傳遞、并行任務(wù)執(zhí)行和相關(guān)并發(fā)設(shè)計(jì)的大多數(shù)常見使用的上下文活尊。
??? ?6.3.同步器,四個(gè)類可協(xié)助實(shí)現(xiàn)常見的專用同步語句漏益。Semaphore 是一個(gè)經(jīng)典的并發(fā)工具蛹锰。CountDownLatch 是一個(gè)極其簡(jiǎn)單但又極其常用的實(shí)用工具,用于在保持給定數(shù)目的信號(hào)绰疤、事件或條件前阻塞執(zhí)行铜犬。CyclicBarrier 是一個(gè)可重置的多路同步點(diǎn),在某些并行編程風(fēng)格中很有用轻庆。Exchanger 允許兩個(gè)線程在 collection 點(diǎn)交換對(duì)象癣猾,它在多流水線設(shè)計(jì)中是有用的。
??? ?6.4.并發(fā)包 Collection余爆,此包還提供了設(shè)計(jì)用于多線程上下文中的 Collection 實(shí)現(xiàn):ConcurrentHashMap纷宇、ConcurrentSkipListMap、ConcurrentSkipListSet蛾方、CopyOnWriteArrayList 和 CopyOnWriteArraySet像捶。當(dāng)期望許多線程訪問一個(gè)給定 collection 時(shí),ConcurrentHashMap 通常優(yōu)于同步的 HashMap桩砰,ConcurrentSkipListMap 通常優(yōu)于同步的 TreeMap拓春。當(dāng)期望的讀數(shù)和遍歷遠(yuǎn)遠(yuǎn)大于列表的更新數(shù)時(shí),CopyOnWriteArrayList 優(yōu)于同步的 ArrayList亚隅。
7.隊(duì)列
??? 關(guān)于隊(duì)列可以分為:本地的隊(duì)列 和 分布式隊(duì)列 2類
??? 本地隊(duì)列:一般常見的用于非及時(shí)性的數(shù)據(jù)批量寫入硼莽,可以將獲取的數(shù)據(jù)緩存在一個(gè)數(shù)組中等達(dá)到一定數(shù)量的時(shí)候在進(jìn)行批量的一次寫入,可以使用BlockingQueue或者List/Map來實(shí)現(xiàn)煮纵。
???? 相關(guān)資料:Sun Java API.
??? 分布式隊(duì)列:一般作為消息中間件懂鸵,構(gòu)建分布式環(huán)境下子系統(tǒng)與子系統(tǒng)之間通信的橋梁偏螺,JEE環(huán)境中使用最多的就是Apache的AvtiveMQ和Sun公司的OpenMQ。
??? ?輕量級(jí)的MQ中間件之前也向大家介紹過一些例如:Kestrel和Redis(Ref http://www.javabloger.com/article/mq-kestrel-redis-for-java.html)矾瑰,最近又聽說LinkedIn的搜索技術(shù)團(tuán)隊(duì)推出了一個(gè)MQ產(chǎn)品-kaukaf(Ref http://sna-projects.com/kafka )砖茸,對(duì)此保持關(guān)注。
??? 相關(guān)資料:
?? ?1.ActiveMQ http://activemq.apache.org/getting-started.html
???? 2.OpenMQ http://mq.java.net/about.html
??? ?3.Kafka http://sna-projects.com/kafka
??? 4.JMS文章 http://www.javabloger.com/article/category/jms
?8.NIO
??? NIO是在JDK1.4后的版本中出現(xiàn)的殴穴,在Java 1.4之前凉夯,Jdk提供的都是面向流的I/O系統(tǒng),例如讀/寫文件則是一次一個(gè)字節(jié)地處理數(shù)據(jù)采幌,一個(gè)輸入流產(chǎn)生一個(gè)字節(jié)的數(shù)據(jù)劲够,一個(gè)輸出流消費(fèi)一個(gè)字節(jié)的數(shù)據(jù), 面向流的I/O速度非常慢休傍,并且一個(gè)數(shù)據(jù)包要么整個(gè)數(shù)據(jù)報(bào)已經(jīng)收到征绎,要么還沒有。Java NIO非堵塞技術(shù)實(shí)際是采取Reactor模式磨取,有內(nèi)容進(jìn)來會(huì)自動(dòng)通知,不必死等人柿、死循環(huán),大大的提升了系統(tǒng)性能忙厌。在現(xiàn)實(shí)場(chǎng)景中NIO技術(shù)多數(shù)運(yùn)用兩個(gè)方面凫岖,1是文件的讀寫操作,2是網(wǎng)絡(luò)上數(shù)據(jù)流的操作逢净。在NIO中有幾個(gè)核心對(duì)象需要掌握:1選擇器(Selector)哥放、2通道(Channel)、3緩沖區(qū)(Buffer)爹土。
我的廢話:
1.在Java NIO的技術(shù)范疇中內(nèi)存映射文件是一種高效的做法甥雕,可以用于緩存中存儲(chǔ)的冷/熱數(shù)據(jù)分離,將緩存中的一部分冷數(shù)據(jù)進(jìn)行這樣的處理胀茵,這種做法上比常規(guī)的基于流或者基于通道的I/O快的多社露,通過使文件中的數(shù)據(jù)出現(xiàn)為內(nèi)存數(shù)組的內(nèi)容來完成的,將文件中實(shí)際讀取或者寫入的部分才會(huì)映射到內(nèi)存中琼娘,并不是將整個(gè)文件讀到內(nèi)存中呵哨。
?2.在Mysql的jdbc驅(qū)動(dòng)中也可以使用NIO技術(shù)對(duì)數(shù)據(jù)庫進(jìn)行操作來提升系統(tǒng)的性能。
9.從程序員開發(fā)角度
??? ?9.1.代碼程序執(zhí)行效率轨奄,正確實(shí)例化對(duì)象孟害,申明變量等,避免虛擬機(jī)內(nèi)存資源耗損
??? ?9.2.優(yōu)化sql挪拟,增加合適的索引挨务,正確書寫sql,使索引發(fā)揮正確的用處
?????9.3.java代碼開發(fā)死循環(huán)代碼,造成cpu達(dá)到100%谎柄,致使服務(wù)器宕機(jī)
長(zhǎng)連接/Servlet3.0
?這里說的長(zhǎng)連接就是長(zhǎng)輪詢丁侄,以前瀏覽器(客戶端)需要關(guān)注服務(wù)器端發(fā)生的數(shù)據(jù)變化需要不斷的訪問服務(wù)器,這樣客戶端的數(shù)量一多必然會(huì)給服務(wù)器端造成很大的壓力朝巫,例如:論壇中的站內(nèi)消息『枰。現(xiàn)在Servlet3.0規(guī)范中提供了一個(gè)新的特性:異步IO通信;該特性會(huì)保持一個(gè)長(zhǎng)連接劈猿。利用Servlet3異步請(qǐng)求的這項(xiàng)技術(shù)可以大大的緩解服務(wù)器端的壓力拙吉。
?Servlet3.0的原理就是將request的請(qǐng)求開啟一個(gè)線程掛起,中間設(shè)置等待超時(shí)的時(shí)間揪荣,如果后臺(tái)事件觸發(fā)request請(qǐng)求筷黔,得到的結(jié)果返回給客戶端的request請(qǐng)求,如果在設(shè)置等待超時(shí)的時(shí)間內(nèi)沒有任何事件發(fā)生也將請(qǐng)求返回給客戶端仗颈,客戶端將再次發(fā)起request請(qǐng)求佛舱,客戶端與服務(wù)器端的交互可以與此往復(fù)。
?就好比挨决,你先過來跟我說如果有人找你请祖,我就立馬通知你你來見他,原先你需要不斷的問我有沒有要找你脖祈,而不管有沒有人找你肆捕,你都需要不斷的問我有沒有人找你,這樣的話不論問的人還是被問的人都會(huì)累死撒犀。
日志
?Log4J是通常被人們使用的工具,系統(tǒng)在剛剛上線的時(shí)候日志一般都設(shè)置在INFO的級(jí)掏秩,真正上線后一般設(shè)置在ERROR級(jí)或舞,但無論在任何時(shí)候,日志的輸入內(nèi)容都是需要關(guān)注的蒙幻,開發(fā)人員一般可以依靠輸出的日志查找出現(xiàn)的問題或者依靠輸出的日志對(duì)系統(tǒng)的性能進(jìn)行優(yōu)化映凳,日志也是系統(tǒng)運(yùn)行狀態(tài)的報(bào)告和排錯(cuò)的依據(jù)。
?簡(jiǎn)單來說日志按照定義的不同策略和等級(jí)輸出到不同的環(huán)境邮破,那樣便于我們分析和管理诈豌。相反你沒有策略的輸出,那么機(jī)器一多抒和,時(shí)間一長(zhǎng)矫渔,會(huì)有一大推亂糟糟的日志,會(huì)讓你排錯(cuò)的時(shí)候無從下手摧莽,所以日志的輸出策略是使用日志的關(guān)鍵點(diǎn)庙洼。
?參考資料:http://logging.apache.org/log4j/1.2/manual.html
?打包/部署
在代碼設(shè)計(jì)的時(shí)候最好能將不同類型的功能模塊在IDE環(huán)境中粗粒度的分為不同的工程,便于打成不同jar包部署在不同的環(huán)境中。有這樣的一個(gè)應(yīng)用場(chǎng)景:需要每天定時(shí)遠(yuǎn)程從SP那邊獲得當(dāng)天100條新聞和部分城市的天氣預(yù)報(bào)油够,雖然每天的數(shù)據(jù)量不多蚁袭,但是前端訪問的并發(fā)量很大,顯然需要在系統(tǒng)架構(gòu)上做到讀寫分離石咬。
?如果把web工程和定時(shí)抓取的功能模塊完全集中在一個(gè)工程里打包揩悄,將導(dǎo)致需要擴(kuò)展的時(shí)候每臺(tái)機(jī)器上既有web應(yīng)用也有定時(shí)器,因?yàn)楣δ苣K沒有分開鬼悠,每臺(tái)機(jī)器上都有定時(shí)器工作將會(huì)造成數(shù)據(jù)庫里面的數(shù)據(jù)重復(fù)删性。
?如果開發(fā)的時(shí)候就將web和定時(shí)器分為2個(gè)工程,打包的時(shí)候就可以分開部署厦章,10臺(tái)web對(duì)應(yīng)一臺(tái)定期器镇匀,分解了前端請(qǐng)求的壓力,數(shù)據(jù)的寫入也不會(huì)重復(fù)袜啃。
這樣做的另一個(gè)好處就是可以共用汗侵,在上述的場(chǎng)景中web和定時(shí)器都需要對(duì)數(shù)據(jù)庫進(jìn)行讀取,那么web和定時(shí)器的工程里都有操作數(shù)據(jù)庫的代碼群发,在代碼的邏輯上還是感覺亂亂的晰韵。如果再抽出一個(gè)DAL層的jar,web和定時(shí)器的應(yīng)用模塊開發(fā)者只需要引用DAL層的jar熟妓,開發(fā)相關(guān)的業(yè)務(wù)邏輯雪猪,面向接口編程,無需考慮具體的數(shù)據(jù)庫操作起愈,具體的對(duì)數(shù)據(jù)庫操作由其他開發(fā)者完成只恨,可以在開發(fā)任務(wù)分工上很明確,并且互不干涉抬虽。
框架
?所謂流行的SSH(Struts/Spring/Hiberanet)輕量級(jí)框架,對(duì)于很多中小型項(xiàng)目而言一點(diǎn)都不輕量級(jí)官觅,開發(fā)者不僅需要維護(hù)代碼,還需要維護(hù)繁瑣的xml配置文件阐污,而且說不定某個(gè)配置文件寫的不對(duì)就讓整個(gè)都工程無法運(yùn)行休涤。無配置文件可以取代SSH(struts/Spring/Hiberanet)框架的產(chǎn)品真的太多了,我之前就向大家介紹過一些個(gè)產(chǎn)品(Ref)笛辟。
?這個(gè)我并不是一味的反對(duì)使用SSH(Struts/Spring/Hiberanet)框架功氨,在我眼里SSH框架真的作用是做到了規(guī)范開發(fā),而并不使用了SSH(Struts/Spring/Hiberanet)框架能提高多少性能手幢。
SSH框架只是對(duì)于非常大的項(xiàng)目人數(shù)上百人的團(tuán)隊(duì)捷凄,還需要、繼續(xù)增加團(tuán)隊(duì)規(guī)模的公司而言围来,是需要選擇一些市面上大家都認(rèn)可纵势,并且熟悉的技術(shù)踱阿,SSH(Struts/Spring/Hiberanet)框架比較成熟所以是首先產(chǎn)品。
?但是對(duì)于一些小團(tuán)隊(duì)中間有個(gè)把技術(shù)高人的團(tuán)隊(duì)而言完全可以選擇更加簡(jiǎn)潔的框架钦铁,真正的做到提速你的開發(fā)效率软舌,早日拋棄SSH框架選擇更簡(jiǎn)潔的技術(shù)在小團(tuán)隊(duì)開發(fā)中是一種比較明知的選擇。
?原文引自:http://blog.csdn.net/u010214269/article/details/50902474