本章介紹使用資料服務開發程式庫 (DSDL) 設計和實作資源類型的一般使用方法。還重點介紹了設計資源類型以驗證資源配置以及啟動、停止和監視資源。此外,本章說明如何使用 DSDL 以實作資源類型回呼方法。
請參閱 rt_callbacks(1HA) 線上手冊,以取得附加資訊。
您需要資源的特性設定存取權限來完成這些作業。DSDL 公用程式 scds_initialize() 提供統一方法以存取這些資源特性。此函數被設計為在每個回呼方法開始時呼叫。此公用程式函數將從叢集架構中擷取所有資源特性,並將該叢集架構提供給 scds_getname() 函數系列。
本章涵蓋下列主題:
資源類型註冊 (RTR) 檔案將有關資源類型的詳細資訊指定給 Sun Cluster 軟體。詳細資訊包含以下資訊︰
實作所需的特性
這些特性的資料類型和預設值
資源類型實作回呼方法的檔案系統路徑
系統定義的特性之多種設定
DSDL 隨附的 RTR 檔案範例足以適用大多數資源類型實作。您僅需要編輯某些基本元素,例如,資源類型名稱和資源類型回呼方法的路徑名稱。如果需要新的特性以實作資源類型,您可以將其宣告為資源類型實作的 RTR 檔案中的延伸特性,並透過使用 DSDL scds_get_ext_property() 公用程式存取新的特性。
資源類型實作的 Validate 回呼方法用於檢查資源類型是否接受建議的資源設定 (由資源上的建議特性設定指定)。
在以下兩種情況,Resource Group Manager (RGM) 會呼叫資源類型實作的 Validate 方法︰
資源類型的新資源正在建立中
資源或資源群組的特性正在更新中
這兩種情況可由傳送至 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 尚未建立資源 (對建立回呼而言) 或尚未套用正在更新的特性之已更新的值 (對更新回呼而言)。
如果您使用由 HAStoragePlus 資源類型管理的本機檔案系統,則您可使用 scds_hasp_check() 函數以檢查該資源類型的狀態。此項資訊是從所有 SUNW.HAStoragePlus 資源的狀態 (線上或其他狀態) 取得,其中資源視所採用為其定義的 Resource_dependencies 或 Resource_dependencies_weak 系統特性而定。請參閱 scds_hasp_check(3HA) 線上手冊,以取得由 scds_hasp_check() 函數傳回的狀態程式碼之完整清單。
DSDL 函數 scds_initialize() 使用以下方式處理這些狀況︰
如果正在建立資源,則 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); }
驗證函數還應記錄資源驗證失敗的原因。然而,透過省去該詳細資訊 (第 8 章, DSDL 資源類型實施範例包含驗證函數更實際可行的處理),您可以實作一個較簡單的範例 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() 函數的實作。
RGM 在選擇的叢集節點上呼叫資源類型實作的 Start 回呼方法以啟動資源。資源群組名稱、資源名稱以及資源類型名稱將在指令行上進行傳送。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 才表示成功啟動節點上的資源。如果啟動函數出現問題,必將傳回非 0 值。此函數失敗時,RGM 將嘗試在其他叢集節點上啟動資源。
為了更好地使用 DSDL,svc_start() 函數可呼叫 scds_pmf_start() 公用程式以啟動程序監視工具 (PMF) 下的應用程式。此公用程式還使用 PMF 的失敗回呼動作功能以偵測程序失敗。請參閱 pmfadm(1M) 線上手冊中的 -a 動作引數的說明,以取得更多資訊。
RGM 在某叢集節點上呼叫資源類型實作的 Stop 回呼方法以停止應用程式。Stop 方法的回呼語義要求以下因素︰
Stop 方法必須是等冪的,因為即使 Start 方法未在節點上成功完成,RGM 也可以呼叫 Stop 方法。因此,,Stop 方法也必須成功 (以 0 值結束),即使應用程式目前未在叢集節點上執行,並且無作業可執行。
如果資源類型的 Stop 方法在叢集節點上失敗 (以非 0 值結束),則試圖停止的資源會進入 STOP_FAILED 狀態。依據資源上的 Failover_mode 設定,此情況可能導致 RGM 執行叢集節點的強制重新啟動。
因此,您必須設計 Stop 方法以便此方法一定可以停止應用程式。如果應用程式無法終止,您可能更需要使用 SIGKILL 以突然結束應用程式。
由於架構將 Stop_timeout 特性的過期視為停止失敗,並因而將資源置於 STOP_FAILED 狀態,因此您還必須確保此方法及時停止應用程式。
DSDL 公用程式 scds_pmf_stop() 在首次嘗試使用 SIGTERM 平緩停止應用程式時,應滿足多數應用程式。然後,此函數將 SIGKILL 傳送至程序。此函數會假定應用程式使用 scds_pmf_start() 在 PMF 下啟動。請參閱PMF 函數,以取得有關此公用程式的詳細資訊。
假定用於停止應用程式的應用程式特定函數名為 svc_stop(),按如下所示實作 Stop 方法︰
if (scds_initialize(&handle, argc, argv)!= SCHA_ERR_NOERR) { return (1); /* Initialization Error */ } return (svc_stop(handle));
之前 svc_stop() 函數的實作是否包含 scds_pmf_stop() 函數是不相關的。決定是否包含 scds_pmf_stop() 函數要取決於應用程式是否使用 Start 方法在 PMF 下啟動。
由於即使系統目前遇到問題,Stop 方法應嘗試在此節點上停止應用程式,因此,svc_validate() 方法不用於 Stop 方法的實作。
RGM 呼叫 Monitor_start 方法以啟動資源的故障監視器。故障監視器將監視正由資源管理的應用程式之運作狀態。通常,資源類型實作會將故障監視器實作為在背景中執行的獨立常駐程式。Monitor_start 回呼方法用於使用正確的引數啟動此常駐程式。
由於監視器常駐程式本身易於失敗,(例如,突然停止運作,使應用程式處於非監視狀態),因此,您應使用 PMF 來啟動監視器常駐程式。DSDL 公用程式 scds_pmf_start() 具有內建支援用於啟動故障監視器。此公用程式將與 RT_basedir 相關的路徑名稱用於監視器常駐程式的資源類型回呼方法實作之位置。此應用程式使用由 DSDL 管理的 Monitor_retry_interval 和 Monitor_retry_count 延伸特性,來防止常駐程式無限制重新啟動。
此公用程式還將為所有回呼方法定義的相同指令行語法 (即 -R resource -G resource-group -T resource-type) 強加於監視器常駐程式上,儘管監視器常駐程式永遠無法由 RGM 直接呼叫。最後,此公用程式還可使監視器常駐程式實作本身啟用 scds_initialize() 公用程式,以設置自己的環境。主要的工作在於設計監視器常駐程式自身。
RGM 呼叫 Monitor_stop 方法以停止使用 Monitor_start 方法啟動的故障監視器常駐程式。處理此回呼方法失敗的方式與處理 Stop 方法失敗的方式完全相同。因此,Monitor_stop 方法必須是等冪的,且與 Stop 方法一樣牢固的。
如果使用 scds_pmf_start() 公用程式來啟動故障監視器公用程式,請使用 scds_pmf_stop() 公用程式來停止它。
RGM 在特定資源節點的資源上執行 Monitor_check 回呼方法,以確定叢集節點是否可以主控資源。換言之,RGM 執行此方法以確定由資源管理的應用程式是否可以在節點上成功地執行。
通常,此情況需要確定應用程式需要的所有系統資源在叢集節點上確實可用。如Validate 方法中所述,您實作的函數 svc_validate() 至少用於確定該情況。
依據由資源類型實作管理的特定應用程式,可以寫入 Monitor_check 方法以執行附加作業。必須實作 Monitor_check 方法,以使其不與同時執行的其他方法衝突。如果您使用 DSDL,Monitor_check 方法應呼叫 svc_validate() 函數,該函數實作資源特性的應用程式特定驗證。
RGM 呼叫資源類型實作的 Update 方法,以套用叢集管理員對使用中資源的配置所做的所有變更。僅在資源目前在線上的節點 (如果存在) 上呼叫 Update 方法。
由於 RGM 在執行 Update 方法之前執行資源類型的 Validate 方法,因此,資源類型實作必定接受對資源配置所做的變更。在變更資源或資源群組特性之前會呼叫 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 API 嘗試容錯移轉服務,則 scds_fm_action() 將重設或忽略其目前失敗歷程記錄。由於其歷程記錄已超出 Retry_count,此函數將重設目前失敗歷程記錄。如果監視器常駐程式在下次重複運算時喚醒,且無法成功完成常駐程式的運作狀態檢查,則監視器常駐程式將再次嘗試呼叫 scha_control() 函數。由於在最後一次重複運算中導致該呼叫被拒絕的情況仍然有效,因此該呼叫可能會被再次拒絕。重設歷程記錄可確保故障監視器在下次重複運算中至少嘗試更正本機情況 (例如,透過重新啟動應用程式)。
通常,如果該情況不進行本身更正,之後即會快速發佈 scha_control(),因此,scds_fm_action() 不會在重新啟動失敗情況下重設應用程式失敗歷程記錄。
依據失敗歷程記錄,公用程式 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 */