Sun Cluster 数据服务开发者指南(适用于 Solaris OS)

第 7 章 设计资源类型

本章介绍了 DSDL 在设计和实现资源类型方面的典型用法, 还着重介绍了设计资源类型以验证资源配置以及启动、停止和监视该资源等内容。 在本章的最后还介绍了如何使用 DSDL 实现资源类型回叫方法。

有关其它信息,请参阅 rt_callbacks(1HA) 手册页。

要完成这些任务,您需要存取资源的特性设置。 DSDL 公用程序 scds_initialize() 向您提供了一种用来存取资源特性的统一方法。 本函数设计成在每个回叫方法的开头部分进行调用。 此公用程序函数用来从群集框架检索资源的所有特性,并使其可供 scds_getname() 系列函数使用。

本章包括以下主题:

RTR 文件

资源类型登记 (RTR) 文件是资源类型的重要组成部分。 此文件用来向 Sun Cluster 指定资源类型的详细信息。 这些详细信息包括实现所需的特性、这些特性的数据类型以及缺省值、资源类型实现的回叫方法的文件系统路径以及系统定义的特性的各种设置。

DSDL 附带的 RTR 文件样例应该能够满足大多数资源类型实现的要求。 您仅需编辑一些基本的元素,例如资源类型的名称和该资源类型回叫方法的路径名。 如果实现该资源类型时需要一个新的特性,您可以在该资源类型实现的资源类型登记 (RTR) 文件中将该特性声明为扩展特性,然后使用 DSDL scds_get_ext_property() 公用程序存取新特性。

Validate 方法

RGM 会在两种情况下调用资源类型实现的 Validate 方法: 1) 创建资源类型的新资源时;2) 更新资源或资源组的特性时。 这两种方案可以根据传送到资源的 Validate 方法的命令行选项 -c(创建)或 -u(更新)是否存在来区分。

对一组节点中的每一个节点都调用 Validate 方法,其中该组节点都是由资源类型特性 INIT_NODES 的值定义的。 如果 INIT_NODES 设置为 RG_PRIMARIES,则将对每一个可以承载含有该资源的资源组的节点(主节点)调用 Validate。 如果 INIT_NODES 设置为 RT_INSTALLED_NODES,则将对每一个安装有资源类型软件的节点(通常是群集中的所有节点)调用 ValidateINIT_NODES 的缺省值为 RG_PRIMARIES(请参阅 rt_reg(4))。 调用 Validate 方法时,RGM 尚未创建资源(在创建回叫的情况下)或尚未应用所更新特性的更新后的值(在更新回叫的情况下)。 资源类型实现的 Validate 回叫方法的用途是检查所建议的资源设置(按照该资源的建议特性设置指定)是否适用于该资源类型。


注意:

如果您使用 HAStoragePlus 管理的本地文件系统,则使用 scds_hasp_check 检查 HAStoragePlus 资源的状态。使用为该资源定义的 Resource_dependenciesResource_dependencies_weak 系统特性,从资源依赖的所有 SUNW.HAStoragePlus(5) 资源中获取此信息。 有关 scds_hasp_check 调用返回的状态码的完整列表,请参阅 scds_hasp_check(3HA)


DSDL 函数 scds_initialize() 按以下方式处理这些情况:

假设实现资源特性验证的函数为 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 回叫方法,以启动该资源。 通过命令行传送资源组名称、资源名称和资源类型名称。 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 数据服务规划和管理指南(适用于 Solaris OS)

如果资源在节点上成功启动,则 svc_start() 函数必须返回 0。 如果启动函数遇到了问题,则它必须返回一个非零值。 此函数失败后,RGM 将尝试在其它群集节点上启动该资源。

为了尽可能充分地利用 DSDL,svc_start() 函数可以使用 scds_pmf_start() 公用程序在进程管理工具 (PMF) 控制之下启动该应用程序。 此公用程序还将利用 PMF 的失败回叫操作功能(请参阅 pmfadm( 1M) 中的 -a 操作标志)来实现进程失败检测。

Stop 方法

RGM 将对群集节点调用资源类型实现的 Stop 回叫方法,以停止该应用程序。 Stop 方法的回叫语义要求:

对于大多数应用程序来说,DSDL 公用程序 scds_pmf_stop() 应该就满足要求,因为它首先试图软(通过 SIGTERM)停止应用程序(假设它是通过 scds_pmf_start() 在 PMF 控制下启动的),然后向进程发送 SIGKILL。 有关此公用程序的详细信息,请参阅PMF 函数

以下是迄今为止我们一直在使用的代码模型,其中假设用来停止应用程序的应用程序特定函数为 svc_stop()svc_stop() 的实现是否使用 scds_pmf_stop() 与此处介绍的内容无关,而是取决于该应用程序是否是在 PMF 控制下通过 Start 方法启动的),Stop 方法可用以下方式实现:

if (scds_initialize(&handle, argc, argv)!= SCHA_ERR_NOERR)
{
   return (1);   /* Initialization Error */
}
return (svc_stop(handle));

