本章說明 DSDL 在設計和實施資源類型方面的一般用法, 還重點介紹了設計資源類型以驗證資源配置以及啟動、停止和監視資源。 本章最後說明如何使用 DSDL 實施資源類型回呼方法。
請參閱 rt_callbacks( 1HA) 線上援助頁,以取得其他資訊。
您需要資源的屬性設定存取權限來完成這些作業。 DSDL 公用程式 scds_initialize() 向您提供了一個統一的存取資源屬性的方法。 此函式被設計為在每個回呼方法開始時呼叫。 此公用程式函式從叢集框架擷取資源的所有屬性,並使資源可用於 scds_getname() 函式家族。
資源類型註冊 (RTR) 檔案是資源類型的重要元件。 此檔案將關於資源類型的詳細資訊指定給 Sun Cluster。 這些詳細資訊包括實作所需的屬性、屬性的資料類型、屬性的預設值、用於資源類型實作的回呼方法之檔案系統路徑,以及系統定義屬性的各種設定值。
隨附於 DSDL 的範例 RTR 檔案會滿足大多數資源類型實作的需要。 您需要做的就是編輯某些基本元素,例如資源類型名稱和資源類型回呼方法的路徑名稱。 如果需要新屬性以實施資源類型,您可以宣告它為資源類型實作的資源類型註冊 (RTR) 檔案的延伸屬性,然後使用 DSDL scds_get_ext_property() 公用程式存取新屬性。
資源類型實作的 Validate 方法由 RGM 呼叫,分兩種情形: 1) 建立資源類型的新資源時;2) 更新資源或資源群組的屬性時。 可以由傳送至資源的 Validate 方法的指令行選項為 -c (建立) 還是 -u (更新) 來辨別這兩種情形。
可在節點集的每個節點上呼叫 Validate 方法,節點集由資源類型屬性 INIT_NODES 的值來定義。 如果 INIT_NODES 設定為 RG_PRIMARIES,則會在能夠存放包含資源之資源群組的每個節點上呼叫 Validate。 如果將 INIT_NODES 設定為 RT_INSTALLED_NODES ,則會在安裝資源類型軟體的每個節點上呼叫 Validate,通常為叢集中的所有節點。 INIT_NODES 的預設值為 RG_PRIMARIES (請參閱 rt_reg(4))。 呼叫 Validate 方法時,RGM 尚未建立資源 (就建立回呼而言),或尚未套用要更新屬性的更新值 (就更新回呼而言)。 資源類型實作之 Validate 回呼方法的目的是檢查所建議的資源設定值 (所建議的資源屬性設定指定) 對資源類型來說是可接受的。
如果您使用的是由 HAStoragePlus 管理的本機檔案系統,請使用 scds_hasp_check 來檢查 HAStoragePlus 資源的狀態。此資訊是使用為資源定義的 Resource_dependencies 或 Resource_dependencies_weak 系統屬性,從該資源所依賴之所有 SUNW.HAStoragePlus(5) 資源的狀態 (線上或其他狀態) 獲取 。請參閱 scds_hasp_check(3HA),以取得從 scds_hasp_check 呼叫傳回之狀態程式碼的完整清單。
DSDL 函式 scds_initialize() 以下列模式處理這些情形:
就資源建立而言,它剖析指令行上傳送的建議資源屬性。 這樣,資源屬性的建議值即可被資源類型開發者使用,正如資源已在系統中建立。
就資源或資源群組更新而言,從指令行讀入所建議的由管理員更新的屬性值,並使用資源管理 API 從 Sun Cluster 讀入剩餘屬性 (其值未更新)。 使用 DSDL 的資源類型開發者無需關心所有這些事務性工作。 開發者可以完成資源的驗證,如同資源的所有屬性對於他們來說都是可用的。
假定實施資源屬性驗證的函式稱為 svc_validate(),此函式使用 scds_get_name() 函式家族在驗證中查看其關注的屬性。 假定在此函式中用 0 回覆碼表示一個可接受的資源設定,資源類型的 Validate 方法便可由下列程式碼分段來表示:
int main(int argc, char *argv[]) { scds_handle_t handle; int rc; if (scds_initialize(&handle, argc, argv)!= SCHA_ERR_NOERR) { return (1); /* Initialization Error */ } rc = svc_validate(handle); scds_close(&handle); return (rc); } |
驗證函式也應該記錄資源驗證失敗的原因。 如果省略該詳細資訊 (請參閱下一章,以取得關於驗證函式的更實際的處理資訊),則 svc_validate() 函式可以實施為的一個簡單範例:
int svc_validate(scds_handle_t handle) { scha_str_array_t *confdirs; struct stat statbuf; confdirs = scds_get_confdir_list(handle); if (stat(confdirs->str_array[0], &statbuf) == -1) { return (1); /* Invalid resource property setting */ } return (0); /* Acceptable setting */ } |
這樣,資源類型開發者必須只關心 svc_validate() 函式的實作。 典型的資源類型實作範例可以是確保名為 app.conf 的應用程式配置檔案存在於 Confdir_list 屬性之下。 這可以由源自 Confdir_list 屬性的適當路徑名稱上的 stat() 系統呼叫便利地實施。
資源類型實作的 Start 回呼方法由 RGM 在選擇的叢集節點上呼叫以啟動資源。 資源群組名稱、資源名稱以及資源類型名稱將在指令行上進行傳送。 Start 方法預期將執行在叢集節點上啟動資料服務資源所需的動作。 通常包括擷取資源屬性、尋找應用程式特定的可執行檔和/或配置檔、以及用適當的指令行引數啟動應用程式。
透過 DSDL,資源配置已經由 scds_initialize() 公用程式擷取。 應用程式的啟動動作可以包含在函式 svc_start() 中。 可以呼叫另一個函式 svc_wait() 來驗證應用程式確實啟動。 用於 Start 方法的簡化程式碼變為:
int main(int argc, char *argv[]) { scds_handle_t handle; if (scds_initialize(&handle, argc, argv)!= SCHA_ERR_NOERR) { return (1); /* Initialization Error */ } if (svc_validate(handle) != 0) { return (1); /* Invalid settings */ } if (svc_start(handle) != 0) { return (1); /* Start failed */ } return (svc_wait(handle)); } |
此啟動方法實現將呼叫 svc_validate(),以驗證資源配置。 如果失敗,則資源配置和應用程式配置不符合,或目前在叢集節點上出現關於系統的問題。 例如,資源所需的全域檔案系統目前可能在此叢集節點上不可用。 在此情況下,即使嘗試在此叢集節點上啟動資源也是無效的。 最好讓 RGM 嘗試在其他節點上啟動資源。 然而請注意,上面假設了 svc_validate ()足夠保守 (以致它僅檢查應用程式絕對需要之叢集節點上的資源),否則資源可能在所有叢集節點上均無法啟動,從而陷入 START_FAILED 狀態。 請參閱 scswitch( 1M) 與Sun Cluster Data Services Planning and Administration Guide for Solaris OS,以取得此狀態的說明。
svc_start() 函式必須傳回 0 才表示成功啟動節點上的資源。 如果啟動函式遇到問題,則必定傳回非零值。 此函式失敗時,RGM 將嘗試在其他叢集節點上啟動資源。
若要盡可能利用 DSDL,svc_start() 函式可以使用 scds_pmf_start() 公用程式在程序管理設備 (PMF) 下啟動應用程式。 此公用程式還利用 PMF 的故障回呼動作功能 (請參閱 pmfadm( 1M) 中的 -a 動作旗號),以實施程序故障偵測。
資源類型實現的 Stop 回呼方法由 RGM 在叢集節點上呼叫來停止應用程式。 Stop 方法的回呼語義要求
Stop 方法必須是等冪的,因為即使 Start 方法未在節點上成功完成,RGM 也可以呼叫 Stop 方法。 這樣,Stop 方法必定會成功 (退出零),即使應用程式目前未在叢集節點上執行,並且無任何工作可做。
如果資源類型的 Stop 方法在叢集節點上失敗 (退出非零),正被停止的資源將以 STOP_FAILED 狀態結束。 依靠資源上的 Failover_mode 設定,這可能導致 RGM 強制重新啟動叢集節點。 因此,請務必設計 Stop 方法以便於應用程式無法終止時,它會盡力確實停止應用程式,甚至突然地強制終止應用程式 (例如,使用 SIGKILL)。 它還應該確保能夠及時完成此作業,因為框架將 Stop_timeout 的過期視為停止失敗,並使資源處於 STOP_FAILED 狀態。
當 DSDL 公用程式 scds_pmf_stop() 初次嘗試軟式 (透過 SIGTERM) 停止應用程式 (假設它透過 scds_pmf_start() 在 PMF 下啟動),然後遞送 SIGKILL 至程序時,它應該滿足大多數應用程式的需要。 請參閱PMF 函式,以取得關於此公用程式的詳細資訊。
遵循到目前為止使用的程式碼模型,假定要停止應用程式的應用程式特定函式名為 svc_stop() (svc_stop() 實作是否使用 scds_pmf_stop() 在此處不考慮,而取決於是否透過 Start 方法在 PMG 下啟動應用程式),Stop 方法可以實施為
if (scds_initialize(&handle, argc, argv)!= SCHA_ERR_NOERR) { return (1); /* Initialization Error */ } return (svc_stop(handle));
在 Stop 方法的實現中不使用 svc_validate() 方法,因為即使系統目前出現問題,Stop 方法也會試圖停止此節點上的應用程式。
RGM 呼叫 Monitor_start 方法以啟動資源的故障監視器。 故障監視器監視由資源管理的應用程式的運作狀況。 資源類型實作通常將故障監視器作為在後台執行的獨立常駐程式來實施。 Monitor_start 回呼方法用於以適當的引數啟動此常駐程式。
由於監視器常駐程式自身易於出現故障 (例如,它可能停止,使應用程式處於未監視狀態),因此您應該使用 PMF 啟動監視器常駐程式。 DSDL 公用程式 scds_pmf_start() 具有用於啟動故障監視器的內建支援。 此公用程式使用監視器常駐程式的相對路徑名稱 (相對於用於資源類型回呼方法實作的位置之 RT_basedir)。 它使用由 DSDL 管理的 Monitor_retry_interval 和 Monitor_retry_count 延伸屬性,以防止常駐程式無限制地重新啟動。 雖然 RGM 決不會直接呼叫監視器常駐程式,但是它將為所有回呼方法定義的相同指令行語法 (即 -R resource -G resource_group -T resource_type) 強加於監視器常駐程式。 它允許監視器常駐程式實作自己利用 scds_initialize() 公用程式設定自己的環境。 主要的工作在於設計監視器常駐程式自身。
RGM 呼叫 Monitor_stop 方法,以停止透過 Monitor_start 方法啟動的故障監視器常駐程式。 此回呼方法的失敗被視為與 Stop 方法的失敗方式完全相同;因此,Monitor_stop 方法必須與 Stop 方法一樣等冪和可靠。
如果使用 scds_pmf_start() 公用程式來啟動故障監視器公用程式,請使用 scds_pmf_stop() 公用程式來停止它。
在指定資源的節點上呼叫資源的 Monitor_check 回呼方法,以確定叢集節點是否能夠主控資源 (即資源所管理的應用程式是否能在節點上成功執行?)。 通常,這種情形包括確定應用程式需要的所有系統資源確實在叢集節點上可用。 與在Validate 方法中說明的一樣,預定開發者實施的函式 svc_validate() 至少能確定這一點。
依靠資源類型實作所管理的特定應用程式,可以寫入 Monitor_check 方法以執行某些額外作業。 必須實施 Monitor_check 方法,以便它不會與同時在執行的其他方法發生衝突。 對於使用 DSDL 的開發者,建議 Monitor_check 方法利用 svc_validate() 函式,此函式是為了實施應用程式特定的資源屬性驗證而寫入的。
RGM 呼叫資源類型實現的 Update 方法,以套用系統管理員對作用中資源配置所做的所有變更。 僅在資源目前在線上的節點 (如果存在) 上呼叫 Update 方法。
由於 RGM 在執行資源類型的 Validate 方法後才執行 Update 方法,因此可以確保對資源配置所做的變更對於資源類型實作來說是可接受的。 在資源或資源群組屬性變更之前呼叫 Validate 方法,Validate 方法可以禁止所建議的變更。 在套用變更之後呼叫 Update 方法,以使作用中 (線上) 的資源可以注意到新的設定。
作為資源類型開發人員,您需要謹慎地決定要動態更新的屬性,並在 RTR 檔案中用 TUNABLE = ANYTIME 設定標示這些屬性。 通常,您可以指定要動態更新故障監視器常駐程式使用的資源類型實作之任意屬性,前提是 Update 方法實作至少重新啟動監視器常駐程式。
可能的候選屬性如下:
Thorough_Probe_Interval
Retry_Count
Retry_Interval
Monitor_retry_count
Monitor_retry_interval
Probe_timeout
這些屬性影響故障監視器常駐程式進行服務運作狀況檢查的方法,包括檢查的頻率、用來記錄錯誤的歷史間隔以及 PMF 在其上設定的重新啟動臨界值。 在 DSDL 中提供了公用程式 scds_pmf_restart (),以實施這些屬性的更新。
如果您需要能夠動態更新資源屬性,但是修改屬性可能影響執行中的應用程式,則您需要執行適當的動作,以便對該屬性的更新可以正確套用至應用程式的任何執行中的實例。 目前沒有透過 DSDL 簡化此作業的方法。 無法在指令行上將修改的屬性傳送至 Update (與 Validate 相同)。
這些是由資源管理 API 規格定義的一次性動作方法。 DSDL 所包含的範例實作未對這些方法的使用進行說明。 但是,如果資源類型開發者需要這些方法,則 DSDL 中的所有功能對這些方法也是可用的。 通常,Init 和 Boot 方法對於資源類型實作實施一次性動作是完全相同的。 Fini 方法通常執行還原 Init 或 Boot 方法的動作之動作。
使用 DSDL 的資源類型實作通常具有擔負下列職責的故障監視器常駐程式。
定期監視被管理的應用程式的運作狀況。 監視器常駐程式的這個特定方面嚴格相依於應用程式,並隨資源類型的不同而有很大不同。 DSDL 具有某些內建公用程式函式,以執行基於 TCP 的簡單服務運作狀況檢查。 執行基於 ASCII 的協定的應用程式 (例如 HTTP、NNTP、IMAP 和 POP3) 可以使用這些公用程式來實施。
由使用資源屬性 Retry_interval 和 Retry_count 的應用程式記錄遇到的問題。 在應用程式完全失敗時,決定 PMF 動作程序檔是否應該重新啟動服務,或應用程式失敗是否已經累積得如此迅速,以至於可能需要考慮故障轉移。 DSDL 公用程式 scds_fm_action() 和 scds_fm_sleep() 預定會幫助您實施此機制。
採取適當的動作 (通常重新啟動應用程式或嘗試對所包含的資源群組進行故障轉移)。 DSDL 公用程式 scds_fm_action() 實施此類演算法。 為達到此目的,它計算在過去的 Retry_interval 秒內,探測失敗的目前累積量。
更新資源狀態,以便 scstat 指令與叢集管理 GUI 可以使用應用程式運作狀態。
設計了 DSDL 公用程式,從而故障監視器常駐程式的主迴圈便可以由下列虛擬程式碼來表示。
對於使用 DSDL 來實施的故障監視器,
由於透過 PMF 的程序失敗通知非同步,因此透過 scds_fm_sleep() 偵測應用程式程序失敗非常迅速。 與故障監視器不時喚醒以檢查服務運作狀況並尋找失敗應用程式的情況進行對比。 故障偵測時間明顯減少,因此服務可用性增加。
如果 RGM 拒絕透過 scha_control(3HA) API 轉移服務故障的嘗試,則 scds_fm_action() 重設 (遺忘) 其目前的失敗歷史。 原因是失敗歷史已經超出 Retry_count,如果監視器常駐程式在下一次重覆中喚醒且無法成功完成其常駐程式的運作狀況檢查,它將再次嘗試呼叫 scha_control() 呼叫,但可能仍會被拒絕,因為在上一次重覆中導致其被拒絕的情形仍然存在。 重設歷史將確保故障監視器至少嘗試在下一個重覆中在本機校正此情形 (例如,透過應用程式重新啟動)。
一旦重新啟動失敗,scds_fm_action() 將不重設應用程式失敗歷史,因為如果此情形未自行校正,則通常可能很快嘗試 scha_control()。
根據失敗歷史,公用程式 scds_fm_action() 會將資源狀況更新至 SCHA_RSSTATUS_OK、SCHA_RSSTATUS_DEGRADED 或 SCHA_RSSTATUS_FAULTED。 從而此狀況對於叢集系統管理來說是可用的。
在大多數情況下,應用程式特定的運作狀況檢查動作可以在單獨的獨立式公用程式 (例如,svc_probe()) 中實施,並與此一般主迴圈整合。
for (;;) { / * sleep for a duration of thorough_probe_interval between * successive probes. */ (void) scds_fm_sleep(scds_handle, scds_get_rs_thorough_probe_interval(scds_handle)); /* Now probe all ipaddress we use. Loop over * 1. All net resources we use. * 2. All ipaddresses in a given resource. * For each of the ipaddress that is probed, * compute the failure history. */ probe_result = 0; /* Iterate through the all resources to get each * IP address to use for calling svc_probe() */ for (ip = 0; ip < netaddr->num_netaddrs; ip++) { /* Grab the hostname and port on which the * health has to be monitored. */ hostname = netaddr->netaddrs[ip].hostname; port = netaddr->netaddrs[ip].port_proto.port; /* * HA-XFS supports only one port and * hence obtaint the port value from the * first entry in the array of ports. */ ht1 = gethrtime(); /* Latch probe start time */ probe_result = svc_probe(scds_handle, hostname, port, timeout); /* * Update service probe history, * take action if necessary. * Latch probe end time. */ ht2 = gethrtime(); /* Convert to milliseconds */ dt = (ulong_t)((ht2 - ht1) / 1e6); /* * Compute failure history and take * action if needed */ (void) scds_fm_action(scds_handle, probe_result, (long)dt); } /* Each net resource */ } /* Keep probing forever */ |