天天看點

應用健康度隐患刨析解決系列之資料庫時區設定

作者:京東雲開發者

作者:京東零售 董方酉

引言

應用健康度是回報應用健康程度的名額,它将系統名額分類為基礎資源、容器、應用、報警配置、鍊路這幾項,收集了一系列系統應用的名額,并對名額進行打分。

應用健康度的每一項名額顯示着系統在某一方面可能存在的隐患和安全問題;是以提高應用健康度對于系統監控具有重要意義。知其然需知其是以然,了解應用健康度中的名額背後的隐患,對于我們了解和提升系統安全性很有幫助。

筆者作為後端研發工程師,同時在推動組内應用健康度提高的同時,基于遇到的問題現象,結合應用健康度進行剖析,将逐一總結一系列應用健康度隐患剖析;

第一篇,我們來剖析下容易被人忽視的資料庫時區設定項可能導緻的隐患。

一、應用健康度檢查項

資料庫連接配接池配置中,通過解析源代碼擷取,支援DBCP1.X,DBCP2.X,Ali Durid,HikariCP四種連接配接池;配置監測有以下幾項

應用健康度隐患刨析解決系列之資料庫時區設定

風險示例如下圖所示:

應用健康度隐患刨析解決系列之資料庫時區設定

connectTimeout 、SocketTimeout 和 時區 三個名額是連接配接池資料源的 url 中解析得到, 如:mysql://xxx.jd.com:3358/jdddddb_0?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&connectTimeout=1000&socketTimeout=3000&serverTimezone=Asia/Shanghai

其中,時區設定容易被人忽視;忽略設定會帶來什麼樣的隐患呢?

二、遇到的問題

1、現象

在2023年3月12日(3月的第二個周日),系統UMP監控報警,提示如下

應用健康度隐患刨析解決系列之資料庫時區設定

2、問題原因

Mysql 驅動:mysql-connector-java 更新到8版本後。将資料庫時間解析到java時間,需要擷取資料庫的時區。如果資料庫連接配接中指定時區,則會用該時區,否則可能會使用系統時區

可通過select @@time_zone語句查詢,如果傳回SYSTEM,則說明資料庫沒有設定時區,使用select @@system_time_zone 語句可查詢得出系統預設時區,為CST。

CST時區為美國中部時間,由于美國有夏令時和非夏令時

CST非夏令時對應 UTC-06:00,夏令時對應 UTC-05:00 。

美國的夏令時,從每年3月第2個星期天淩晨開始,到每年11月第1個星期天淩晨結束。

以2023年為例:

夏令時開始時間調整前:2023年03月12日星期日 02:00:00,時間向前撥一小時.

調整後:2023年03月12日星期日 03:00:00

夏令時結束時間調整前:2023年11月05日星期日 02:00:00,時間往回撥一小時.

調整後:2023年11月05日星期日 01:00:00

這意味這:CST沒有2023-03-12 02:00:00~2023-03-12 03:00:00 這個區間的時間。會有兩個 2023-11-05 01:00:00~2023-11-05 02:00:00區間的時間。

是以,在擷取資訊時會抛出“SQLException: HOUR_OF_DAY: 2 -> 3”異常。

3、修改方案

資料庫連接配接位址中設定資料時區:serverTimezone=Asia/Shanghai

三、時間相關的其他隐患

1、據研究實驗回報,設定時區為預設時可能有性能問題,往往需要指定時區。

2、使用timestamp類型時需注意時間偏差:

timestamp類型的時間範圍between '1970-01-01 00:00:01' and '2038-01-19 03:14:07',超出這個範圍則值記錄為'0000-00-00 00:00:00',該類型的一個重要特點就是儲存的時間與時區密切相關,UTC(Universal Time Coordinated)标準,指的是經度0度上的标準時間,大陸日常生活中時區以首都北京所處的東半球第8區為基準,統一使用東8區時間(俗稱中原標準時間),比UTC要早8個小時,時區設定也遵照此标準,是以對應過來timestamp的時間範圍則應校準為'1970-01-01 08:00:01' and '2038-01-19 11:14:07',也就是說東八區的1970-1-1 08:00:01等同于UTC1970-1-1 00:00:01。

3、盡量使用dateTime格式而非timestamp:

