1. 程式人生 > >效能調優,程式設計師轉型架構師的攔路虎【3】

效能調優,程式設計師轉型架構師的攔路虎【3】

效能調優系列前序文章索引:

  • 程式設計師必須掌握的效能調優:老兵哥結合個人經歷解釋了程式設計師往架構師方向發展時為什麼要跨越效能調優這一關,以及介紹了從 X、Y、Z 三個維度優化效能的思路。
  • 從  X  維度優化系統的效能:老兵哥分享了從 X 維度優化系統性能的思路,包括讓客戶端分計算儲存任務、優化互動設計等,主要是作為引子拓寬我們效能調優的思路。
  • 應用容器 Tomcat 效能調優:Y 維度就是從業務 HTTP 請求的橫向處理流程來看,HTTP 請求會穿越網路、計算機、應用容器(Tomcat)、Spring、ORM(Hibernate)、資料庫等節點,在這個流程中每個節點都有許多可以可優化的地方,此文主要介紹通過優化應用容器(Tomcat)來優化系統性能的方法。

程式設計師在轉型架構師的過程中需要建立流程化、結構化、系統化的思維方式,而效能調優是非常難得的契機,它既給了我們壓力,也給了我們動力,跨越它就是突破自己的過程。

  • X 維度,即業務維度,技術始終是服務業務的,任何技術問題的原點就是業務需求。在啟動技術層面的效能優化之前,我們有必要先審視一下業務流程是否合理,互動設計上有沒有可以優化的空間等。
  • Y 維度,待業務維度優化完畢,接下來就是審視技術在實現當前業務流程或互動設計的全鏈路上有沒有可優化的地方,即 HTTP 請求處理全流程,從瀏覽器到應用容器,再到 Spring、Hibernate、資料庫等。
  • Z 維度,除了沿著 HTTP 請求的橫向鏈路,我們還要審視支援應用系統的縱向技術棧,從上到下包括 JVM、作業系統和硬體等,這是整套應用系統執行的環境,許多效能問題都跟執行環境存在關係。

今天老兵哥將介紹通過優化開發框架 Spring 來優化系統性能的方法。

3. 開發框架 Spring

3.1 事務管理

事務(Transaction),是併發控制的基本單位,是使用者定義的一個操作序列。這些操作要麼都做,要麼都不做,是一個不可分割的工作單位。通過使用事務控制,我們可以極大地避免邏輯處理失敗導致的髒資料等問題。事務具有 4 個屬性:原子性、一致性、隔離性、永續性等,這四個屬性通常稱為 ACID 特性。

  • 原子性(Atomicity),一個事務是一個不可分割的工作單位,事務包含的操作要麼都做、要麼都不做。
  • 一致性(Consistency),事務必須讓資料庫從一個一致性狀態變到另一個一致性狀態,不能出現不一致。
  • 隔離性(Isolation),一個事務的執行不能被其他事務干擾,即一個事務內部的操作及使用的資料對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。
  • 永續性(Durability),永續性也稱永久性,指一個事務一旦提交,它對資料庫中資料的改變是永久性的,接下來的其他操作或故障不應該對其有任何影響。

Spring 事務管理是通過 XML 檔案或註解 @Transactional 配置的,其背後是靜態代理或動態代理等技術。在代理模式下,那些從代理傳遞傳過來的“外部”方法呼叫會被攔截,但“自我呼叫”是不會觸發事務的。例如,在目標物件中呼叫自身其他方法的方法是不會觸發事務的,即使被呼叫的方法標記為 @Transactional。

通常,我們很少關注 Spring 事務管理相關的屬性,但這些屬性的取值會影響系統的效能。Spring 事務管理最重要的兩個特性是:傳播級別、隔離級別。傳播級別,定義了事務的控制範圍;隔離級別,定義了事務在資料庫讀寫方面的控制範圍。我們知道,事務的控制範圍越大,系統的併發性就會越差,效能也就隨之降低。事務的隔離級別越高,系統的併發性也會越差,效能也會隨之下降。如果不瞭解這些屬性的取值規則,我們就不能選擇最合適的取值,不知不覺中就會浪費許多系統資源,接下來我們一起來看看這些屬性。

屬性型別描述
propagation 列舉型:Propagation 傳播級別,可選,預設值:PROPAGATION_REQUIRED
isolation 列舉型:Isolation 隔離級別,可選,預設值:ISOLATION_DEFAULT
readOnly 布林型 讀寫型事務、只讀型事務
timeout INT 型,以秒為單位 事務超時閾值
rollbackFor 一組 Class 類,必須是 Throwable 的子類 一組異常類,遇到時必須回滾。預設情況下 Checked Exceptions 不進行回滾,僅 Unchecked Exceptions(即 RuntimeException 的子類)才進行事務回滾。
rollbackForClassname 一組 Class 類的名字,必須是 Throwable 的子類 一組異常類名,遇到時必須回滾
noRollbackFor 一組 Class 類,必須是 Throwable 的子類 一組異常類,遇到時不需要回滾

Spring 事務管理的傳播級別 Propagation 取值有以下幾種: 

