玩轉Windows服務系列——Windows服務啟動超時時間


最近有客戶反映,機房出現斷電情況,服務器的系統重新啟動后,數據庫服務自啟動失敗。第一次遇到這種情況,為了查看是不是斷電情況導致數據庫文件損壞,從客戶的服務器拿到數據庫的日志,進行分析。

數據庫工作機制

要分析數據庫啟動失敗的原因,首先說明一下數據庫服務的工作機制。

數據庫分為六大服務:

數據庫六大服務

數據庫的六大服務之間存在依賴關系,及啟動流程:

數據庫啟動流程

服務自動啟動失敗原因

從客戶那里,拿到了兩份日志,一份是開機自啟動的日志信息,此次數據庫啟動失敗。另外一份是開機后,手動啟動數據庫服務的日志信息,此次數據庫啟動成功。

首先看第一份日志:

快照數據服務成功啟動

從日志中看到,快照數據服務已經成功啟動,但是沒有后續的日志信息,說明問題可能出在snapshot服務,或者下一個將要啟動的equation服務。而另外一份日志中看到所有的服務都成功啟動,並且正常運行,這就排除了服務器意外斷電導致文件損壞的可能。

數據庫可以通過手動的方式成功啟動,說明數據庫的文件信息都正確,但是第一啟動時卻只logger、historian、snapshot服務成功啟動,由於后續沒有日志輸出,很難分析問題的原因。

既然數據庫沒有相應的日志,那么就要通過系統日志來分析,此處需要尋求系統的事件日志的幫助。

在計算機管理中找到事件查看器,選擇系統,如下圖:

系統事件查看器

默認情況下,服務出現啟動失敗等異常時,操作系統會記錄一些系統事件。

從中可以看到如下信息:

snapshot 服務啟動時掛起
事件ID 7022

有事件ID與事件描述,谷歌之,但是沒有找到相應的解決方案,沒辦法,還是只能從數據庫日志來分析。

再次分析日志,看到這樣一種情況:

快照服務啟動耗時

snapshot服務從開始啟動,到啟動結束,共耗時兩分半,這個時間對於Windows服務的啟動來說,時間是很長了。根據此情況,以及系統事件的描述,推測,有可能是服務啟動超時。

為了驗證此推測,在數據庫服務啟動時加入一個Sleep(60000),這個時間足夠超時了。從服務管理器中啟動服務,過了一段時間后,服務啟動失敗,從事件查看器中,看到”服務啟動時掛起的消息”,由此基本上可以斷定數據庫服務是由於超時而啟動失敗的。

服務啟動超時原因

知道服務啟動失敗原因是超時導致的,還需要分析一下為什么開機自啟動的時候服務會啟動超時。

還是從日志開始,幸好日志中有詳細的輸出日志,從這些日志中,看到兩個耗時比較長的操作:

快照服務耗時比較長的操作

鎖定歷史數據緩存與鎖定歷史數據補寫緩存兩個操作,耗時分別在一分鍾左右,兩個操作一起占了啟動耗時的大部分時間,那么啟動超時就是由這兩個操作導致的。

既然這兩個操作比較耗時,那么他們在悄悄的做什么呢。這兩個操作實際是在鎖定物理內存,使其盡量不要交換到磁盤上,那么開機啟動后,所有的緩存數據還沒有加載到內存中,此時鎖定此內存,就會導致操作系統將此緩存數據從磁盤加載到內存中。看似復雜,實際就是操作系統在讀磁盤,而機械磁盤的讀取速度是有限並且非常慢的,當緩存文件很大時,純粹讀取磁盤的時間就要很長。而此案例中,兩個緩存文件都在15G左右,所以耗時也就比較長了。

由此分析下來,也就找到了服務啟動超時的原因了。

服務第二次啟動時順利啟動的原因分析

這還沒完,服務啟動超時的原因是知道了,但是為什么第二次啟動時,就可以順利啟動呢。接着分析。

再來看第二次啟動時的日志:

快照服務第二次啟動耗時

此日志中看到,第一次啟動中,每個占用耗時達到60秒的鎖定內存操作,此次只有3秒,可以說非常迅速了。

上面說到,鎖定內存實際是在讀取磁盤,而磁盤速度特別慢,15G的緩存文件,在3秒內讀取完,是根本不可能的。那么唯一的可能就是根本沒有讀取磁盤。

其實這是Windows的一個內存管理機制,內存映射文件在卸載的時候,並不會立即去釋放內存,釋放內存的時機是由操作系統來決定的。當snapshot服務在很短的時間內又重新加載此內存映射文件時,操作系統發現此內存映射文件還存放在內存中,那么就不會再加載了,因為讀取磁盤的速度實在是太慢了。而在開機啟動的時候,由於是第一次加載內存映射文件,內存中還不存在,就會讀取一次磁盤。所以這個鎖定內存的時間也就由第一啟動時的60秒變為3秒了。

設置Windows服務啟動超時時間

Windows系統的服務超時時間默認是30s,當一個服務的啟動時間超過這個時間后,服務管理器會認為服務存在異常,並視為啟動失敗,然后記錄一些系統事件信息。但是有時候這個時間是比較短的,比如我們的snapshot服務,這就需要修改注冊表來解決這個問題。注冊表項為HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/ServicesPipeTimeout,這個值有可能不存在,如果不存在需要添加。類型為DWORD,單位是毫秒。

當然,這個超時時間是對所有服務都有效的,修改這個值並不是最好的解決辦法。最好能在snapshot程序內部,對啟動時加載緩存流程進行優化,以縮短啟動時間,或者將耗時比較長的操作放到啟動后進行。

總結

  • 可以通過修改注冊表來修改Windows的服務啟動超時時間。
  • Windows的一個內存管理機制,內存映射文件在卸載的時候,並不會立即去釋放內存,釋放內存的時機是由操作系統來決定的。當程序在很短的時間內又重新加載此內存映射文件時,操作系統發現此內存映射文件還存放在內存中,那么就不會再加載了。

當然,還有最重要的一點,日志系統很重要,騷年,乖乖的給程序加日志去吧!

系列鏈接

玩轉Windows服務系列——創建Windows服務

玩轉Windows服務系列——Debug、Release版本的注冊和卸載,及其原理

玩轉Windows服務系列——無COM接口Windows服務啟動失敗原因及解決方案

玩轉Windows服務系列——服務運行、停止流程淺析

玩轉Windows服務系列——Windows服務小技巧

玩轉Windows服務系列——命令行管理Windows服務

玩轉Windows服務系列——Windows服務啟動超時時間

玩轉Windows服務系列——使用Boost.Application快速構建Windows服務

玩轉Windows服務系列——給Windows服務添加COM接口


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM