標籤:

那些年走過的OpenStack的坑(下)

OpenStack是由眾多內部組件和第三方軟體組成的龐大而複雜的分散式系統。各組件和第三方軟體都有自己不同的特點,如果不了解這些特點,很容易陷入坑中。

正是如此,作為openstack行業相關的工作者,不僅要學習openstack各組件、第三方軟體的功能,還要學習積累一些調試和排錯的方法,這樣在遇到問題時,才能臨危不亂,找准突破口,逐步找到問題所在。

本文列舉了雲途騰測試團隊在實際測試openstack過程中所遇到的7個奇葩問題以及針對這些問題的排查過程和解決辦法。在上一期中我們針對雲主機的一些問題進行了分享,在這一期的內容中,我們繼續針對服務層面進行討論,希望能對大家有所幫助!

問題現象:

在一次正常使用dashboard過程中發現頁面不響應了,刷新之後重定向到登錄界面。

輸入正確的用戶名和密碼,點擊「登錄」按鈕後頁面沒有響應,過了很長時間提示超時。

排查過程:

dashboard的正常工作,需要apache服務工作正常,排查後發現apache沒有問題。

登錄dashboard,需要驗證用戶名和密碼,這依賴於keystone以及資料庫,排查後發現這兩個也沒有有問題。

但是在keystone的日誌中顯示連接不到rabbitmqserver。

rabbitmq是openstack中主流的消息隊列系統,作為openstack組件內的消息載體,幫助完成openstack當中的rpc調用,對openstack至關重要。

一般來說,keystone不會與rabbitmq打交道,但是有一種情況是,在keystone中配置notification_driver = messaging,可以讓keystone發送notification到ceilometer,用於計費,這時候就需要用到rabbitmq了,如果rabbitmq異常,則keystone也會受到影響,造成dashboard無法訪問。

檢查rabbitmq服務,發現它確實down掉了。於是查看rabbitmq log,發現如下報錯:

意思是說,rabbitmq-server由於申請內存失敗而崩潰。而當時系統的可用內存,確實少於rabbitmq要申請的值。

在rabbitmq的配置文件中,有一個參數vm_memory_high_watermark,簡稱【內存水位線】,這個參數是用來限制rabbitmq可用的內存值,默認值是0.4,也就是系統總內存的40%。

由於rabbitmq所在的物理節點內存較小,所以設置了rabbitmq最多使用1G的內存空間。奇怪的是上面的錯誤信息顯示rabbitmq居然申請了1.3G內存。事實上,在這個環境中rabbitmq已經運行過一段時間了,本身已經佔用了一部分內存,現在還要申請這麼多內存,真是不可思議。

經過查詢發現,原來rabbitmq可以佔用超過預設值的內存。而且在最壞的情況下,可以佔用達到預設值2倍的內存。官網是這麼解釋的:

The default memorythreshold is set to 40% of installed RAM. Note that this does not prevent theRabbitMQ server from using more than 40%, it is merely the point at whichpublishers are throttled. Erlangs garbage collector can, in the worst case,cause double the amount of memory to be used (by default, 80% of RAM). It isstrongly recommended that OS swap or page files are enabled.

解決辦法:

對於這個問題,臨時的解決辦法是:清理一下內存,關閉無用的程序,然後重新啟動rabbitmq。

出於對穩定性的考慮,為了防止rabbitmq崩潰的問題再次發生,可以從下面幾個方面入手:

1.設置參數vm_memory_high_watermark_paging_ratio為較小值,讓rabbitmq在內存吃緊時,利用硬碟來存儲數據。

註:為了防止rabbitmq內存達到水位線,rabbitmq還設計了一個參數,vm_memory_high_watermark_paging_ratio,它的默認值是0.5,意思是rabbitmq對內存的使用達到【內存水位線】的50%時,就開始把內存里的數據轉移到硬碟里。將它設置成一個較小的值,可以在一定程度上緩解內存的壓力。

2.把rabbitmq部署在一個單獨的環境里,配置較大內存。

3.修改vm_memory_high_watermark值,讓rabitmq申請少一些內存。

註:這樣可能會造成rabbitmq性能下降,但不至於崩潰。

4.升級到較新版本的rabbitmq,建議3.4版本以上,因為新版本在內存管理方面做了改進。

問題現象:

在安裝計算節點的過程中,重啟nova-compute服務,執行systemctlrestart openstack-nova-compute命令,結果命令一直卡住不動,得不到到響應。

排查過程:

通過查看nova-compute的log得知,無法連接到rabbitmq。

ping一下rabbitmqserver的主機名,結果是不識別主機名;

但是直接ping rabbitmq server的ip地址,結果是通的。這說明網路本身沒有問題,懷疑是/etc/hosts文件配置不正確,因為linux就是靠它解析主機名的。

查看/etc/hosts文件後,發現是正常的。這就比較詭異。

在其它計算節點嘗試ping一下rabbitmq server的主機名,結果是通的。