有一些情況需要注意不要使用 timestamp 存儲時間:

•生日:生日肯定會有早于1970年的,會超出 timestamp 的範圍

•有效期截止時間:timestamp 的最大時間是2038年,如果用來存類似身份證的有效期截止時間,營業執照的截止時間等就不合适。

•業務生存時間:網際網路時代發展快,業務時間很可能在2038年還在繼續營運。

四、資料庫連接配接設定的其他隐患

1、連接配接數設定

(1) 介紹

資料庫連接配接池在初始化時将建立一定數量的資料庫連接配接放到連接配接池中,這些資料庫連接配接的數量是由最小資料庫連接配接數制約。無論這些資料庫連接配接是否被使用,連接配接池都将一直保證至少擁有這麼多的連接配接數量。連接配接池的最大資料庫連接配接數量限定了這個連接配接池能占有的最大連接配接數,當應用程式向連接配接池請求的連接配接數超過最大連接配接數量時,這些請求将被加入到等待隊列中。

由此看來,當資料庫最大連接配接數設定不夠大時,則會出現某些報表或需要查詢資料庫的請求失敗,由于連接配接數不夠不能被處理,進而報錯。當出現大量并發的報表請求,且連接配接池的最大連接配接數不夠用時,一些使用者的請求就無法處理,這樣也就從另一個層面影響了整個項目處理吞吐量的能力,限制了項目的性能和效率。

(2)設定原則

既能保證項目正常使用時對資料庫連接配接數的要求,又能保護DBS的安全和穩定。

(3)查詢方式:

查詢最大連接配接數指令:show variables like'%max_connections%';

查詢目前資料庫已建立連接配接數:show status like 'Threads_connected';

(4)建議:

MYSQL官網給出了一個設定最大連接配接數的建議比例:

Max_used_connections / max_connections * 100% ≈ 85%
           

即已使用的連接配接數占總上限的85%左右。

2、逾時時間設定

(1)介紹

一次完整的請求包括三個階段:1、建立連接配接 2、資料傳輸 3、斷開連接配接

connect timeout:如果與伺服器(這裡指資料庫)請求建立連接配接的時間超過ConnectionTimeOut,就會抛 ConnectionTimeOutException,即伺服器連接配接逾時,沒有在規定的時間内建立連接配接。 在資料庫連接配接設定中,connectTimeout表示等待和MySQL資料庫建立socket連結的逾時時間,預設值0,表示不設定逾時,機關毫秒。

socket timeout:如果與伺服器連接配接成功,就開始資料傳輸了。如果伺服器處理資料用時過長,超過了SocketTimeOut,就會抛出SocketTimeOutExceptin,即伺服器響應逾時,伺服器沒有在規定的時間内傳回給用戶端資料。在資料庫連接配接設定中,socketTimeout表示用戶端和MySQL資料庫建立socket後,讀寫socket時的等待的逾時時間,linux系統預設的socketTimeout為30分鐘。

(2)隐患

通路資料庫逾時間太長,通路資料量大或者掃描的資料量太大,導緻資料庫長時間無響應。連結被占用無法釋放,會導緻線程池被占滿。是以,為了能夠及時釋放占用連結,其他業務對資料庫通路不受影響,是以要合理設定資料庫通路逾時時間。

JDBC的socket timeout在資料庫被突然停掉或是發生網絡錯誤(由于裝置故障等原因)時十分重要。由于TCP/IP的結構原因,socket沒有辦法探測到網絡錯誤,是以應用也無法主動發現資料庫連接配接斷開。如果沒有設定socket timeout的話,應用在資料庫傳回結果前會無期限地等下去,這種連接配接被稱為dead connection。

為了避免dead connections,socket必須要有逾時配置。socket timeout可以通過JDBC設定,socket timeout能夠避免應用在發生網絡錯誤時産生無休止等待的情況,縮短服務失效的時間。

(3)建議

一般情況,建議配置connectTimeout=60000,機關毫秒。建議配置socketTimeout=60000,機關毫秒。具體配置因系統而異。

總結

容易被忽視的資料庫連接配接應用健康度檢查項,背後有着時區、逾時時間、連接配接數設定不當可能帶來的隐患;根據應用實際情況并遵循設定原則進行合理設定,滿足應用健康度檢查項,才能防患于未然。