應用伺服器出現錯誤的原因簡析

sqiutz發表於2010-03-11
磁碟已滿    導致系統無法正常執行的最可能的原因是磁碟已滿。一個好的網路管理員會密切關注磁碟的使用情況,隔一定的時間,就需要將磁碟上的一些負載轉存到備份儲存介質中(例如磁帶)。   日誌檔案會很快用光所有的磁碟空間。Web伺服器的日誌檔案、SQL*Net的日誌檔案、JDBC日誌檔案,以及應用程式伺服器日誌檔案均與記憶體洩漏有同等的危害。可以採取措施將日誌檔案儲存在與作業系統不同的檔案系統中。日誌檔案系統空間已滿時Web伺服器也會被掛起,但機器自身被掛起的機率已大大減低。   C指標錯誤   用C或C 編寫的程式,如Web伺服器API模組,有可能導致系統的崩潰,因為只要間接引用指標(即,訪問指向的記憶體)中出現一個錯誤,就會導致作業系統終止所有程式。另外,使用了糟糕的C指標的Java模擬量(analog)將訪問一個空的物件引用。Java中的空引用通常不會導致立刻退出JVM,但是前提是程式設計師能夠使用異常處理方法恰當地處理錯誤。在這方面,Java無需過多的關注,但使用 Java對可靠性進行額外的度量則會對效能產生一些負面影響。   記憶體洩漏   C/C 程式還可能產生另一個指標問題:丟失對已分配記憶體的引用。當記憶體是在子程式中被分配時,通常會出現這種問題,其結果是程式從子程式中返回時不會釋放記憶體。如此一來,對已分配的記憶體的引用就會丟失,只要作業系統還在執行中,則程式就會一直使用該記憶體。這樣的結果是,曾佔用更多的記憶體的程式會降低系統效能,直到機器完全停止工作,才會完全清空記憶體。   解決方案之一是使用程式碼分析工具(如Purify)對程式碼進行仔細分析,以找出可能出現的洩漏問題。但這種方法無法找到由其他原因引起的庫中的洩漏,因為庫的原始碼是不可用的。另一種方法是每隔一段時間,就清除並重啟程式。Apache的Web伺服器就會因這個原因建立和清除子程式。   雖然Java本身並無指標,但總的說來,與C程式相比, Java程式使用記憶體的情況更加糟糕。在Java中,物件被頻繁建立,而直到所有到物件的引用都消失時,垃圾回收程式才會釋放記憶體。即使執行了垃圾回收程式,也只會將記憶體還給虛擬機器VM,而不是還給作業系統。結果是:Java程式會用光給它們的所有堆,從不釋放。由於要儲存實時(Just In Time,JIT)編譯器產生的程式碼,Java程式的大小有時可能會膨脹為最大堆的數倍之巨。   還有一個問題,情況與此類似。從連線池分配一個資料庫連線,而無法將已分配的連線還回給連線池。一些連線池有活動計時器,在維持一段時間的靜止狀態之後,計時器會釋放掉資料庫連線,但這不足以緩解糟糕的程式碼快速洩漏資料庫連線所造成的資源浪費。   程式缺乏檔案描述符   如果已為一臺Web伺服器或其他關鍵程式分配了檔案描述符,但它卻需要更多的檔案描述符,則伺服器或程式會被掛起或報錯,直至得到了所需的檔案描述符為止。檔案描述符用來保持對開放檔案和開放套接字的跟蹤記錄,開放檔案和開放套接字是Web伺服器很關鍵的組成部分,其任務是將檔案複製到網路連線。預設時,大多數shell有64個檔案描述符,這意味著每個從shell啟動的程式可以同時開啟64個檔案和網路連線。大多數shell都有一個內嵌的 ulimit命令可以增加檔案描述符的數目。   執行緒死鎖   由多執行緒帶來的效能改善是以可靠性為代價的,主要是因為這樣有可能產生執行緒死鎖。執行緒死鎖時,第一個執行緒等待第二個執行緒釋放資源,而同時第二個執行緒又在等待第一個執行緒釋放資源。我們來想像這樣一種情形:在人行道上兩個人迎面相遇,為了給對方讓道,兩人同時向一側邁出一步,雙方無法通過,又同時向另一側邁出一步,這樣還是無法通過。雙方都以同樣的邁步方式堵住了對方的去路。假設這種情況一直持續下去,這樣就不難理解為何會發生死鎖現象了。   解決死鎖沒有簡單的方法,這是因為使執行緒產生這種問題是很具體的情況,而且往往有很高的負載。大多數軟體測試產生不了足夠多的負載,所以不可能暴露所有的執行緒錯誤。在每一種使用執行緒的語言中都存線上程死鎖問題。由於使用Java進行執行緒程式設計比使用C容易,所以 Java程式設計師中使用執行緒的人數更多,執行緒死鎖也就越來越普遍了。可以在Java程式碼中增加同步關鍵字的使用,這樣可以減少死鎖,但這樣做也會影響效能。如果負載過重,資料庫內部也有可能發生死鎖。   如果程式使用了永久鎖,比如鎖檔案,而且程式結束時沒有解除鎖狀態,則其他程式可能無法使用這種型別的鎖,既不能上鎖,也不能解除鎖。這會進一步導致系統不能正常工作。這時必須手動地解鎖。 伺服器超載   Netscape Web伺服器的每個連線都使用一個執行緒。Netscape Enterprise Web伺服器會線上程用完後掛起,而不為已存在的連線提供任何服務。如果有一種負載分佈機制可以檢測到伺服器沒有響應,則該伺服器上的負載就可以分佈到其它的 Web伺服器上,這可能會致使這些伺服器一個接一個地用光所有的執行緒。這樣一來,整個伺服器組都會被掛起。作業系統級別可能還在不斷地接收新的連線,而應用程式(Web伺服器)卻無法為這些連線提供服務。使用者可以在瀏覽器狀態行上看到connected(已連線)的提示訊息,但這以後什麼也不會發生。   解決問題的一種方法是將obj.conf引數RqThrottle的值設定為執行緒數目之下的某個數值,這樣如果越過 RqThrottle的值,就不會接收新的連線。那些不能連線的伺服器將會停止工作,而連線上的伺服器的響應速度則會變慢,但至少已連線的伺服器不會被掛起。這時,檔案描述符至少應當被設定為與執行緒的數目相同的數值,否則,檔案描述符將成為一個瓶頸。   資料庫中的臨時表不夠用   許多資料庫的臨時表(cursor)數目都是固定的,臨時表即保留查詢結果的記憶體區域。在臨時表中的資料都被讀取後,臨時表便會被釋放,但大量同時進行的查詢可能耗盡數目固定的所有臨時表。這時,其他的查詢就需要列隊等候,直到有臨時表被釋放時才能再繼續執行。   這是一個不容易被程式設計師發覺的問題,但會在負載測試時顯露出來。但可能對於資料庫管理員(DataBase Administrator,DBA)來說,這個問題十分明顯。   此外,還存在一些其他問題:設定的表空間不夠用、序號限制太低,這些都會導致表溢位錯誤。這些問題表明了一個好的DBA對用於生產的資料庫設定和效能進行定期檢查的重要性。而且,大多數資料庫廠商也提供了監控和建模工具以幫助解決這些問題。   另外,還有許多因素也極有可能導致Web站點無法工作。如:相關性、子網流量超載、糟糕的裝置驅動程式、硬體故障、包括錯誤檔案的萬用字元、無意間鎖住了關鍵的表。

相關文章