對比兩個計算節點的配置文件,發現出問題的節點上沒有/etc/nsswitch.conf這個文件。

通過查詢資料得知,nsswitch.conf是nameservice switch configuration,它規定了通過哪些途徑、按照什麼順序來查找特定類型的信息。

nsswitch.conf中的每一行配置都指明了如何搜索信息,每行配置的格式如下:

Info: method[[action]] [method[[action]]...]

在nsswitch.conf中有如下信息

hosts: files dns myhostname

它說明了在做名字解析時,先執行files,也就是搜索本地文件/etc/hosts,如果沒有找到的話再查找dns,再不行的話,查找本地hostname。

所以在缺少nsswitch.conf這個文件,或者上面的信息被修改後,操作系統不知道去掉用/etc/hosts,導致不能解析主機名,最終造成nova-compute不能連接到rabbitmq而卡住。

解決方法:

創建/etc/nsswitch.conf,並填入下面的內容

passwd: files sss

shadow: files sss

group: files sss

hosts: files dns myhostname

bootparams:nisplus [NOTFOUND=return] files

ethers: files

netmasks: files

networks: files

protocols: files

rpc: files

services: files sss

netgroup: files sss

publickey: nisplus

automount: files

aliases: files nisplus

mongodb是當今很流行的一種非關係型資料庫,它的主打是海量存儲。在openstack中主要是應用於ceilometer,作為openstack平台監控信息的存儲後端。

在生產環境中使用mongodb,一般都使用mongodb副本集和分片結合的集群模式,既可以保證高可用,也可以保證其可擴展性。

問題現象:

一台mongodb副本節點所在主機斷電,在大概一小時後恢復。由於高可用,業務沒有受到影響,監控信息還能正常存儲。重新啟動mongodb後,其狀態顯示為RECOVERING,貌似可以自動恢復。

但是在很長時間之後,還是處於RECOVERING狀態,不太正常。

排查過程:

查看日誌,發現該節點已經無法自動同步數據。

從日誌中可以看到,由於本機的數據太老,無法從其它mongodb同步數據。mongodb進入維護模式,需要人為干預才能恢復。

為什麼說數據太老,怎麼判斷?一起來分析一下。

在mongodb副本集中,有一個主節點和若干從節點,即一個PRIMARY,多個SECONDARY。一般情況下,PRIMARY負責寫入資料庫的操作,而SECONDARY只負責讀資料庫,SECONDARY上保存著資料庫的一個備份。

這兩種節點都維護著一個表結構(在mongodb中稱作「集合」),名字是oplog.rs,簡單稱它為oplog。它被存放在名稱為"local"的mongodb自帶的資料庫里。PRIMARY在寫資料庫時,就會將這些操作寫入oplog中。

也就是說oplog中存放了對資料庫的一條一條的寫操作,比如create,inert,update,而且每個操作都帶有時間戳。比如下面是一個插入操作。

一般來說SECONDARY會從PRIMARY同步數據,但不是簡單的從PRIMARY拷貝資料庫文件,而是拷貝其oplog,然後再將oplog中的一條一條的操作在本地資料庫中進行回放,即重新執行create,inert,update等操作。

oplog這個集合是固定大小的(可以在啟動mongodb的時候設置),所以oplog能存放的對資料庫操作記錄也是有限的。oplog會逐漸被寫滿,然後新的記錄就會覆蓋老的記錄。

SECONDARY在進行數據同步的時候,會拿自身的最新oplog時間,跟PRIMARYS上的最老的oplog時間比較,以獲得差值,同步差值內的記錄。

比如,PRIMARY節點上oplog記錄的是2:00到3:00之間的資料庫操作,SECONDARY節點上記錄的是2:00到2:30的資料庫操作,那麼就SECONDARY就會從PRIMARY同步2:30到3:00之間的記錄。

但是如果SECONDARY上最新的oplog時間比PRIMARY上最老的oplog時間還要老,那麼mongodb就不能正常同步了。比如PRIMARY節點上oplog記錄的是2:00到3:00之間的資料庫操作,SECONDARY節點上記錄的是1:00到1:30的資料庫操作。這時候SECONDARY節點上就會說數據太老,提示「we are too stale to use xxx as a sync source」。

出問題的環境中,由於ceilometer監控的項目比較多,會往mongodb資料庫里不斷插入信息,而且數據量特別大,所以當關機一個多小時後,該mongodb節點的資料庫里oplog就跟不上其它節點了。

解決辦法:

根據官網的說明,這種情況下需要人為來操作。

docs.mongodb.com/manual

有兩種方法:

1.讓mongodb自動做一次全量同步,這個方法簡單,數據量少的情況下可以採用這個方法

在出問題的機器上,停掉所有mongod進程,刪除數據文件,比如刪除下中/root/mongo/db/shard-x/目錄下的所有文件

重新啟動mongod進程。啟動後,mongo會執行一次全量同步,同步所有數據,不只是oplog里所記錄的那些。

2.從其它節點拷貝資料庫文件

