1. 程式人生 > >Java架構師之效能調優

Java架構師之效能調優

一個用Java寫的GUI程式,作用是分析日誌, 它會將一定數量的格式相同的文字日誌檔案讀入記憶體分析處理,然後將結果合併輸出。
這裡寫圖片描述
檔案數量幾十個,檔案大小几KB, 日誌記錄幾千條左右, 此工具可以流暢處理, 輕鬆滿足需求。

然而, 因為記錄日誌的方案調整,記錄日誌類型範圍從warn、error級別擴大到了連info、debug級別的日誌也要記錄,從而導致了日誌量激增, 固定時間範圍內產生的日誌檔案增加到了幾百個, 單個大小也增加到幾M,日誌記錄一下子達到幾十萬條,然後工具就跑的跟蝸牛一樣慢, 幾十秒才能出結果。

要繼續使用這個工具,自然需要優化,要優化則需要定位效能瓶頸在哪裡。 這個工具不復雜,沒有複雜的計算, 也沒有無謂的執行損耗, 最可能導致問題的地方是檔案內容讀取的I/O開銷,可是以Java的能耐,從幾百個檔案中讀取幾百M內容, 沒有可能需要幾十秒時間。 而且為了提升速度我還使用了多執行緒處理,使用執行緒池為每個日誌檔案的讀取和處理分配一個執行緒,於是我以此處為中心開始分析問題所在,直覺上, 執行緒的使用總是容易和效能問題聯絡在一起。

因為使用

Executors.newCachedThreadPool()

建立我所使用的執行緒池,而使用這個執行緒池太過於潦草, 它沒有大小限制,為每個日誌檔案的處理分配一個執行緒,假如有100個檔案需要處理, 那麼執行緒池就會建立100個執行緒, 而我的機器CPU只有4核心,顯然這100個執行緒無法被同時執行,而且還增加了執行緒之間切換的開銷,所以懷疑這是導致效能問題的原因之一。

從相關網路資料中得知,最佳執行緒數目可通過以下公式確定

最佳執行緒數目 = ((執行緒等待時間+執行緒CPU時間)/執行緒CPU時間 )* CPU數目

顯然,公式中所有變數除了CPU數目, 其它一概不知,所以我採用了另外一個簡單粗暴的公式

執行緒資料 = 2 * CPU核心數 + 1

這是I/O密集型程式的計算公式。因為這個工具需要頻繁讀取磁碟檔案,所以我將他定位為I/O密集型

ExecutorServiceexecutorService=Executors.newFixedThreadPool(9);

通過使用有數量限制的執行緒池對程式進行改進後,執行速度似乎有所改善, 可是對於讓程式以可以接受的速度執行而言卻是杯水車薪。當然,我本來也對此改進沒有抱多大希望,因為上百個執行緒的切換不可能要花幾十秒。

我知道程式存在問題, 可對於一個沒有問題的程式在正常情況下處理這些日誌檔案需要花多少時間沒有一個明確的概念,所以並沒有充足的信心確定程式出問題的模組所在,只能沒有證據的猜測, 因此不能迅速的定位問題所在。

可能是直覺的將效能與併發和執行緒掛鉤,因此接下來的優化仍舊以這個主題進行。

我決定將日誌檔案的讀取與處理分開,讀取檔案使用一個執行緒, 日誌資料處理使用一個執行緒, 讀取檔案的執行緒將讀取的內容存入一個阻塞佇列,資料處理響執行緒從阻塞佇列中讀取資料進行處理,這是典型的生產消費模式。

費了很大力氣實現這個模式,信心滿滿的以為程式的執行速度會有所改善,然而,出乎意料的程式執行的速度非但沒有改善,而且比以前更加緩慢了,並且伴隨卡死的現象, 我很沮喪, 可不得不承認,效能瓶頸不在併發處理上,朝這個方向優化永遠不能解決問題,高大上的併發技能在這裡毫無用武之地。

我意識必須不斷縮小問題範圍,精確定位到問題程式碼所在,才能啃掉這塊骨頭。

我雖然懷疑效能瓶頸在檔案讀取上,可並沒有明確證據, 必須需要一個明確的資料指標才行。

我在程式的關鍵部位加上除錯程式碼,計算執行各個環節所需要的時間,從資料中明確得知,大部分時間的確被檔案讀取佔用了。

我定位到最接近檔案的程式碼,一個從其它專案中拷貝過來的方法

publicstaticStringreadStringFromFile(Filefile){

try{

if(file.isFile()&&file.exists()){

InputStreamReaderread=newInputStreamReader(newFileInputStream(file),"UTF-8");

BufferedReaderbufferedReader=newBufferedReader(read);

StringlineTxt=bufferedReader.readLine();

Stringresult="";

while(lineTxt!=null){

result+=lineTxt;

lineTxt=bufferedReader.readLine();

}

returnresult;

}

}catch(IOExceptione){

e.printStackTrace();

}

returnnull;

}

這個方法似乎沒什麼毛病, 還使用 BufferedReader 來提升效能,我百思不得其解,並開始推測問題所在。

程式是逐行讀去內容的,問題會不會出現在這裡?

如果一次性讀取整個檔案的內容速度會不會快一點?

正思考間,目光被一行程式碼吸引

result+=lineTxt;

然後靈光一現,一個程式設計概念再我腦海中閃現:String型別是執行緒安全的,狀態不可變, 每次操作都會複製一個自身的副本,因此效能很低,在頻繁拼接字串的情況下, 應該以StringBuffer或者StringBuilder代替String。

幾百個日誌檔案, 幾十萬條日誌記錄,即使一行一條記錄, Java虛擬機器也執行了幾十萬次的字串的拷貝,速度慢是必然的。

確定問題所在,改進就很容易了,我用StringBuilder類替代String進行字串處理

publicstaticStringreadStringFromFile(Filefile){

try{

if(file.isFile()&&file.exists()){

InputStreamReaderread=newInputStreamReader(newFileInputStream(file),"UTF-8");

BufferedReaderbufferedReader=newBufferedReader(read);

StringlineTxt=bufferedReader.readLine();

StringBuilderresult=newStringBuilder();

while(lineTxt!=null){

result.append(lineTxt);

lineTxt=bufferedReader.readLine();

}

returnresult.toString();

}

}catch(IOExceptione){

e.printStackTrace();

}

returnnull;

}

程式執行速度提升驚人,之前幾十秒才能出的結果,現在不到一秒就完成,問題迎刃而解。 至於為什麼不用StringBuffer是因為StringBuffer是StringBuffer的併發安全版本,效能略微不及StringBuider,而這裡不存在併發處理問題,因此自然選著效能更優的StringBuilder。

只改三行程式碼就能解決的問題卻令我折騰了半天, 究其原因在於以下原因

  1. 思路先入為主, 總是把效能問題和併發掛上鉤,利用多執行緒處理優化
  2. 憑直覺判斷問題形成的原因,沒有確切的依據, 致使優化方向錯誤

很多情況下, 程式效能問題跟併發處理無關, 當一個程式執行緩慢時, 並不會因為多加幾個執行緒處理就會變的很快,真正引起問題的原因往往出人意料,而且極有可能是非常低階的問題, 排除掉這些問題所在,保證程式碼健康,如果效能問題依舊存在, 再使用併發手段去解決不遲。

再者,優化程式效能必須確定造成效能問題的程式碼塊所在,不能評直覺判斷, 否者不但解決不了問題,還浪費時間。

想要學習瞭解以上技術加群【Java高階架構進階群】:854180697;本群提供免費的學習指導,架構資料以及免費的解答,不懂得問題都可以在本群提出來,之後還會有職業生涯規劃以及面試指導;進群修改群備註:開發年限-地區-經驗,方便架構師解答問題

寫在最後:歡迎留言討論,歡迎關注,持續更新!

相關推薦

Java架構效能調

一個用Java寫的GUI程式,作用是分析日誌, 它會將一定數量的格式相同的文字日誌檔案讀入記憶體分析處理,然後將結果合併輸出。 檔案數量幾十個,檔案大小几KB, 日誌記錄幾千條左右, 此工具可以流暢處理, 輕鬆滿足需求。 然而, 因為記錄日誌的方案調整,

JAVA架構路----maven001---何為Maven

maven本人犯了猴子掰玉米的錯誤;現在從頭開始:成功=可行的計劃+執行力何為Maven?答:1>關鍵字:構建、依賴、項目信息、解決方案/gav、誇平臺、開源/apache、分布式開發集群式部署、本地倉庫、遠程倉庫、中央倉庫、私服/nexus、插件;2>2個url:http://mvnreposi

劍指架構系列-MySQL調

日期轉換 存在 重復 mysq 更新 unique mps 方便 like 介紹MySQL的調優手段,主要包括慢日誌查詢分析與Explain查詢分析SQL執行計劃 1、MySQL優化 1、慢日誌查詢分析 首先需要對慢日誌進行一些設置,如下: SHOW VARIAB

Spark效能調總結(一)

總結一下spark的調優方案: 一、效能調優   1、效能上的調優主要注重一下幾點:     Excutor的數量     每個Excutor所分配的CPU的數量     每個Excutor所能分配的記憶體量     Driver端分配的記憶體數量   2、如何分配資源     在生產環境中,

大資料效能調方面(資料傾斜、shuffle、JVM等方面)

一、對於資料傾斜的發生一般都是一個key對應的資料過大,而導致Task執行過慢,或者記憶體溢位(OOM),一般是發生在shuffle的時候,比如reduceByKey,groupByKey,sortByKey等,容易產生資料傾斜。 那麼針對資料傾斜我們如何解決呢?我們可以首先觀看log日誌,以為log日誌報

