この章では、リソースタイプの設計や実装で DSDL を通常どのように使用するかについて説明します。この章では、特に、リソース構成を検証したり、リソースの開始、停止、および監視を行なったりするためのリソースタイプの設計について説明します。 そして、最後に、リソースタイプのコールバックメソッドを DSDL を使って導入する方法を説明します。詳細は、rt_callbacks(1HA) のマニュアルページを参照してください。
リソースタイプの開発者がこのような作業を行うためには、リソースのプロパティ設定値にアクセスできなければなりません。プログラマは DSDL のユーティリティー scds_initialize() を使うことで、統一された方法でこのようなリソースプロパティにアクセスできます。この機能は、各コールバックメソッドの始めの部分で呼び出す必要があります。このユーティリティー関数は、クラスタフレームワークからリソースのすべてのプロパティを取り出します。これによって、これらのプロパティは、scds_get() 関数群からアクセスできるようになります。
RTR (Resource Type Registration 、リソースタイプ登録) ファイルは、リソースタイプのとても重要なコンポーネントです。Sun Cluster は、リソースタイプの詳細な情報をこのファイルから取得します。この情報には、この実装に必要なプロパティや、それらのデータタイプやデフォルト値、リソースタイプの実装に必要なコールバックメソッドのファイルシステムパス、システム定義プロパティのさまざまな設定値などがあります。
ほとんどのリソースタイプ実装では、DSDL に添付されるサンプル RTR ファイルだけで十分なはずです。ただし、リソースタイプの名前やリソースタイプのコールバックメソッドのパス名など、いくつかの基本的な要素は編集する必要があります。リソースタイプを実装する際に新しいプロパティが必要な場合は、そのプロパティをリソースタイプ実装のリソースタイプ登録 (RTR) ファイルに拡張プロパティとして宣言します。新しいプロパティには、DSDL の scds_get_ext_property() ユーティリティーを使ってアクセスできます。
リソースタイプ実装の VALIDATE メソッドは、 1) リソースタイプの新しいリソースが作成されているときや、2) リソースまたはリソースグループのプロパティが更新されているときにそれぞれ RGM から呼び出されます。この 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 コールバックメソッドの目的は、リソースの新しい設定値 (リソースに対して指定された新しいプロパティ設定値) がそのリソースタイプにとって有効であるかどうかを検査することにあります。
DSDL 関数 scds_initialize() は、リソースの作成や更新をそれぞれ次のように処理します。
リソースの作成では、コマンド行から渡された新しいリソースプロパティを解析します。これによって、リソースタイプの開発者は、リソースプロパティの新しい値を、そのリソースががすでにシステムに作成されているかのように使用できます。
リソースやリソースグループの更新では、管理者によって更新されようとしているプロパティの新しい値をコマンド行から読み込み、残りのプロパティ (値が更新されないもの) をリソース管理 API を使って Sun Cluster から読み込みます。ただし、リソースタイプの開発者は、DSDL を使用する限り、このような初期作業を行う必要はありません。 さらに、開発者は、リソースのすべてのプロパティが使用可能であるものとして、リソースの検証を行うことができます。
次の図に示す svc_validate() は、リソースプロパティの検証を実装する関数です。この関数は、scds_get_*() 関数群を使って、検証しようとするプロパティを検査します。リソースの設定が有効ならこの関数から戻りコード 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);/* 初期設定のエラー */ } 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); /* リソースプロパティの設定が無効 */ } return (0); /* 設定が有効 */ } |
このように、リソースタイプの開発者は、svc_validate() ルーチンの実装だけに集中できます。リソースタイプ実装の典型的な例としては、app.conf というアプリケーション構成ファイルを Confdir_list プロパティの下に置く処理があります。 この処理は、Confdir_list プロパティから取り出した適切なパス名に対して stat() システム呼び出しを実行することによって実装できます。
リソースタイプ実装の START コールバックメソッドは、特定のクラスタノードのリソースを開始するときに RGM によって呼び出されます。リソースグループ名とリソース名、およびリソースタイプ名はコマンド行から渡されます。START メソッドは、クラスタノードでデータサービスリソースを開始するために必要なアクションを行います。通常、このようなアクションには、リソースプロパティの取得や、アプリケーション固有の実行可能ファイルと構成ファイル (または、どちらか) の場所の特定、適切なコマンド行引数を使用したアプリケーションの起動などがあります。
DSDL では、リソース構成ファイルが scds_initialize() ユーティリティーによってすでに取得されています。アプリケーションの起動アクションは、svc_start() ルーチンに指定できます。 さらに、アプリケーションが実際に起動されたかどうかを確認するために、svc_wait() ルーチンを呼び出すことができます。START メソッドのコード (詳細は省略) は、次のようになります。
intmain(int argc, char *argv[]) { scds_handle_t handle; if (scds_initialize(&handle, argc, argv)!= SCHA_ERR_NOERR) { return (1); /* 初期設定のエラー */ } if (svc_validate(handle) != 0) { return (1); /* 設定値が無効 */ } if (svc_start(handle) != 0) { return (1); /* 起動に失敗 */ } return (svc_wait(handle)); } |
この起動メソッドの実装では、svc_validate() を呼び出してリソース構成を検証します。検証結果が正しくない場合は、リソース構成とアプリケーション構成が一致していないか、このクラスタノードのシステムに関して何らかの問題があることを示しています。たとえば、リソースに必要な広域ファイルシステムが現在このクラスタノードで使用できないのかもしれません。その場合には、このクラスタノードでこのリソースを起動しても意味がないので、RGM を使って別のノードのリソースを起動すべきです。ただし、この場合、svc_validate() は十分に限定的であるものとします (その場合、このルーチンは、アプリケーションが必要とするリソースがあるかどうかをそのクラスタノードだけで検査します)。そうでないと、このリソースはすべてのクラスタノードで起動に失敗し、START_FAILED の状態になる可能性があります。リソースのこの状態については、scswitch(1M) と『Sun Cluster 3.0 12/01 データサービスのインストールと構成』を参照してください。
svc_start() ルーチンは、このノードでリソースの起動に成功したら戻りコード 0 を、問題を検出したら 0 以外の戻りコードをそれぞれ返す必要があります。 このルーチンから 0 以外の値が返されると、RGM は、このリソースを別のクラスタノードで起動しようと試みます。
DSDL を最大限に活用するには、svc_start() ルーチンで scds_pmf_start() ユーティリティーを使って、アプリケーションを PMF (プロセス管理機能) のもとで起動できます。このユーティリティーは、PMF の障害コールバックアクション機能 (pmfadm(1M) の -a アクションフラグを参照) を使って、プロセス障害の検出を実装します。
リソースタイプ実装の STOP コールバックメソッドは、特定のクラスタノードでアプリケーションを停止するときに RGM によって呼び出されます。STOP メソッドのコールバックが有効であるためには、次の条件が必要です。
STOP メソッドは結果に依存しない命令 (idempotent) でなければなりません。つまり、STOP メソッドは、そのノードで START メソッドが正常に終了していなくても、RGM から呼び出されることがあります。したがって、STOP メソッドは、そのクラスタノードでアプリケーションが動作していない場合でも (したがって、特別な処理が必要ない場合でも)、正常に (終了コード 0 で) 終了しなければなりません。
リソースタイプの STOP メソッドが特定のクラスタノードで失敗に終わると (戻りコードが 0 以外だと)、そのリソースタイプは STOP_FAILED の状態になります。 この場合、リソースの Failover_mode 設定によっては、このクラスタノードが RGM によって強制的に再起動されることがあります。したがって、STOP メソッドの設計時には、アプリケーションを停止する手段をメソッドに組み込んでおくことが重要です。たとえば、アプリケーションが停止しない場合は、 SIGKILL などを使って、アプリケーションを強制的かつ即時に停止する必要があります。さらに、この処理は一定の時間内に行われなければなりません。Stop_timeout で設定した時間が経過すると、停止が失敗したものとみなされ、リソースは STOP_FAILED の状態になるからです。
ほとんどのアプリケーションには、DSDL ユーティリティー scds_pmf_stop() で十分なはずです。このユーティリティーは、まず、アプリケーションが PMF の scds_pmf_start() で起動されたものとみなして、アプリケーションを SIGTERM で「静かに」停止しようとします。これで停止しない場合は、プロセスに対して SIGKILL を適用します。このユーティリティーの詳細については、「PMF 関数」を参照してください。
アプリケーションを停止するそのアプリケーション固有のルーチンを svc_stop() とし、これまで使用してきたコードモデルに従うとするなら、STOP メソッドは、次のように実装できます。svc_stop() の実装で scds_pmf_stop() が使用されているかどうかは、ここでは関係ありません。それが使用されているかどうかは、アプリケーションが PMF のもとで START メソッドによって起動されているかどうかに依存します。
if (scds_initialize(&handle, argc, argv)!= SCHA_ERR_NOERR) { return (1); /* 初期設定のエラー */ } return (svc_stop(handle));
STOP メソッドの実装では、svc_validate() メソッドは使用されません。システムに問題があったとしても、STOP メソッドは、このノードでこのアプリケーションを 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() ユーティリティーで停止する必要があります。
クラスタノードが特定のリソースを支配できるかどうかを確認するために (つまり、そのリソースによって管理されるアプリケーションがそのノードで正常に動作するかどうかを確認するために)、そのリソースの MONITOR_CHECK コールバックメソッドがそのリソースのノードで呼び出されます。 通常、この呼び出しでは、アプリケーションに必要なすべてのシステムリソースが本当にクラスタノードで使用可能かどうかが確認されます。「VALIDATE メソッド」 で述べたように、開発者が実装する svc_validate() ルーチンでは、少なくともこの確認が行われなければなりません。
リソースタイプ実装によって管理されているアプリケーションによっては、MONITOR_CHECK メソッドでその他の作業を行うことがあります。DSDL を使用する場合には、リソースプロパティに対するアプリケーション固有の検証を実装するために作成された svc_validate() ルーチンを MONITOR_CHECK メソッドで活用することをお勧めします。
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 に渡すことはできます)。
これらのメソッドは、「1 度だけのアクション」を行なうためのものです (リソース管理 API 仕様の定義を参照)。DSDL のサンプル実装には、これらのメソッドの使い方は示されていません。しかし、これらのメソッドを使用する必要がある場合には、DSDL のすべての機能をこれらのメソッドでも使用できます。通常、「1 度だけのアクション」を実装するリソースタイプ実装では、INIT メソッドと BOOT メソッドはまったく同じように機能します。FINI メソッドは、一般に、INIT メソッドや BOOT メソッドのアクションを「取り消す」ためのアクションに使用されます。
DSDL を使用したリソースタイプ実装の障害モニターデーモンには、通常、次の役割があります。
管理されているアプリケーションの状態を定期的に監視します。モニターデーモンのこの役割はアプリケーションに大きく依存します。したがって、リソースタイプによって大幅に異なることがあります。DSDL には、TCP に基づく簡単なサービスの状態を検査するいくつかのユーティリティー関数が組み込まれています。HTTP、NNTP、IMAP、POP3 など、ASCII ベースのプロトコルを実装するアプリケーションは、これらのユーティリティーを使って実装できます。
アプリケーションによって検出された問題をリソースプロパティ Retry_interval や Retry_count を使って追跡します。 さらに、アプリケーションが異常停止した場合には、PMF アクションスクリプトを使ってサービスを再起動すべきかどうかや、アプリケーションの障害が頻繁に発生するためにフェイルオーバーを考慮すべきかどうかを判断します。DSDL では、この機構の実装を助けるユーティリティーとして scds_fm_action() と scds_fm_sleep() が提供されます。
アプリケーションを再起動するか、リソースを含むリソースグループのフェイルオーバーを試みるなど、適切なアクションを実行します。DSDL ユーティリティー scds_fm_action() には、このようなアルゴリズムが実装されています。そのために、このアルゴリズムは、過去の Retry_interval で指定した秒数の間に起った検証障害の累積を計算します。
リソースの状態を更新します。これによって、scstat(1m) コマンドやクラスタ管理 GUI からアプリケーションの状態を知ることができます。
DSDL ユーティリティーの設計では、障害モニターデーモンの主要ループは次のようになっています。
DSDL を使って実装された障害モニターでは、
アプリケーションプロセスの異常停止は、scds_fm_sleep() によって比較的迅速に検出されます。これは、PMF によるプロセス停止の通知が非同期に行われるためです。これは、障害モニターが時々リープから復帰してサービスの状態を検査し、アプリケーションの停止を検出する方法と対象的です。DSDL を使用した障害モニターでは障害検出時間が大幅に短縮されるため、サービスの可用性が向上します。
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 (;;) { / * 正常な検証と検証の間の thorough_probe_interval * だけスリープする。*/ (void) scds_fm_sleep(scds_handle, scds_get_rs_thorough_probe_interval(scds_handle)); /* 使用するすべての ipaddress を検証する。次の各要素を繰り返し検証する。 * 1. 使用するすべてのネットリソース * 2. 特定のリソースのすべての ipaddresses * 検証する ipaddress ごとに * 障害履歴を計算する。 */ probe_result = 0; /* すべてのリソースを繰り返し調べて、 * svc_probe() の呼び出しに使用する各 IP アドレスを取得する。 */ for (ip = 0; ip < netaddr->num_netaddrs; ip++) { /* 状態を検証する必要があるホスト名とポート * を取得する。 */ hostname = netaddr->netaddrs[ip].hostname; port = netaddr->netaddrs[ip].port_proto.port; /* * HA-XFS は 1 つのポートしかサポートしないため、 * ポート配列の最初のエントリから * ポート値を取得する。 */ ht1 = gethrtime(); /* 検証開始時刻を保存する。*/ probe_result = svc_probe(scds_handle, hostname, port, timeout); /* * サービス検証履歴を更新し、 * 必要に応じてアクションを実行する。 * 検証終了時刻を保存する。 */ ht2 = gethrtime(); /* ミリ秒に変換する。 */ dt = (ulong_t)((ht2 - ht1) / 1e6); /* * 障害履歴を計算し、 * 必要に応じてアクションを実行する。 */ (void) scds_fm_action(scds_handle, probe_result, (long)dt); } /* 各ネットリソース */ } /* 検証を続ける。 */ |