生產環境中,mongodb資料庫可能會有幾百G,重新同步數據會需要很長時間,也可以嘗試手動拷貝資料庫文件。

這個問題的根本原因是oplog size設置太小,所以解決方法,還是把oplog size設置成一個合理的大小。官方推薦的是空閑可用磁碟空間的5%。

問題現象:

一次機房斷電並恢復後,rabbitmq集群無法啟動。

在每個節點上用systemctl status rabbitmq-server命令來查看rabbitmq狀態,發現全是failed

排查過程:

出問題的環境中,rabbitmq是以3個節點為集群的方式運行的,3個節點全是disk node。

查看rabbitmq的日誌文件,出現了類似下面的錯誤信息。

rabbit@node26:

* connected toepmd (port 4369) on node26

* epmd reports:node rabbit not running at all

no other nodes onnode26

* suggestion:start the node

rabbit@node25:

* connected toepmd (port 4369) on node25

* epmd reports:node rabbit not running at all

no other nodes onnode25

* suggestion:start the node

意思是說本節點連不到其它兩個節點,建議開啟其它節點上的rabbitmq server。

但是單獨啟動集群中的任何一個節點,都不能成功。

記得rabbitmq集群的啟動方式有點特殊,經過調查,在rabbitmq官網找到這麼一段話,寫了兩種場景:

When the entirecluster is brought down, the last node to go down must be the first node to bebrought online. If this doesnt happen, the nodes will wait 30 seconds for thelast disc node to come back online, and fail afterwards. If the last node to gooffline cannot be brought back up, it can be removed from the cluster usingthe forget_cluster_node command - consultthe rabbitmqctl manpage for more information.

If all clusternodes stop in a simultaneous and uncontrolled manner (for example with a powercut) you can be left with a situation in which all nodes think that some othernode stopped after them. In this case you can usethe force_boot command on one node to make it bootable again -consult the rabbitmqctlmanpage for more information.

第一種場景說的是,如果依次正常關閉集群中各節點上rabbitmq服務,在下次啟動集群時,要先啟動最後一個關閉服務的節點,因為它的數據在集群中是最新的。其它節點啟動時就可以從這個節點同步數據。如果最後一個節點沒有第一個啟動的話,其它節點啟動時就會在30秒內等待最後一個節點啟動。

對於第二種場景,在斷電的情況下,已經不能區分出誰是最後一個關閉的節點,也區分不出誰的數據最新。該場景符合這次遇到的問題,所以單獨在其中任何一個節點上啟動rabbitmq server都不成功。

按照官網給出的方法,用rabbitmqctl force_boot可以強制讓節點在下一次啟動。

但是用的時候又遇到了麻煩,問題環境中的rabbitmq server,版本是3.3.5,沒有這個命令。

rabbitmqctl force_reset命令是有的,但它的作用是清除rabbitmq資料庫,會造成節點脫離集群,所以不能用這個命令。

經過查詢,得知rabbitmq在3.4版本才加入了rabbitmqctl force_boot這條命令。

重新看一下上面提到的兩種場景:

第一種場景,rabbitmq server啟動後的30秒內,會嘗試連接它認為比自己晚關閉的節點。

第二種場景,斷電的情況下,既然每個節點不認為自己是最後一個關閉的,它認為集群中的其它節點都比它自己晚關閉。

綜合上面的分析,每一個節點啟動時都要求集群中其它節點在30秒內也啟動。

嘗試在第個節點上執行「rabbitmq-server」,然後馬上在第二個和第三個節點上也執行這個命令,結果是很短時間後所有節點都能啟動了,沒有報錯。看來這是一個可行的解決辦法。

解決方法:

對於3.4版本以上的rabbitmq,可以在集群中的一個節點上先執行rabbitmqctl force_boot,再正常啟動rabbitmq;然後啟動集群中其它節點的rabbitmq服務。

對於低版本的rabbitmq,嘗試在30秒內啟動rabbitmq集群內所有節點的rabbitmq服務。

總結:

通過這兩期的幾個問題的排查過程,可以得到下面一些思路:

首先根據問題現象,判斷大概跟哪些組件有關。

查看相關組件的服務狀態,查看進程是否異常。

檢查日誌中是否有錯誤信息。

對於服務卡死的情況,考慮gdb調試。

如果上面的排查過程中發現有錯誤信息,可以嘗試先自行解決,再檢查網路上是否有解決方法。

如果找不到錯誤信息,可以嘗試拿出問題的環境跟正常的環境做對比,看有哪些差異,再用排除法以此排查。

如果對某個組件的工作流程不清晰,可以查詢官網。

篇幅有限,部分過程未能詳細展開,如果希望了解更多的細節的讀者,可以通過官網或官方微信聯繫雲途騰測試團隊。


推薦閱讀:

如何從零開始學習OpenStack?
Kubernetes和OpenStack到底是什麼關係?
優雅安裝OpenStack
2017 OpenStack Summit | 網路性能篇

TAG:OpenStack |