傳播級別說明備註
PROPAGATION_REQUIRED 如果上下文中已經存在事務,那麼就加入到事務中執行;如果上下文中不存在事務,則新建事務執行。 這個級別通常能滿足處理大多數的業務場景。
PROPAGATION_SUPPORTS 如果上下文中已經存在事務,則支援加入到事務中執行;如果上下文中不存在事務,則使用非事務的方式執行。 這個通常是用來處理那些並非原子性的非核心業務邏輯操作,應用場景較少。
PROPAGATION_MANDATORY 該級別的事務要求上下文中必須要存在事務,否則就會丟擲異常。這是避免上下文呼叫程式碼遺漏新增事務控制的保證手段。 例如某段程式碼不能被單獨呼叫執行,但是一旦被呼叫就必須要有事務包含,這種情況下就可以使用這個傳播級別。
PROPAGATION_REQUIRES_NEW 每次都會新建一個事務,並且同時將上下文中的事務掛起,執行當前新建事務完成以後,上下文事務恢復再執行。 問題1:如果某個子事務發生回滾,父事務是否回滾?答案是不會,因為子事務是新建事務,父事務已經被掛起,兩者不會受到影響。問題2:如果父事務發生回滾,子事務是否回滾?答案是不會,同樣的理由。但是可以手動控制,一旦子事務回滾,父事務也回滾。
PROPAGATION_NOT_SUPPORTED 如果上下文中已經存在事務,則掛起事務,執行當前邏輯,結束後恢復上下文的事務。 這個級別可以幫助你儘可能地縮小事務範圍。一個事務範圍越大,它存在的風險也就越多,例如某段程式碼是迴圈 1000 次的非核心業務邏輯操作,此類程式碼如果包在事務中,勢必導致事務太大,很容易出現些難以考慮周全的異常情況,此時這個級別就派上用場了。
PROPAGATION_NEVER 該級別要求上下文中不能存在事務,一旦有事務,就丟擲runtime異常,強制停止執行。

 傳播級別 PROPAGATION_REQUIRED 會為每一個被應用到的方法建立一個邏輯事務作用域。每一個邏輯事務作用域都可以自主地決定回滾條件,當這樣的邏輯事務作用域被外部邏輯事務作用域所包含時,它們在邏輯上是獨立的,但在實現層面它們會被對映到相同的物理事務上。

傳播級別 PROPAGATION_REQUIRES_NEW 為每一個相關的事務作用域使用了一個完全獨立的事務。在這種情況下,物理事務也將是不同的。因此,外部事務可以不受內部事務回滾狀態的影響獨立提交或者回滾。

Spring 事務管理的隔離級別 Isolation 取值有以下幾種:

隔離級別說明
Serializable 最嚴格的級別,事務序列執行,資源消耗最大。
Repeatable Read 保證了一個事務不會修改已經由另一個事務讀取但未提交(或回滾)的資料,避免了“髒讀取”和“不可重複讀取”的情況,但會帶來了更多的效能損耗。
Read Committed 大多數主流資料庫的預設事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的資料,避免了“髒讀取”,該級別適用於大多數系統。
Read Uncommitted 保證了讀取過程中不會讀取到非法資料。

上述說明中涉及的幾個專業術語:

  • 髒讀(Dirty Reads):就是讀到了別的事務回滾前的髒資料。例如,事務 B 執行過程中修改了資料 X,在未提交前,事務 A 讀取了 X,而事務 B 卻回滾了,這樣事務 A 就形成了髒讀。
  • 不可重複讀(Non-Repeatable Reads):不可重複讀字面含義已經很明確了。例如,事務 A 首先讀取了一條資料,然後執行邏輯的時候,事務 B 將這條資料改變了,然後事務 A 再次讀取的時候,發現數據不匹配了,這就是所謂的不可重複讀。
  • 幻讀(Phantom Reads):我們小時候數鴨子,第一次數是 10 個,第二次數是 11 個,怎麼回事,產生幻覺了?幻讀也是這樣子,事務 A 先根據條件索引到 10 條資料,然後事務 B 改變了資料庫一條資料,導致也符合事務 A 的搜尋條件,這樣事務 A 再次搜尋發現有 11 條資料了,這就產生了幻讀。
隔離級別與副作用髒讀不可重複讀幻讀
Serializable 不會 不會 不會
Repeatable Read 不會 不會
Read Committed 不會
Read Uncommitted

從上面這張對映表中,我們知道最安全的是 Serializable,但是伴隨而來的是高昂的效能開銷。各種傳播級別、隔離級別本身沒有好壞,關鍵是根據業務需求選擇最合適的取值,避免無效的效能損耗。另外,Spring 事務管理還有兩個常用屬性,它們的取值也會影響效能:

  • Readonly:只讀型事務要比讀寫型事務的效能更好,設定事務為只讀以提升效能。
  • Timeout:設定事務的超時時間,一般用於防止大事務的發生,事務要儘可能的小。

3.2 二級快取

快取作為提高應用系統性能的一種有效途徑,在事務管理配置不當的情況下,將很難發揮應有的效用。因此,在做快取處理或者其他處理,要考慮事務管理對效能的影響。

 

關注「 IT老兵哥 」,賦能程式人生!堅持原創不易,請小夥伴們不吝點個「 贊 」哦!推薦軟技能文章,請點選連結:程式設計師,怎樣打造個人影響力?

 

 

近期熱評系列《 程式設計師必須懂的架構師入門課 》:

  • 架構到底是什麼,你知道嗎? (閱讀人數:1201)
  • 架構都有哪些,我該怎麼選? (閱讀人數:886)
  • 架構師都幹什麼,你知道嗎? (閱讀人數:1178)
  • 練就哪些技能才勝任架構師? (閱讀人數:1145)
  • 怎樣才能搞定上下游的客戶? (閱讀人數:492)
  • 如何從開發崗轉型做架構師? (閱讀人數:1288)
  • 程式設計師必須懂的架構入門課    (閱讀人數:611)