本系列會分析OpenStack 的高可用性(HA)概念和解決方案:
(2)Neutron L3 Agent HA - VRRP (虛擬路由冗余協議)
(3)Neutron L3 Agent HA - DVR (分布式虛機路由器)
(4)Pacemaker 和 OpenStack Resource Agent (RA)
(5)RabbitMQ HA
(6)MySQL HA
1. Pacemaker
1.1 概述
Pacemaker 承擔集群資源管理者(CRM - Cluster Resource Manager)的角色,它是一款開源的高可用資源管理軟件,適合各種大小集群。Pacemaker 由 Novell 支持,SLES HAE 就是用 Pacemaker 來管理集群,並且 Pacemaker 得到了來自Redhat,Linbit等公司的支持。它用資源級別的監測和恢復來保證集群服務(aka. 資源)的最大可用性。它可以用基礎組件(Corosync 或者是Heartbeat)來實現集群中各成員之間的通信和關系管理。它包含以下的關鍵特性:
- 監測並恢復節點和服務級別的故障
- 存儲無關,並不需要共享存儲
- 資源無關,任何能用腳本控制的資源都可以作為服務
- 支持使用 STONITH 來保證數據一致性
- 支持大型或者小型的集群
- 支持 quorum (仲裁) 或 resource(資源) 驅動的集群
- 支持任何的冗余配置
- 自動同步各個節點的配置文件
- 可以設定集群范圍內的 ordering, colocation and anti-colocation
- 支持高級的服務模式
1.2 Pacemaker 集群的架構
1.2.1 軟件架構
- Pacemaker - 資源管理器(CRM),負責啟動和停止服務,而且保證它們是一直運行着的以及某個時刻某服務只在一個節點上運行(避免多服務同時操作數據造成的混亂)。
- Corosync - 消息層組件(Messaging Layer),管理成員關系、消息和仲裁。見 1.2 部分介紹。
- Resource Agents - 資源代理,實現在節點上接收 CRM 的調度對某一個資源進行管理的工具,這個管理的工具通常是腳本,所以我們通常稱為資源代理。任何資源代理都要使用同一種風格,接收四個參數:{start|stop|restart|status},包括配置IP地址的也是。每個種資源的代理都要完成這四個參數據的輸出。Pacemaker 的 RA 可以分為三種:(1)Pacemaker 自己實現的 (2)第三方實現的,比如 RabbitMQ 的 RA (3)自己實現的,比如 OpenStack 實現的它的各種服務的RA,這是 mysql 的 RA。
1.2.2 Pacemaker 支持的集群類型
Pacemaker 支持多種類型的集群,包括 Active/Active, Active/Passive, N+1, N+M, N-to-1 and N-to-N 等。
這里 有詳細的 Pacemaker 安裝方法。這是 中文版。這篇文章 提到了 Pacemaker 的一些問題和替代方案。
1.3 Corosync
Corosync 用於高可用環境中提供通訊服務,位於高可用集群架構中的底層,扮演着為各節點(node)之間提供心跳信息傳遞這樣的一個角色。Pacemaker 位於 HA 集群架構中資源管理、資源代理這么個層次,它本身不提供底層心跳信息傳遞的功能,它要想與對方節點通信就需要借助底層的心跳傳遞服務,將信息通告給對方。
關於心跳的基本概念:
- 心跳:就是將多台服務器用網絡連接起來,而后每一台服務器都不停的將自己依然在線的信息使用很簡短很小的通告給同一個網絡中的其它主機,告訴它們自己依然在線,其它服務器收到這個心跳信息就認為它是在線的,尤其是主服務器。
- 心跳信息怎么發送,由誰來收,其實就是進程間通信。兩台主機是沒法通信的,只能利用網絡功能,通過進程監聽在某一套接字上,實現數據發送,數據請求,所以多台服務器就得運行同等的進程,這兩個進程不停的進行通信,主節點(主服務器)不停的向對方同等的節點發送自己的心跳信息,那這個軟件就叫高可用的集群的基准層次,也叫心跳信息傳遞層以及事物信息的傳遞層,這是運行在集群中的各節點上的進程,這個進程是個服務軟件,關機后需要將其啟動起來,主機間才可以傳遞信息的,一般是主節點傳給備節點。
這篇文章 詳細介紹了其原理。
1.4 Fencing Agent
一個 Pacemaker 集群往往需要使用 Fencing agent。https://alteeve.ca/w/ANCluster_Tutorial_2#Concept.3B_Fencing 詳細地闡述了Fencing的概念及其必要性。Fencing 是在一個節點不穩定或者無答復時將其關閉,使得它不會損壞集群的其它資源,其主要用途是消除腦裂。
通常有兩種類型的 Fencing agent:power(電源)和 storage (存儲)。Power 類型的 Agent 會將節點的電源斷電,它通常連到物理的設備比如UPS;Storage 類型的Agent 會確保某個時刻只有一個節點會讀寫共享的存儲。
1.5 資源代理(Resource Agent - RA)
一個 RA 是管理一個集群資源的可執行程序,沒有固定其實現的編程語言,但是大部分RA都是用 shell 腳本實現的。Pacemaker 使用 RA 來和受管理資源進行交互,它既支持它自身實現的70多個RA,也支持第三方RA。Pacemaker 支持三種類型的 RA:
主流的 RA 都是 OCF 類型的。RA 支持的主要操作包括:
- start: enable or start the given resource
- stop: disable or stop the given resource
- monitor: check whether the given resource is running (and/or doing useful work), return status as running or not running
- validate-all: validate the resource's configuration
- meta-data: return information about the resource agent itself (used by GUIs and other management utilities, and documentation tools)
- some more, see OCF Resource Agents and the Pacemaker documentation for details.
在一個 OpenStack Pacemaker 集群中,往往都包括這幾種類型的 RA,比如:
- MySQL 和 Apache RA 是 Pacemaker native 的。更多的原生 RA 在 http://www.linux-ha.org/wiki/Resource_agents 中可以查看。
- RabbitMQ RA 和 OpenStack RA 也是第三方的
在 OpenStack 控制節點Pacemaker集群中各組件:
- CIB 是個分布式的XML 文件,有用戶添加配置
- Pacemaker 和 Corosync 根據 CIB 控制 LRMD 的行為
- LRMD 通過調用 RA 的接口控制各資源的行為
1.5.1 RA 的實現
要實現一個 RA, 需要遵守 OCF 的規范,其規范在 http://www.opencf.org/cgi-bin/viewcvs.cgi/specs/ra/resource-agent-api.txt?rev=HEAD
下面以OpenStack Glance-api RA 為例,說明其功能。其代碼在 https://github.com/openstack/openstack-resource-agents/blob/master/ocf/glance-api,本身其實是一個 shell 腳本。
usage() { #RA 的功能,包括 start,stop,validate-all,meta-data,status 和 monitor glance-api 等,每個對應下面的一個函數 cat <<UEND usage: $0 (start|stop|validate-all|meta-data|status|monitor) $0 manages an OpenStack ImageService (glance-api) process as an HA resource The 'start' operation starts the imaging service. The 'stop' operation stops the imaging service. The 'validate-all' operation reports whether the parameters are valid The 'meta-data' operation reports this RA's meta-data information The 'status' operation reports whether the imaging service is running The 'monitor' operation reports whether the imaging service seems to be working UEND } meta_data() { #meta-data 功能,輸出一段XML cat <<END ... END } ####################################################################### # Functions invoked by resource manager actions glance_api_validate() { #檢查 glance-api,比如libaray是否存在,配置文件是否存在,RA 使用的用戶是否存在 local rc check_binary $OCF_RESKEY_binary check_binary $OCF_RESKEY_client_binary # A config file on shared storage that is not available # during probes is OK. if [ ! -f $OCF_RESKEY_config ]; then if ! ocf_is_probe; then ocf_log err "Config $OCF_RESKEY_config doesn't exist" return $OCF_ERR_INSTALLED fi ocf_log_warn "Config $OCF_RESKEY_config not available during a probe" fi getent passwd $OCF_RESKEY_user >/dev/null 2>&1 rc=$? if [ $rc -ne 0 ]; then ocf_log err "User $OCF_RESKEY_user doesn't exist" return $OCF_ERR_INSTALLED fi true } glance_api_status() { #獲取運行狀態,通過檢查 pid 文件來確認 glance-api 是否在運行 local pid local rc if [ ! -f $OCF_RESKEY_pid ]; then ocf_log info "OpenStack ImageService (glance-api) is not running" return $OCF_NOT_RUNNING else pid=`cat $OCF_RESKEY_pid` fi ocf_run -warn kill -s 0 $pid rc=$? if [ $rc -eq 0 ]; then return $OCF_SUCCESS else ocf_log info "Old PID file found, but OpenStack ImageService (glance-api) is not running" return $OCF_NOT_RUNNING fi } glance_api_monitor() { #監控 glance-api 服務的運行狀態,通過運行 glance image-list 命令 local rc glance_api_status rc=$? # If status returned anything but success, return that immediately if [ $rc -ne $OCF_SUCCESS ]; then return $rc fi # Monitor the RA by retrieving the image list if [ -n "$OCF_RESKEY_os_username" ] && [ -n "$OCF_RESKEY_os_password" ] \ && [ -n "$OCF_RESKEY_os_tenant_name" ] && [ -n "$OCF_RESKEY_os_auth_url" ]; then ocf_run -q $OCF_RESKEY_client_binary \ --os_username "$OCF_RESKEY_os_username" \ --os_password "$OCF_RESKEY_os_password" \ --os_tenant_name "$OCF_RESKEY_os_tenant_name" \ --os_auth_url "$OCF_RESKEY_os_auth_url" \ index > /dev/null 2>&1 rc=$? if [ $rc -ne 0 ]; then ocf_log err "Failed to connect to the OpenStack ImageService (glance-api): $rc" return $OCF_NOT_RUNNING fi fi ocf_log debug "OpenStack ImageService (glance-api) monitor succeeded" return $OCF_SUCCESS } glance_api_start() { #啟動 glance-api 服務 local rc glance_api_status rc=$? if [ $rc -eq $OCF_SUCCESS ]; then ocf_log info "OpenStack ImageService (glance-api) already running" return $OCF_SUCCESS fi # run the actual glance-api daemon. Don't use ocf_run as we're sending the tool's output # straight to /dev/null anyway and using ocf_run would break stdout-redirection here. su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file $OCF_RESKEY_config \ $OCF_RESKEY_additional_parameters"' >> /dev/null 2>&1 & echo $!' > $OCF_RESKEY_pid # Spin waiting for the server to come up. # Let the CRM/LRM time us out if required while true; do glance_api_monitor rc=$? [ $rc -eq $OCF_SUCCESS ] && break if [ $rc -ne $OCF_NOT_RUNNING ]; then ocf_log err "OpenStack ImageService (glance-api) start failed" exit $OCF_ERR_GENERIC fi sleep 1 done ocf_log info "OpenStack ImageService (glance-api) started" return $OCF_SUCCESS } glance_api_stop() { #停止 glance-api 服務 local rc local pid glance_api_status rc=$? if [ $rc -eq $OCF_NOT_RUNNING ]; then ocf_log info "OpenStack ImageService (glance-api) already stopped" return $OCF_SUCCESS fi # Try SIGTERM pid=`cat $OCF_RESKEY_pid` ocf_run kill -s TERM $pid rc=$? if [ $rc -ne 0 ]; then ocf_log err "OpenStack ImageService (glance-api) couldn't be stopped" exit $OCF_ERR_GENERIC fi # stop waiting shutdown_timeout=15 if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5)) fi count=0 while [ $count -lt $shutdown_timeout ]; do glance_api_status rc=$? if [ $rc -eq $OCF_NOT_RUNNING ]; then break fi count=`expr $count + 1` sleep 1 ocf_log debug "OpenStack ImageService (glance-api) still hasn't stopped yet. Waiting ..." done glance_api_status rc=$? if [ $rc -ne $OCF_NOT_RUNNING ]; then # SIGTERM didn't help either, try SIGKILL ocf_log info "OpenStack ImageService (glance-api) failed to stop after ${shutdown_timeout}s \ using SIGTERM. Trying SIGKILL ..." ocf_run kill -s KILL $pid fi ocf_log info "OpenStack ImageService (glance-api) stopped" rm -f $OCF_RESKEY_pid return $OCF_SUCCESS } ####################################################################### case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; usage|help) usage exit $OCF_SUCCESS;; esac # Anything except meta-data and help must pass validation glance_api_validate || exit $? # What kind of method was invoked? case "$1" in start) glance_api_start;; stop) glance_api_stop;; status) glance_api_status;; monitor) glance_api_monitor;; validate-all) ;; *) usage exit $OCF_ERR_UNIMPLEMENTED;; esac
1.5.2 RA 的配置
(1)因為上述的 RA 是第三方的,因此需要將它下載到本地,RA 所在的文件夾是 /usr/lib/ocf/resource.d/provider,對 OpenStack 來說,就是 /usr/lib/ocf/resource.d/openstack。然后設置其權限為可運行。
(2)通過運行 crm configure,輸入下面的配置,就可以創建一個 Pacemaker 資源來對 glance-api 服務進行 monitor:
primitive p_glance-api ocf:openstack:glance-api \ params config="/etc/glance/glance-api.conf" os_password="secretsecret" \ os_username="admin" os_tenant_name="admin" os_auth_url="http://192.168.42. 103:5000/v2.0/" \ op monitor interval="30s" timeout="30s"
該配置指定了:
- ocf:openstack:glance-api: ”ocf“ 是指該 RA 的類型,”openstack“ 是指RA 的 namespace,”glance-api“ 是 RA 可執行程序的名稱。
- os_* 和 interval 和 timeout 參數參數(monitor 函數會用到)
- glance-api 和 config 文件 (在 start 和 stop 中會用到)
- ”op monitor“ 表示對該資源進行 monitor,如果失敗,則執行默認的行為 restart(先 stop 再 start)(注意這里Pacemaker 有可能在另一個節點上重啟,OpenStack 依賴其它約束比如 Pacemaker resource group 等來進行約束)
- ”interval = 30s“ 表示 monitor 執行的間隔是 30s
- ”timeout = 30“ 表示每次 monitor 的最長等待時間為 30s
- 另外,其實這里可以指定該資源為 clone 類型,表示它會分布在兩個節點上運行於 active/active 模式;既然這里沒有設置,它就只運行在一個節點上。
- 另外,Pacemaker 1.1.18 版本之后,crm configure 命令被移除了,取而代之的是 pcs 命令。
(3)創建一個 service group
group g_services_api p_api-ip p_keystone p_glance-api p_cinder-api p_neutron-server p_glance-registry p_ceilometer-agent-central
Pacemaker group 的一些特性:
- 一個 group 中的所有服務都位於同一個節點上。本例中,VIP 在哪里,其它的服務也在那個節點上運行。
- 規定了 failover 時的啟動和停止操作的規則:啟動時,group 中所有的 service 都是按照給定順序被啟動的;停止時,group 中所有的 service 都是按照逆給定順序被停止的
- 啟動時,前面的 service 啟動失敗了的話,后面的服務不會被啟動。本例中,如果 p_api-ip (VIP)啟動失敗,后面的服務都不會被啟動
1.4.3 Pacemaker 對 RA 的使用
Pacemaker 根據 CIB 中對資源的 operation 的定義來執行相應的 RA 中的命令:
(1)monitor:Pacemaker 使用 monitor 接口來檢查整個集群范圍內該資源的狀態,來避免重復啟動一個資源。同時,重啟已經崩潰的資源。
(2)restart:在被 monitored 的資源不在運行時,它會被重啟(stop 再 start)。需要注意的是,Pacemaker 不一定在原來的節點上重啟某服務,因此,需要通過更多的限制條件(group 和 colocation),來使得某服務在規定的節點上運行。
(3)failover:當 master 節點宕機時,Pacemaker 會啟動failover 將它監管的服務切換到被節點上繼續運行。這種切換,也許需要啟動服務,也許只需要做上下文切換即可。
1.4.4 CIB 和 Pacemaker 的行為
這篇文章 分析了用戶在 CIB 中對 Pacemaker 所做的配置和 Pacemaker 的行為時間之間的關系。
CIB 針對重啟服務的行為,做了兩種規定:
- 1) Intervals and timeout of recovery tasks (“when”).
- 2) Grouping and colocation of recovery tasks (“where”).
各種配置項、值和結果:
這篇文章通過多種測試,得出如下基本的結論:
- CIB 配置對資源恢復時長有直接影響
- 減少 group 有利於減少時長
- 增加 colocation 有利於減少時長
- 需要合理地進行配置來盡可能減少時長
詳細的結論可以直接閱讀那論文。
2. DRBD
