在任何微服務中,精確管理資料庫互動對於維護應用程式效能和可靠性至關重要 。通常,我們會在 效能測試時解決資料庫連線方面的奇怪問題。
最近, Spring 微服務應用程式的儲存庫層出現了一個關鍵問題,異常處理不當導致效能測試期間出現意外故障和服務中斷。
本文深入探討了該問題的具體情況,並強調了註釋的關鍵作用@Transactional,它解決了該問題。
Spring 微服務應用程式嚴重依賴穩定高效的資料庫互動,通常透過Java Persistence API (JPA)進行管理。正確管理資料庫連線,特別是防止連線洩漏,對於確保這些互動不會對應用程式效能產生負面影響至關重要。
問題背景
在最近一輪的效能測試中,我們的一個基本微服務中出現了一個關鍵問題,該微服務 被指定 用於傳送客戶端通訊。該服務開始出現重複的閘道器超時錯誤。根本問題根源在於我們在儲存庫層的資料庫操作。
對這些超時錯誤的調查表明儲存過程始終失敗。失敗 是 由傳遞給過程的無效引數觸發的,這引發了儲存過程的業務異常。儲存庫層沒有有效地處理這個異常;它冒泡了。下面是儲存過程呼叫的原始碼:
public long createInboxMessage(String notifCode, String acctId, String userId, String s3KeyName, |
問題分析
正如我們的場景所示,當儲存過程遇到錯誤時,產生的異常將從儲存庫層向上傳播到服務層,最後傳播到控制器。這種傳播是有問題的,導致我們的 API 以非 200 HTTP 狀態程式碼進行響應 - 通常為 500 或 400。在發生幾次此類事件後,服務容器達到了無法再處理傳入請求的程度,最終導致 502 閘道器超時錯誤。這種嚴重狀態反映在我們的監控系統中,Kibana 日誌表明了該問題:
“HikariPool-1 - 連線不可用,請求在 30000 毫秒後超時。”
問題在於異常處理不當,因為異常在系統層中不斷湧現,而沒有得到適當的管理。這會阻止將資料庫連線釋放回連線池,從而導致可用連線耗盡。因此,在耗盡所有連線後,容器無法處理新請求,導致Kibana 日誌中報告錯誤和非 200 HTTP 錯誤。
解決
為了解決這個問題,我們可以優雅地處理異常:
- 讓 JPA 和 Spring 上下文釋放池的連線。
- 另一種選擇是@Transactional對方法使用註釋。
下面是帶有註釋的相同方法:
@Transactional |
下面方法的實現演示了一種異常處理方法,透過在方法本身中捕獲和記錄異常,防止異常進一步向堆疊上層傳播:
public long createInboxMessage(String notifCode, String acctId, String userId, String s3KeyName, |
使用@Transactional
@TransactionalSpring 框架中的註釋管理事務邊界。它在帶註釋的方法啟動時開始事務,並在方法完成時提交或回滾事務。當發生異常時,@Transactional確保事務回滾,這有助於適當地將資料庫連線釋放回連線池。
如果沒有@Transactional
如果呼叫儲存過程的儲存庫方法 沒有使用@Transactional 註釋 ,Spring 不會管理該方法的事務邊界。 如果儲存過程丟擲異常,則必須手動實現事務處理。如果管理不當,可能會導致資料庫連線未關閉且未返回到池中,從而導致連線洩漏。
最佳實踐
- 當方法的操作應在事務範圍內執行時,應始終使用 @Transactional。這對於涉及儲存過程(可修改資料庫狀態)的操作尤為重要。
- 確保方法中的異常處理包括適當的事務回滾和關閉任何資料庫連線,主要是在不使用 @Transactional 時。
結論
有效的事務管理對於維護使用 JPA 的 Spring 微服務應用程式的健康和效能至關重要。透過使用 @Transactional 註解,我們可以防止連線洩漏,並確保資料庫互動不會降低應用程式的效能或穩定性。遵守這些準則可以提高 Spring 微服務的可靠性和效率,為消費應用程式或終端使用者提供穩定、響應迅速的服務。