本章介绍资源池及其属性。
资源池提供了用于管理处理器集和线程调度类的框架。资源池用于对计算机资源进行分区。通过资源池可以分散工作负荷,使各工作负荷对特定资源的占用不会发生冲突。在具有混合工作负荷的系统上,这种资源预留有助于获得可预测的性能。
有关资源池以及用于管理资源池的示例命令的概述,请参见《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 12 章 “动态资源池(概述)”和《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 13 章 “管理动态资源池(任务)”。
处理器集将系统中的 CPU 分组到一个有界限的实体中,在该实体中进程可以采用独占方式运行。其中的进程不能扩展到该处理器集外,而其他进程也不能扩展到该处理器集内。处理器集可以将具有类似特征的任务组合在一起,并设置针对 CPU 使用的硬限制(上限)。
资源池框架用于定义具有最大和最小 CPU 计数要求的软处理器集。此外,该框架还为该处理器集提供了一个硬定义调度类。
资源池定义以下内容
处理器集组
调度类
调度类为基于算术逻辑的线程提供不同的 CPU 访问特性。调度类包括:
实时调度类
交互式调度类
固定优先级调度类
分时调度类
公平共享调度类
有关公平共享调度程序以及用于管理公平共享调度程序的示例命令的概述,请参见《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 8 章 “公平共享调度程序(概述)”和《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 9 章 “管理公平共享调度程序(任务)”。
请不要在 CPU 集中混合调度类。如果在 CPU 集中混合调度类,则系统性能可能会不稳定或不可预测。请使用处理器集按照应用程序特征分别部署应用程序。请指定使应用程序能够达到最佳性能的调度类。有关各个调度类的特征的更多信息,请参见 priocntl(1)。
有关资源池的概述以及对何时使用资源池的讨论,请参见第 6 章,动态资源池。
libpool 库定义了可用于各种实体(使用池功能管理)的属性。每个属性都属于以下类别:
约束定义了属性的限制。典型的约束是在 libpool 配置中指定的最大和最小分配量。
目标可以更改当前配置的资源分配,以生成遵循已建立约束的新的候选配置。(请参见 poold(1M)。)目标包含以下类别:
与工作负荷有关的目标将依据工作负荷强加的条件有所变化。与工作负荷有关的目标示例为 utilization 目标。
与工作负荷无关的目标不会依据工作负荷强加的条件发生变化。与工作负荷无关的目标示例为 cpu locality 目标。
目标可以采用可选的前缀来指示目标的重要性。为确定目标的重要性,将在目标中增加此前缀(是 0 到 INT64_MAX 之间的整数)。
如果在 /etc/project 中找不到指定的池,请绑定到 pool.default 属性设置为 TRUE 的池。
系统的用户说明。缺省的池命令不使用 system.comment,但通过 poolcfg 实用程序启动配置时除外。此时,系统会将提示性消息置于该配置的 system.comment 属性中。
配置的用户名称。
处理此配置所需的 libpool 版本。
如果为 TRUE,则表示该池处于活动状态。
池的用户说明。
如果为 TRUE,则表示该池为缺省池。请参见 system.bind-default 属性。
该池的相对重要性。用于可能的资源争用解决方案。
池的用户名称。setproject(3PROJECT) 使用 pool.name 作为 project(4) 数据库中的 project.pool 项目属性的值。
与该池的使用者绑定的调度程序类。此属性是可选的,如果未指定,则调度程序对该池使用者的绑定将不受影响。有关各个调度类的特征的更多信息,请参见 priocntl(1)。调度程序类包括:
RT(代表实时调度程序)
TS(代表分时调度程序)
IA(代表交互式调度程序)
FSS(代表公平共享调度程序)
FX(代表固定优先级调度程序)
资源的用户说明。
标识缺省的处理器集。
表示是否为此 pset 设置 PSET_NOESCAPE。请参见 pset_setattr(2) 手册页。
此处理器集的负载。最低值为 0。该值将随着处理器集上的负载(由系统运行队列中的作业数度量)以线性方式增加。
此处理器集中允许的最大 CPU 数。
此处理器集中允许的最小 CPU 数。
资源的用户名称。
此处理器集的当前 CPU 数。
系统指定的处理器集 ID。
命名资源类型。所有处理器集的值都为 pset。
标识与大小相关的属性的意义。所有处理器集的值都为 population。
CPU 的用户说明。
libpool(3LIB) 池配置库定义了用于读取和写入池配置文件的接口。该库还定义了用于提交现有配置以成为运行的操作系统配置的接口。<pool.h> 头文件提供了所有库服务的类型和函数声明。
在资源池功能中,引入了“池”这个一般性的概念,用来指可绑定到进程的资源的集合。可以采用持久方式配置、分组并标记处理器集和其他实体。可以将工作负荷组件与系统总资源的一部分相关联。libpool(3LIB) 库提供了用于访问资源池功能的 C 语言 API。pooladm(1M)、poolbind(1M) 和 poolcfg(1M) 可通过从 shell 中调用命令来使用资源池功能。
以下列表包含与创建或销毁 pset 以及处理 pset 关联的函数。
将 LWP(lightweight process,轻量进程)或一组 LWP 绑定到指定的处理器。
为处理器集分配处理器。
将一个或多个 LWP(lightweight processes,轻量进程)绑定到处理器集。
创建不包含处理器的空处理器集。
销毁处理器集并释放关联的成员处理器和进程。
设置或获取处理器集属性。
本节列出了所有的资源池函数。每个函数都带有指向相应手册页的链接和有关该函数用途的简短说明。根据函数执行操作还是查询,函数分为两组:
用于交换集的 libpool 的导入接口与本文档中定义的接口相同。
本节中列出的接口用于执行与池和关联元素相关的操作。
将资源与指定的池关联起来。
将指定的组件转换为池元素类型。
创建池配置。
关闭指定的池配置并释放关联资源。
提交对指定池配置所做的更改以进行永久存储。
将给定的配置保存到指定位置。
释放池配置。
在指定的位置创建池配置。
删除对配置的永久存储。
将配置状态恢复到池配置的永久存储中保留的状态。
将指定的池配置转换为池元素类型。
更新内核状态的库快照。
使用缺省属性和每种类型的缺省资源创建新的池。
破坏指定的池。关联的资源不会被修改。
删除给定资源与池之间的关联。
将有关元素的命名属性设置为指定的值。
使用所提供配置的指定名称和类型创建新的资源。
从配置文件中删除指定的资源。
将指定的池资源转换为池元素类型。
将基本单位从源资源传输到目标资源。
将指定组件从源资源传输到目标资源。
从元素中删除命名的属性。
将指定的进程绑定到与正在运行的系统中的池关联的资源。
修改池功能的当前状态。
将指定的池转换为池元素类型。
分配并返回池属性值的不透明容器。
释放分配的属性值。
设置 boolean 类型的属性值。
设置 double 类型的属性值。
设置 int64 类型的属性值。
为池属性设置 name=value 对。
复制已传递的字符串。
设置 uint64 类型的属性值。
本节中列出的接口用于执行与池和关联元素相关的查询。
返回描述给定组件的字符串。
返回描述整个配置的字符串。
返回为指定配置的 pool_conf_open() 提供的位置字符串。
返回池配置的有效性状态。
检查给定配置内容的有效性。
返回池框架用于存储动态配置的位置。
返回通过调用资源池配置库函数记录的最终故障的错误值。
返回正在运行的系统中的池名称,该池包含与指定进程绑定的资源集。
返回当前包含指定组件的资源。
返回具有所提供配置中的指定名称的池。
检索元素中的已命名属性的值。
返回具有所提供配置中的给定名称和类型的资源。
返回正在运行的系统中的池名称,该池包含与给定进程绑定的资源集。
检索池功能的当前状态。
返回指定池的说明。
检索与指定的属性列表匹配的所有资源组件。
返回当前与池关联的以 NULL 结尾的资源数组。
返回与指定的属性列表匹配的池列表。
返回构成指定资源的以 NULL 结尾的组件数组。
返回与指定的属性列表匹配的资源列表。
返回指定资源的说明。
枚举此平台上的池框架支持的资源类型。
返回池框架用于存储缺省池框架实例化配置的位置。
返回每个有效池错误代码的说明。
获取 boolean 类型的属性值。
获取 double 类型的属性值。
获取 int64 类型的属性值。
返回为指定池属性指定的名称。
获取 string 类型的属性值。
返回指定的池值包含的数据类型。
获取 uint64 类型的属性值。
获取池库的版本号。
调用对资源中包含的所有组件的回调。
调用在配置中定义的所有池的回调。
调用对为给定元素定义的所有属性的回调。
调用对与池关联的所有资源的回调。
本节包含资源池接口的代码示例。
sysconf(3C) 提供有关整个系统中的 CPU 数的信息。以下示例提供了用于确定特定应用程序的池 pset 中所定义 CPU 数的粒度。
本示例的要点包括以下内容:
pvals[] 应该为以 NULL 结尾的数组。
pool_query_pool_resources() 返回与应用程序的池 my_pool 中的 pvals 数组类型 pset 匹配的所有资源的列表。由于池只能有一个 pset 资源实例,因此每个实例始终在 nelem 中返回。reslist[] 仅包含一个元素,即 pset 资源。
pool_value_t *pvals[2] = {NULL}; /* pvals[] should be NULL terminated */ /* NOTE: Return value checking/error processing omitted */ /* in all examples for brevity */ conf_loc = pool_dynamic_location(); conf = pool_conf_alloc(); pool_conf_open(conf, conf_loc, PO_RDONLY); my_pool_name = pool_get_binding(getpid()); my_pool = pool_get_pool(conf, my_pool_name); pvals[0] = pool_value_alloc(); pvals2[2] = { NULL, NULL }; pool_value_set_name(pvals[0], "type"); pool_value_set_string(pvals[0], "pset"); reslist = pool_query_pool_resources(conf, my_pool, &nelem, pvals); pool_value_free(pvals[0]); pool_query_resource_components(conf, reslist[0], &nelem, NULL); printf("pool %s: %u cpu", my_pool_ name, nelem); pool_conf_close(conf);
以下示例列出了在应用程序的池 pset 中定义的所有资源池。
该示例的要点包括以下内容:
采用 PO_RDONLY 以只读方式打开动态 conf 文件。pool_query_pools() 将池列表返回到 pl 中,并将池数目返回到 nelem 中。对于每个池,请调用 pool_get_property() 以将 pool.name 属性从元素放入 pval 值中。
pool_get_property() 将调用 pool_to_elem() 以将 libpool 实体转换为不透明的值。pool_value_get_string() 将从不透明的池值中获取字符串。
conf = pool_conf_alloc(); pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY); pl = pool_query_pools(conf, &nelem, NULL); pval = pool_value_alloc(); for (i = 0; i < nelem; i++) { pool_get_property(conf, pool_to_elem(conf, pl[i]), "pool.name", pval); pool_value_get_string(pval, &fname); printf("%s\n", name); } pool_value_free(pval); free(pl); pool_conf_close(conf);
该示例的要点包括以下内容:
pool_query_pool_resources() 将获取 rl 中的所有资源的列表。由于 pool_query_pool_resources() 的最后一个参数为 NULL,因此将返回所有资源。对于每种资源,系统都会读取并列显 name、load 和 size 属性。
对 strdup() 的调用将分配本地内存并复制由 get_string() 返回的字符串。对 get_string() 的调用将返回一个指针,该指针由对 get_property() 的下一次调用释放。如果不包括对 strdup() 的调用,则对字符串的后续引用将导致应用程序出现故障,并出现段错误。
printf("pool %s\n:" pool_name); pool = pool_get_pool(conf, pool_name); rl = pool_query_pool_resources(conf, pool, &nelem, NULL); for (i = 0; i < nelem; i++) { pool_get_property(conf, pool_resource_to_elem(conf, rl[i]), "type", pval); pool_value_get_string(pval, &type); type = strdup(type); snprintf(prop_name, 32, "%s.%s", type, "name"); pool_get_property(conf, pool_resource_to_elem(conf, rl[i]), prop_name, pval); pool_value_get_string(val, &res_name); res_name = strdup(res_name); snprintf(prop_name, 32, "%s.%s", type, "load"); pool_get_property(conf, pool_resource_to_elem(conf, rl[i]), prop_name, pval); pool_value_get_uint64(val, &load); snprintf(prop_name, 32, "%s.%s", type, "size"); pool_get_property(conf, pool_resource_to_elem(conf, rl[i]), prop_name, pval); pool_value_get_uint64(val, &size); printf("resource %s: size %llu load %llu\n", res_name, size, load); free(type); free(res_name); } free(rl);
以下示例设置了 pset 的 pool.comment 属性。该示例还在 pool.newprop 中创建了新的属性。
该示例的要点包括以下内容:
在对 pool_conf_open() 的调用中,使用静态配置文件中的 PO_RDWR 要求调用方为超级用户。
要在运行此实用程序后提交对 pset 所做的更改,请发出 pooladm -c 命令。要使实用程序提交更改,请使用第二个非零参数调用 pool_conf_commit()。
pool_set_comment(const char *pool_name, const char *comment) { pool_t *pool; pool_elem_t *pool_elem; pool_value_t *pval = pool_value_alloc(); pool_conf_t *conf = pool_conf_alloc(); /* NOTE: need to be root to use PO_RDWR on static configuration file */ pool_conf_open(conf, pool_static_location(), PO_RDWR); pool = pool_get_pool(conf, pool_name); pool_value_set_string(pval, comment); pool_elem = pool_to_elem(conf, pool); pool_put_property(conf, pool_elem, "pool.comment", pval); printf("pool %s: pool.comment set to %s\n:" pool_name, comment); /* Now, create a new property, customized to installation site */ pool_value_set_string(pval, "New String Property"); pool_put_property(conf, pool_elem, "pool.newprop", pval); pool_conf_commit(conf, 0); /* NOTE: use 0 to ensure only */ /* static file gets updated */ pool_value_free(pval); pool_conf_close(conf); pool_conf_free(conf); /* NOTE: Use "pooladm -c" later, or pool_conf_commit(conf, 1) */ /* above for changes to the running system */ }
另一种修改池的注释并添加新的池属性的方法是使用 poolcfg(1M)。
poolcfg -c 'modify pool pool-name (string pool.comment = "cmt-string")' poolcfg -c 'modify pool pool-name (string pool.newprop = "New String Property")'
编写应用程序时,请考虑以下问题。
每个站点都可以向池配置中添加其自己的属性列表。
可以在多个配置文件中维护多个配置。系统管理员可以提交不同的文件,以反映在不同的时间段对资源占用情况的更改。根据负载条件,这些时间段可以包括不同的时间(日、周、月或季节)。
可以在池之间共享资源集,但是池只有一个给定类型的资源集。因此,可以在缺省应用程序数据库池与特定应用程序数据库池之间共享 pset_default。
请谨慎使用 pool_value_*() 接口。切记字符串池值的内存分配问题。请参见报告给定池的池统计信息。