Spark調效能調

1.1分配更多資源 1.1.1 分配哪些資源 Executor的數量 每個Executor所能分配的CPU數量 每個Executor所能分配的記憶體量 Driver端分配的記憶體數量 1.1.2 在哪裡分配這些資源 在生產環境中,提交spark作業時,用的spark-subm

Java架構旅(五)

夜光序言: 世人辱亦棄你 餘他信亦護你 便值重踏塵泥。       正文:Java高併發場景的資料隔離方案  

Java架構旅(四)

夜光序言: 畫工須畫雲中龍,為人須為人中雄~~         正文:Java分散式Session專案處理方案 如果我們用eclipse就需要安裝STS外掛,這個有很多配置方法嗯~ 提供一種方案:H

Java架構旅(三)

夜光序言: 最痛苦的是,消失了的東西,它就永遠的不見了,永遠都不會再回來,卻偏還要留下一根細而尖的針,一直插在你心頭,一直拔不去,它想讓你疼,你就得疼     正文:JAVATomcat企業級學習 搞清楚tomcat架構/ 具體的處理流程~~

Java架構旅(二)

夜光序言: 裝逼是什麼,就是看見野花不摘,欣賞;什麼是衝動,就是見花就摘,然後沒地擱;男人是什麼,那是眼睛裡根本就沒有野花,全是果~         正文:Java企業級高併發  

Java架構旅(一)

夜光序言:   如果世界和你,都掉進了河裡,我一定先救你,然後忘記世界的呼吸~       正文: MVC框架的演變   我們安裝這個外掛解決沒有tomcat的問題,因為targ

深入理解java虛擬機器JVM調配置

轉載文章:http://blog.csdn.net/sivyer123/article/details/17139443 堆記憶體設定 原理 JVM堆記憶體分為2塊:Permanent Space 和 Heap Space。 Permanent 即 持久代(Pe

2018年java架構分散式效能優化 附帶原始碼

下載地址:百度網盤下載 教程內容:第1章STL實用入門教程第2章C++編碼規範第3章GDIGDI+從入門到精通第4章COM實用入門教程第5章Windows視窗高階程式設計第6章Boost深入剖析之使用技巧第7章VC++實戰除錯技巧第8章靜態庫與動態庫程式設計第9章面向物件實踐程式設計第10章檔案打包技術詳解

Java架構

Java架構師之旅一:MVC框架的演變 Java架構師之旅二:Java企業級高併發 Java架構師之旅三:JAVATomcat企業級學習 Java架構師之旅四:Java分散式Session專案處理方案 Java架構師之旅五:Java高併發場景的資料隔離方案 Java架構師之旅六:

JAVA架構路-視訊學習

https://pan.baidu.com/s/1GK-HNdG_HsNTb_QQ6_L3Tg 目錄: 第一套 JAVA高階架構師之旅     第2套 Java網際網路架構師netty、mina、nio 第三套 阿里開源Dubbo

2019最新 高階JAVA架構路教程

課程目錄:01.Svn版本管理與程式碼上線架構方案03.深入JVM核心—原理、診斷與優化04.基於Netty的RPC架構實戰演練05.Git分散式版本控制系統權威指南06.Redis從入門到精通、叢集與應用07.大資料Hadoop Storm Hive等系列教程08.淘淘商城實戰高併發分散式專案(有

solr研磨效能調

  作者:戰鬥民族就是幹    轉載請註明地址:http://www.cnblogs.com/prayers/p/8982141.html   本篇文章我們來了解一下solr的效能方面的調優,分為Schema優化、索引更新與提交調優、索引合併效能調優、Solr快取、Solr查詢效能優化 Schema優化 1

java架構路:JAVA程式設計師必看的15本書的電子版下載地址

作為Java程式設計師來說,最痛苦的事情莫過於可以選擇的範圍太廣,可以讀的書太多,往往容易無所適從。我想就我自己讀過的技術書籍中挑選出來一些,按照學習的先後順序,推薦給大家,特別是那些想不斷提高自己技術水平的Java程式設計師們。以下書籍電子版下載地址:http://u.i

React Native 痛點解析效能調

自從React Native出世,雖然官方一直儘可能的優化其效能,為了能讓其媲美原生App的速度,但是現實感覺有點不盡人意。接下來介紹下實踐中遇到的一些效能問題以及優化方案。以下對效能引數的依據是來自於React Native自帶的FPS Monitor. 1. Nav

JAVA進階架構指南】五:JVM效能調

## 前言   首先給大家說聲對不起,最近屬實太忙了,白天上班,晚上加班,回家還要收拾家裡,基本每天做完所有事兒都是凌晨一兩點了,沒有精力再搞其他的了.   好了,進入正題,讓我們來聊聊JVM篇最後一個章節----JVM效能調優.童鞋們隨便開啟一個大廠的招聘崗位JD,應該都會有JVM調優相關的描述,其實招