JVM
JEE容器中運行的JVM參數配置參數的正確使用直接關係到整個系統的性能和處理能力,JVM的調優主要是對內存管理方面的調優,優化的方向分爲如下4點:
1.HeapSize 堆的大小,也能夠說Java虛擬機使用內存的策略,這點是很是關鍵的。
2.GarbageCollector 經過配置相關的參數進行Java中的垃圾收集器的4個算法(策略)進行使用。
3.StackSize 棧是JVM的內存指令區,每一個線程都有他本身的Stack,Stack的大小限制着線程的數量。
4.DeBug/Log 在JVM中還能夠設置對JVM運行時的日誌和JVM掛掉後的日誌輸出,這點很是的關鍵,根據各種JVM的日誌輸出才能配置合適的參數。
網上隨處可見JVM的配置技巧,可是我仍是推薦閱讀Sun官方的2篇文章,能夠對配置參數的其所依然有一個瞭解
1.Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
2.Troubleshooting Guide for Java SE 6 with HotSpot VM http://www.oracle.com/technetwork/java/javase/index-137495.html
另外,我相信不是每一個人攻城師都是每天對着這些JVM參數的,若是你忘記了那些關鍵的參數你能夠輸入Java -X(大寫X)進行提示。html
JDBC
針對MySQL的JDBC的參數在以前的文章中也有介紹過,在單臺機器或者集羣的環境下合理的使用JDBC中的配置參數對操做數據庫也有很大的影響。
一些所謂高性能的 Java ORM開源框架也就是打開了不少JDBC中的默認參數:
1.例如:autoReconnect、prepStmtCacheSize、cachePrepStmts、useNewIO、blobSendChunkSize 等,
2.例如集羣環境下:roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster。 具體內容能夠參閱MySQL的JDBC官方使用手冊:
http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-jdbc-reference前端
數據庫鏈接池(DataSource)
應用程序與數據庫鏈接頻繁的交互會給系統帶來瓶頸和大量的開銷會影響到系統的性能,JDBC鏈接池負責分配、管理和釋放數據庫鏈接,它容許應用程序重複使用一個現有的數據庫鏈接,而再不是從新創建一個鏈接,所以應用程序不須要頻繁的與數據庫開關鏈接,而且能夠釋放空閒時間超過最大空閒時間的數據庫鏈接來避免由於沒有釋放數據庫鏈接而引發的數據庫鏈接遺漏。這項技術能明顯提升對數據庫操做的性能。
在此我認爲有一點須要說明:
鏈接池的使用也是須要關閉,由於在數據庫鏈接池啓動的時候就預先和數據庫得到了相應的鏈接,以後再也不須要應用程序直接的和數據庫打交道,由於應用程序使用數據庫鏈接池是一個「借」的概念,應用程序從數據庫鏈接池中得到資源是「借出」,還須要還回去,就比如有20個水桶放在這裏,須要拿水的人均可以使用這些木桶從水池裏面拿水,若是20我的都拿完水,不將水桶還回原地,那麼後面來的人再須要拿水,只能在旁邊等待有人將木桶還回去,以前的人用完後須要放回去,否則後面的人就會一直等待,形成資源堵塞,同理,應用程序獲取數據庫鏈接的時候Connection鏈接對象的時候是從「池」中分配一個數據庫鏈接出去,在使用完畢後,歸還這個數據庫鏈接,這樣才能保持數據庫的鏈接「有借有還」準則。
參考資料:
http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-connection-poolingjava
數據存取
數據庫服務器的優化和數據的存取,什麼類型的數據放在什麼地方更好是值得去思考的問題,未來的存儲極可能是混用的,Cache,NOSQL,DFS,DataBase 在一個系統中都會有,生活的餐具和平日裏穿衣服須要擺放在家裏,可是不會用同一種類型的傢俱存放,貌似沒有那我的家把餐具和衣服放在同一個櫃子裏面的。這就像是系統中不一樣類型的數據同樣,對不一樣類型的數據須要使用合適的存儲環境。文件和圖片的存儲,首先按照訪問的熱度分類,或者按照文件的大小。強關係類型而且須要事務支持的採用傳統的數據庫,弱關係型不須要事務支持的能夠考慮NOSQL,海量文件存儲能夠考慮一下支持網絡存儲的DFS,至於緩存要看你單個數據存儲的大小和讀寫的比例。
還有一點值得注意就是數據讀寫分離,不管在DataBase仍是NOSQL的環境中大部分都是讀大於寫,所以在設計時還需考慮 不只僅須要讓數據的讀分散在多臺機器上,還須要考慮多臺機器之間的數據一致性,MySQL的一主多從,在加上MySQL-Proxy或者借用JDBC中的一些參數(roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster)對後續應用程序開發,能夠將讀和寫分離,將大量讀的壓力分散在多臺機器上,而且還保證了數據的一致性。mysql
緩存
在宏觀上看緩存通常分爲2種:本地緩存和分佈式緩存
1.本地緩存,對於Java的本地緩存而言就是講數據放入靜態(static)的數據結合中,而後須要用的時候就從靜態數據結合中拿出來,對於高併發的環境建議使用 ConcurrentHashMap或者CopyOnWriteArrayList做爲本地緩存。緩存的使用更具體點說就是對系統內存的使用,使用多少內存的資源須要有一個適當比例,若是超過適當的使用存儲訪問,將會拔苗助長,致使整個系統的運行效率低下。
2. 分佈式緩存,通常用於分佈式的環境,將每臺機器上的緩存進行集中化的存儲,而且不只僅用於緩存的使用範疇,還能夠做爲分佈式系統數據同步/傳輸的一種手段,通常被使用最多的就是Memcached和Redis。
數據存儲在不一樣的介質上讀/寫獲得的效率是不一樣的,在系統中如何善用緩存,讓你的數據更靠近cpu,下面有一張圖你須要永遠牢記在內心,來自Google的技術大牛Jeff Dean(Ref)的傑做,如圖所示:
cache-speed
併發/多線程
在高併發環境下建議開發者使用JDK中自帶的併發包(java.util.concurrent),在JDK1.5之後使用java.util.concurrent下的工具類能夠簡化多線程開發,在java.util.concurrent的工具中主要分爲如下幾個主要部分:
1.線程池,線程池的接口(Executor、ExecutorService)與實現類(ThreadPoolExecutor、 ScheduledThreadPoolExecutor),利用jdk自帶的線程池框架能夠管理任務的排隊和安排,並容許受控制的關閉。由於運行一個線程須要消耗系統CPU資源,而建立、結束一個線程也對系統CPU資源有開銷,使用線程池不只僅能夠有效的管理多線程的使用,仍是能夠提升線程的運行效率。
2.本地隊列,提供了高效的、可伸縮的、線程安全的非阻塞 FIFO 隊列。java.util.concurrent 中的五個實現都支持擴展的 BlockingQueue 接口,該接口定義了 put 和 take 的阻塞版本:LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、PriorityBlockingQueue 和 DelayQueue。這些不一樣的類覆蓋了生產者-使用者、消息傳遞、並行任務執行和相關併發設計的大多數常見使用的上下文。
3.同步器,四個類可協助實現常見的專用同步語句。Semaphore 是一個經典的併發工具。CountDownLatch 是一個極其簡單但又極其經常使用的實用工具,用於在保持給定數目的信號、事件或條件前阻塞執行。CyclicBarrier 是一個可重置的多路同步點,在某些並行編程風格中頗有用。Exchanger 容許兩個線程在 collection 點交換對象,它在多流水線設計中是有用的。
4.併發包 Collection,此包還提供了設計用於多線程上下文中的 Collection 實現:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。當指望許多線程訪問一個給定 collection 時,ConcurrentHashMap 一般優於同步的 HashMap,ConcurrentSkipListMap 一般優於同步的 TreeMap。當指望的讀數和遍歷遠遠大於列表的更新數時,CopyOnWriteArrayList 優於同步的 ArrayList。web
隊列
關於隊列能夠分爲:本地的隊列 和 分佈式隊列 2類
本地隊列:通常常見的用於非及時性的數據批量寫入,能夠將獲取的數據緩存在一個數組中等達到必定數量的時候在進行批量的一次寫入,可使用BlockingQueue或者List/Map來實現。
相關資料:Sun Java API.
分佈式隊列:通常做爲消息中間件,構建分佈式環境下子系統與子系統之間通訊的橋樑,JEE環境中使用最多的就是Apache的AvtiveMQ和Sun公司的OpenMQ。
輕量級的MQ中間件以前也向你們介紹過一些例如:Kestrel和Redis(Ref http://www.javabloger.com/article/mq-kestrel-redis-for-java.html),最近又據說LinkedIn的搜索技術團隊推出了一個MQ產品-kaukaf(Ref http://sna-projects.com/kafka ),對此保持關注。
相關資料:
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/jmsredis
NIO NIO是在JDK1.4後的版本中出現的,在Java 1.4以前,Jdk提供的都是面向流的I/O系統,例如讀/寫文件則是一次一個字節地處理數據,一個輸入流產生一個字節的數據,一個輸出流消費一個字節的數據, 面向流的I/O速度很是慢,而且一個數據包要麼整個數據報已經收到,要麼尚未。Java NIO非堵塞技術實際是採起Reactor模式,有內容進來會自動通知,沒必要死等、死循環,大大的提高了系統性能。在現實場景中NIO技術多數運用兩個方面,1是文件的讀寫操做,2是網絡上數據流的操做。在NIO中有幾個核心對象須要掌握:1選擇器(Selector)、2通道(Channel)、3緩衝區(Buffer)。 個人廢話: 1.在Java NIO的技術範疇中內存映射文件是一種高效的作法,能夠用於緩存中存儲的冷/熱數據分離,將緩存中的一部分冷數據進行這樣的處理,這種作法上比常規的基於流或者基於通道的I/O快的多,經過使文件中的數據出現爲內存數組的內容來完成的,將文件中實際讀取或者寫入的部分纔會映射到內存中,並非將整個文件讀到內存中。 2.在Mysql的jdbc驅動中也可使用NIO技術對數據庫進行操做來提高系統的性能。算法
長鏈接/Servlet3.0 這裏說的長鏈接就是長輪詢,之前瀏覽器(客戶端)須要關注服務器端發生的數據變化須要不斷的訪問服務器,這樣客戶端的數量一多必然會給服務器端形成很大的壓力,例如:論壇中的站內消息。如今Servlet3.0規範中提供了一個新的特性:異步IO通訊;該特性會保持一個長鏈接。利用Servlet3異步請求的這項技術能夠大大的緩解服務器端的壓力。 Servlet3.0的原理就是將request的請求開啓一個線程掛起,中間設置等待超時的時間,若是後臺事件觸發request請求,獲得的結果返回給客戶端的request請求,若是在設置等待超時的時間內沒有任何事件發生也將請求返回給客戶端,客戶端將再次發起request請求,客戶端與服務器端的交互能夠與此往復。
就比如,你先過來跟我說若是有人找你,我就立馬通知你你來見他,原先你須要不斷的問我有沒有要找你,而無論有沒有人找你,你都須要不斷的問我有沒有人找你,這樣的話不論問的人仍是被問的人都會累死。sql
日誌
Log4J是一般被人們使用的工具,系統在剛剛上線的時候日誌通常都設置在INFO的級,真正上線後通常設置在ERROR級,但不管在任什麼時候候,日誌的輸入內容都是須要關注的,開發人員通常能夠依靠輸出的日誌查找出現的問題或者依靠輸出的日誌對系統的性能進行優化,日誌也是系統運行狀態的報告和排錯的依據。
簡單來講日誌按照定義的不一樣策略和等級輸出到不一樣的環境,那樣便於咱們分析和管理。相反你沒有策略的輸出,那麼機器一多,時間一長,會有一大推亂糟糟的日誌,會讓你排錯的時候無從下手,因此日誌的輸出策略是使用日誌的關鍵點。
參考資料:http://logging.apache.org/log4j/1.2/manual.html數據庫
打包/部署
在代碼設計的時候最好能將不一樣類型的功能模塊在IDE環境中粗粒度的分爲不一樣的工程,便於打成不一樣jar包部署在不一樣的環境中。有這樣的一個應用場景:須要天天定時遠程從SP那邊得到當天100條新聞和部分城市的天氣預報,雖然天天的數據量很少,可是前端訪問的併發量很大,顯然須要在系統架構上作到讀寫分離。
若是把web工程和定時抓取的功能模塊徹底集中在一個工程裏打包,將致使須要擴展的時候每臺機器上既有web應用也有定時器,由於功能模塊沒有分開,每臺機器上都有定時器工做將會形成數據庫裏面的數據重複。
若是開發的時候就將web和定時器分爲2個工程,打包的時候就能夠分開部署,10臺web對應一臺按期器,分解了前端請求的壓力,數據的寫入也不會重複。
這樣作的另外一個好處就是能夠共用,在上述的場景中web和定時器都須要對數據庫進行讀取,那麼web和定時器的工程裏都有操做數據庫的代碼,在代碼的邏輯上仍是感受亂亂的。若是再抽出一個DAL層的jar,web和定時器的應用模塊開發者只須要引用DAL層的jar,開發相關的業務邏輯,面向接口編程,無需考慮具體的數據庫操做,具體的對數據庫操做由其餘開發者完成,能夠在開發任務分工上很明確,而且互不干涉。apache
框架 所謂流行的SSH(Struts/Spring/Hiberanet)輕量級框架,對於不少中小型項目而言一點都不輕量級,開發者不只須要維護代碼,還須要維護繁瑣的xml配置文件,並且說不定某個配置文件寫的不對就讓整個都工程沒法運行。無配置文件能夠取代SSH(struts/Spring/Hiberanet)框架的產品真的太多了,我以前就向你們介紹過一些個產品(Ref)。 這個我並非一味的反對使用SSH(Struts/Spring/Hiberanet)框架,在我眼裏SSH框架真的做用是作到了規範開發,而並不使用了SSH(Struts/Spring/Hiberanet)框架能提升多少性能。 SSH框架只是對於很是大的項目人數上百人的團隊,還須要、繼續增長團隊規模的公司而言,是須要選擇一些市面上你們都承認,而且熟悉的技術,SSH(Struts/Spring/Hiberanet)框架比較成熟因此是首先產品。 可是對於一些小團隊中間有個把技術高人的團隊而言徹底能夠選擇更加簡潔的框架,真正的作到提速你的開發效率,早日拋棄SSH框架選擇更簡潔的技術在小團隊開發中是一種比較明知的選擇。