svc_validate() 方法不用于 Stop 方法的实现,因为即使系统当前存在问题,Stop 方法应试图停止此节点上的应用程序。

Monitor_start 方法

RGM 将调用 Monitor_start 方法来启动资源的故障监视器。 故障监视器用来监视资源管理的应用程序的运行情况。 资源类型实现通常将故障监视器作为在后台运行的独立守护程序来实现。 Monitor_start 回叫方法用来通过合适的变量启动此守护程序。

因为监视器守护程序本身易于失败(例如,它可能毁坏,从而使应用程序处于不受监视的状态),所以您应该使用 PMF 启动该监视器守护程序。 DSDL 公用程序 scds_pmf_start() 具有启动故障监视器的内置支持。 此公用程序使用监视器守护程序的相对路径名(相对于资源类型回叫方法实现的位置的 RT_basedir)。 它使用由 DSDL 管理的 Monitor_retry_intervalMonitor_retry_count 扩展特性,以避免会无限多次地重启该守护程序。 虽然 RGM 从不直接调用监视器守护程序,但它仍然将与为所有回叫方法定义的命令行语法相同的语法(即 -R resource -G resource_group -T resource_type)强加到该监视器守护程序中。 它允许监视器守护程序实现本身利用 scds_initialize() 公用程序来设置其自己的环境。 主要用于设计监视器守护程序本身方面。

Monitor_stop 方法

RGM 将调用 Monitor_stop 方法来停止原先通过 Monitor_start 方法启动的故障监视器守护程序。 此回叫方法的的故障处理方式与 Stop 方法完全相同,因此 Monitor_stop 方法必须像 Stop 方法一样等幂和强大。

如果您使用 scds_pmf_start() 公用程序启动故障监视器守护程序,则请使用 scds_pmf_stop() 公用程序停止该守护程序。

Monitor_check 方法

可以对指定资源的某节点调用资源中的 Monitor_check 回叫方法,以确定该群集节点是否可以控制该资源(即该资源所管理的应用程序是否可以在该节点上成功运行)。 通常此情况涉及到要确保该群集节点上确实提供了应用程序所需的所有系统资源。 如Validate 方法中所述,由开发者实现的函数 svc_validate() 可用来确定此方面的情况。

根据资源类型实现所管理的具体应用程序,也可以编写 Monitor_check 方法,以执行一些附加任务。 必须实现 Monitor_check 方法,以免该方法与同时运行的其它方法发生冲突。 对于使用 DSDL 的开发者,建议 Monitor_check 方法利用为实现资源特性的应用程序特定验证这一目的而编写的 svc_validate() 函数。

Update 方法

RGM 调用资源类型实现的 Update 方法来应用系统管理员对活动资源的配置进行的更改。 仅对资源当前处于联机状态的节点(如果有)调用 Update 方法。

刚才对资源配置所进行的更改一定会适用于资源类型实现,因为 RGM 在运行 Update 方法之前先运行了该资源类型的 Validate 方法。 Validate 方法在更改资源或资源组特性之前调用,Validate 方法可以否决所建议的更改。 Update 方法在应用更改内容之后调用,以便有机会向活动(联机)资源通知这些新设置。

作为资源类型开发者,您需要谨慎决定您希望能够动态更新的特性,并在 RTR 文件中用 TUNABLE = ANYTIME 设置来标记这些特性。 通常,如果 Update 方法的实现可以重启故障监视器守护程序,您就可以指定您希望能够动态更新该故障监视器守护程序所使用的资源类型实现的任意特性。

可能要更改的特性包括:

这些特性会影响故障监视器守护程序对该服务的运行情况进行检查的方式以及频率、用来跟踪错误的历史间隔和 PMF 对其设置的重启阈值。 为实现这些特性的更新,在 DSDL 中提供了公用程序 scds_pmf_restart()

如果您需要能够动态更新资源特性,而对该特性进行修改又可能会影响运行应用程序,则您需要执行相应操作,以便对该特性进行的更新可以正确地应用到该应用程序的所有运行实例中。 当前无法通过 DSDL 使该操作变得更容易。 Update 不向命令行传递修改后的特性(虽然 Validate 进行了传递)。

InitFiniBoot 方法

这些是按照资源管理 API 规范定义的一次性操作方法。 DSDL 附带的实现样例中并未说明这些方法的用法。 然而,如果资源类型开发者需要使用这些方法,也可以使用 DSDL 中的所有工具。 通常对于资源类型实现来说,InitBoot 方法完全相同,都可以实现一次性操作Fini 方法通常用来执行撤消 InitBoot 方法的操作的操作。

设计故障监视器守护程序

使用 DSDL 的资源类型实现通常都具有一个故障监视器守护程序,该守护程序可执行以下任务。

已对 DSDL 公用程序进行了设计,因此故障监视器守护程序的主循环可以用以下伪代码表示。

对于使用 DSDL 实现的故障监视器,

在大多数情况下,应用程序特定运行情况检查操作可以在独立的公用程序(例如 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 */