理解 OpenStack 高可用(HA) (4): Pacemaker 和 OpenStack Resource Agent (RA)

本系列會分析OpenStack 的高可用性(HA)概念和解決方案:html

(1)OpenStack 高可用方案概述node

(2)Neutron L3 Agent HA - VRRP (虛擬路由冗餘協議)mysql

(3)Neutron L3 Agent HA - DVR (分佈式虛機路由器)linux

(4)Pacemaker 和 OpenStack Resource Agent (RA)git

(5)RabbitMQ HAgithub

(6)MySQL HAsql

 

1. Pacemaker

1.1 概述

    Pacemaker 承擔集羣資源管理者(CRM - Cluster Resource Manager)的角色,它是一款開源的高可用資源管理軟件,適合各類大小集羣。Pacemaker 由 Novell 支持,SLES HAE 就是用 Pacemaker 來管理集羣,而且 Pacemaker 獲得了來自Redhat,Linbit等公司的支持。它用資源級別的監測和恢復來保證集羣服務(aka. 資源)的最大可用性。它能夠用基礎組件(Corosync 或者是Heartbeat)來實現集羣中各成員之間的通訊和關係管理。它包含如下的關鍵特性:shell

  • 監測並恢復節點和服務級別的故障
  • 存儲無關,並不須要共享存儲
  • 資源無關,任何能用腳本控制的資源均可以做爲服務
  • 支持使用 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 的一些問題和替代方案。api

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,好比:

  在 OpenStack 控制節點Pacemaker集羣中各組件:

  1. CIB 是個分佈式的XML 文件,有用戶添加配置
  2. Pacemaker 和 Corosync 根據 CIB 控制 LRMD 的行爲
  3. 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 將它監管的服務切換到被節點上繼續運行。這種切換,也許須要啓動服務,也許只須要作上下文切換便可。

  在標準的 Pacemaker Active/Standby 兩節點集羣中,兩個節點之間至少有兩條通訊鏈路(communication path),一條爲直接的 back-to-back link,另外一條爲服務器的標準物理網絡。使用冗餘的鏈路是高度推薦的,由於,即便一條鏈路失效了,服務器之間還能互相通訊。而只要服務器之間還有一條 通訊鏈路,那麼集羣就不會觸發 failover。
  當一個節點宕機或者網絡失去鏈接時,另外一個節點會檢測到,而後它會啓動切換(failover)把本身從備變爲主。這過程當中,新 master 上的 Pacemaker 會調用全部 RA 的 start 方法,將全部的資源服務啓動。而後,當原來的 master 節點從新上線之後,它上面運行的 Pacemaker 會調用全部 RA 的 stop 方法,將所有資源服務中止。 固然,每次從新啓動服務比較消耗時間,對於無狀態的服務,好比 glance-api,徹底能夠運行在兩個節點上,Pacemaker 只須要控制上下文的切換便可。
  若是兩個節點都在線(online),可是互相之間的通訊鏈路都斷了,每一個節點都會認爲對方節點已經down了,所以,各自會啓動所有的服務,同時將 DRBD 資源轉到 Primary,那麼這時候就會處於腦裂狀態。這時候,要麼須要管理員的介入,要麼須要使用 STONITH 。關於 STONITH, 能夠閱讀  https://ourobengr.com/ha/
  固然,這裏描述的是最簡單的狀況,實際的狀況也許會複雜得多,好比 Percona 的配置: https://github.com/percona/percona-pacemaker-agents/blob/master/doc/PRM-setup-guide.rst

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

    DRBD (Distributed Replication Block Device) 即分佈式複製塊設備。它的工做原理是:在A主機上有對指定磁盤設備寫請求時,數據發送給 A主機的 kernel,而後經過 kernel 中的一個模塊,把相同的數據經過網絡傳送給 B主機的 kernel 一份,而後 B主機再寫入本身指定的磁盤設備,從而實現兩主機數據的同步,也就實現了寫操做高可用。DRBD通常是一主一從,而且全部的讀寫和掛載操做,只能在主節點服務器上進行,可是主從DRBD服務器之間是能夠進行調換的。所以,DRBD 能夠看着基於網絡的 RAID 1 的實現。
 
    DRBD共有兩部分組成:內核模塊和用戶空間的管理工具。其中 DRBD 內核模塊代碼已經整合進Linux內核 2.6.33 之後的版本中,所以,若是你的內核版本高於此版本的話,你只須要安裝管理工具便可;不然,你須要同時安裝內核模塊和管理工具兩個軟件包,而且此二者的版本號必定要保持對應。最新的 DRBD 版本爲 8.4.
 
(file system, buffer cache, disk scheduler, disk drivers, TCP/IP stack and network interface card (NIC) driver)

3. Stonith

    這是一個頗有意思的技術,能夠用來預防腦裂。Stonith 是「shoot the other node in the head」 的首字母簡寫,它是 Heartbeat 軟件包的一個組件,它容許使用一個遠程或「智能的」鏈接到健康服務器的電源設備自動重啓失效服務器的電源,stonith設備能夠關閉電源並響應軟件命令,運行Heartbeat的服務器能夠經過串口線或網線向stonith設備發送命令,它控制高可用服務器對中其餘服務器的電力供應,換句話說,主服務器能夠復位備用服務器的電源,備用服務器也能夠復位主服務器的電源。詳細的說明能夠參考  這篇文章
相關文章
相關標籤/搜索