本部分中的场景介绍常见的工作负载管理问题,并提供带示例的解决方案。
将用户定义的池和用户配置文件用于工作负载管理
- 1: 周期性批量加载
- 2: CEO 查询
- 3: 防止失控查询
- 4: 限制临时查询应用程序的资源使用率
- 5: 为应用程序设置硬性并发限制
- 6: 处理混合工作负载:批处理与交互式处理
- 7: 对不同用户发出的查询设置优先级
- 8: 持续加载和查询
- 9: 确定运行时短查询的优先级
- 10: 删除运行时较长查询的优先级
1 - 周期性批量加载
场景
您每天晚上都执行批量加载,偶尔(很少)在白天执行批量加载。当加载正在运行时,减少查询的资源使用量是可接受的,但在其他所有时间,您希望所有资源都可用于查询。
解决方案
为加载创建一个单独的资源池,使其优先级高于内置 GENERAL 池上的预配置设置。
在此场景中,在从 GENERAL 池中借用内存时,每天晚上的加载具有优先权。在没有运行加载时,所有内存将可自动用于查询。
示例
创建一个优先级高于 GENERAL 池的资源池:
-
创建 PRIORITY 设置为 10 的资源池
load_pool
:=> CREATE RESOURCE POOL load_pool PRIORITY 10;
-
修改用户
load_user
以使用新的资源池:=> ALTER USER load_user RESOURCE POOL load_pool;
2 - CEO 查询
场景
CEO 在每周一的上午 9 点运行报告,您想要确保该报告始终运行。
解决方案
若要确保某个查询或某类查询始终获得资源,可以为其创建专用池,如下所示:
-
使用 PROFILE 命令,运行 CEO 每周运行的查询,确定应当分配的内存量:
=> PROFILE SELECT DISTINCT s.product_key, p.product_description -> FROM store.store_sales_fact s, public.product_dimension p -> WHERE s.product_key = p.product_key AND s.product_version = p.product_version -> AND s.store_key IN ( -> SELECT store_key FROM store.store_dimension -> WHERE store_state = 'MA') -> ORDER BY s.product_key;
-
在查询结束时,系统返回一条含有资源使用量的通知:
NOTICE: Statement is being profiled.HINT: select * from v_monitor.execution_engine_profiles where transaction_id=45035996273751349 and statement_id=6; NOTICE: Initiator memory estimate for query: [on pool general: 1723648 KB, minimum: 355920 KB]
-
创建具有上述提示所报告的 MEMORYSIZE 的资源池,确保至少为 CEO 查询保留此内存大小:
=> CREATE RESOURCE POOL ceo_pool MEMORYSIZE '1800M' PRIORITY 10; CREATE RESOURCE POOL => \x Expanded display is on. => SELECT * FROM resource_pools WHERE name = 'ceo_pool'; -[ RECORD 1 ]-------+------------- name | ceo_pool is_internal | f memorysize | 1800M maxmemorysize | priority | 10 queuetimeout | 300 plannedconcurrency | 4 maxconcurrency | singleinitiator | f
-
假设 CEO 报告用户已存在,使用 ALTER USER 语句将此用户与上述资源池相关联。
=> ALTER USER ceo_user RESOURCE POOL ceo_pool;
-
发出以下命令确认 ceo_user 与 ceo_pool 相关联:
=> SELECT * FROM users WHERE user_name ='ceo_user'; -[ RECORD 1 ]-+------------------ user_id | 45035996273713548 user_name | ceo_user is_super_user | f resource_pool | ceo_pool memory_cap_kb | unlimited
如果 CEO 查询内存使用量过大,可以让资源管理器将其降至符合特定预算的水平。请参阅查询预算。
3 - 防止失控查询
场景
Joe 是一位经常在中午运行大型报告的业务分析员,这些报告占用了整个机器的资源。您想要防止 Joe 使用超过 100MB 的内存,并且想要将 Joe 的查询运行时间限制在 2 小时以内。
解决方案
用户配置文件 为此场景提供了一个解决方案。若要限制 Joe 一次可以使用的内存量,使用 ALTER USER 命令将 Joe 的 MEMORYCAP 设置为 100MB。若要限制 Joe 的查询可以运行的时间长度,使用相同的命令将 RUNTIMECAP 设置为 2 小时。如果 Joe 运行的查询超过其最高限值,Vertica 会拒绝该查询。
如果您有一批需要限制查询的用户,也可以为他们创建一个资源池并为该资源池设置 RUNTIMECAP。将这些用户移至此资源池后,Vertica 会将这些用户的所有查询限制为您为该资源池指定的 RUNTIMECAP。
示例
=> ALTER USER analyst_user MEMORYCAP '100M' RUNTIMECAP '2 hours';
如果 Joe 尝试运行超过 100MB 的查询,系统会返回一个错误,说明请求超出内存会话限制,如以下示例所示:
\i vmart_query_04.sqlvsql:vmart_query_04.sql:12: ERROR: Insufficient resources to initiate plan
on pool general [Request exceeds memory session limit: 137669KB > 102400KB]
只有系统数据库管理员 (dbadmin) 可以提高 MEMORYCAP 设置。用户不能提高自己的 MEMORYCAP 设置,如果他们尝试编辑其 MEMORYCAP 或 RUNTIMECAP 设置,则将看到类似于以下内容的错误:
ALTER USER analyst_user MEMORYCAP '135M';
ROLLBACK: permission denied
4 - 限制临时查询应用程序的资源使用率
场景
您最近将数据仓库提供给一大群用户,而他们并不熟悉 SQL。一些用户对大量的行运行报告,耗尽了系统资源。您想要制约这些用户的系统使用量。
解决方案
-
为 MAXMEMORYSIZE 等于 MEMORYSIZE 的临时应用程序创建资源池。这可以防止该资源池中的查询从 GENERAL 池中借用资源。另外,设置 RUNTIMECAP 以限制临时查询的最大持续时间。
=> CREATE RESOURCE POOL adhoc_pool MEMORYSIZE '200M' MAXMEMORYSIZE '200M' RUNTIMECAP '20 seconds' PRIORITY 0 QUEUETIMEOUT 300 PLANNEDCONCURRENCY 4; => SELECT pool_name, memory_size_kb, queueing_threshold_kb FROM V_MONITOR.RESOURCE_POOL_STATUS WHERE pool_name='adhoc_pool'; pool_name | memory_size_kb | queueing_threshold_kb ------------+----------------+----------------------- adhoc_pool | 204800 | 153600 (1 row)
-
将此资源池与应用程序用于连接到数据库的数据库用户相关联。
=> ALTER USER app1_user RESOURCE POOL adhoc_pool;
提示
其他解决方案包括像在防止失控查询中一样限制单个用户的内存使用量。5 - 为应用程序设置硬性并发限制
场景
为了便于开票,分析员 Jane 希望对此应用程序的并发性实施硬性限制。如何做到这一点?
解决方案
最简单的解决方案是为该应用程序的用户创建一个单独的资源池,并将其 MAXCONCURRENCY 设置为所需的并发级别。任何超过 MAXCONCURRENCY 的查询都会进入队列。
提示
Vertica 建议将 PLANNEDCONCURRENCY 保留为默认级别,以便查询获得最大的资源量。从而使整个系统以最高效率运行。示例
在本示例中,存在四位与开票池相关联的开票用户。目的是对资源池设置硬性限制,使一次最多可以执行三个并发查询。所有其他查询将排队并在资源释放后完成。
=> CREATE RESOURCE POOL billing_pool MAXCONCURRENCY 3 QUEUETIMEOUT 2;
=> CREATE USER bill1_user RESOURCE POOL billing_pool;
=> CREATE USER bill2_user RESOURCE POOL billing_pool;
=> CREATE USER bill3_user RESOURCE POOL billing_pool;
=> CREATE USER bill4_user RESOURCE POOL billing_pool;
=> \x
Expanded display is on.
=> select maxconcurrency,queuetimeout from resource_pools where name = 'billing_pool';
maxconcurrency | queuetimeout
----------------+--------------
3 | 2
(1 row)
> SELECT reason, resource_type, rejection_count FROM RESOURCE_REJECTIONS
WHERE pool_name = 'billing_pool' AND node_name ilike '%node0001';
reason | resource_type | rejection_count
---------------------------------------+---------------+-----------------
Timedout waiting for resource request | Queries | 16
(1 row)
如果查询正在运行并且没有在规定时间内完成(默认超时设置为 5 分钟),请求的下一查询将收到一条类似于以下内容的错误:
ERROR: Insufficient resources to initiate plan on pool billing_pool [Timedout waiting for resource request: Request exceeds limits:
Queries Exceeded: Requested = 1, Free = 0 (Limit = 3, Used = 3)]
下表显示在开票池中存在三个活动查询。
=> SELECT pool_name, thread_count, open_file_handle_count, memory_inuse_kb FROM RESOURCE_ACQUISITIONS
WHERE pool_name = 'billing_pool';
pool_name | thread_count | open_file_handle_count | memory_inuse_kb
--------------+--------------+------------------------+-----------------
billing_pool | 4 | 5 | 132870
billing_pool | 4 | 5 | 132870
billing_pool | 4 | 5 | 132870
(3 rows)
6 - 处理混合工作负载:批处理与交互式处理
场景
您具有一个带交互门户的 Web 应用程序。有时,当 IT 人员运行批处理报告时,Web 页面需要很长时间才能刷新,引起用户抱怨,因此您想要为网站用户提供更好的体验。
解决方案
可以应用先前场景中学习到的原则解决此问题。基本思想是将查询分离成与不同资源池相关联的两组。先决条件是存在两个不同的数据库用户,他们发出不同类型的查询。如果情况与此不同,请将此视为应用程序设计的最佳方法。
方法 1
: 创建专门用于 Web 页面刷新查询的资源池,同时:
-
根据查询的平均资源需求以及门户中发出的并发查询的预期数量来设定资源池大小。
-
将此资源池与运行网站查询的数据库用户相关联。有关创建专用池的信息,请参阅CEO 查询。
这可确保网站查询始终运行并且从不排列在大型批处理作业之后。让处理作业不在 GENERAL 池上运行。
例如,以下池是根据从 Web 运行的查询所需的平均资源量以及并发查询的预期数量来确定的。另外,它给予 Web 查询的优先级要高于任何正在运行的批处理作业,并假定将查询调整为每个查询占用 250M:
=> CREATE RESOURCE POOL web_pool
MEMORYSIZE '250M'
MAXMEMORYSIZE NONE
PRIORITY 10
MAXCONCURRENCY 5
PLANNEDCONCURRENCY 1;
方法 2
创建具有固定内存大小的资源池。这将限制批处理报告可用的内存量,使内存始终留作其他用途。有关详细信息,请参阅限制临时查询应用程序的资源使用率。
例如:
=> CREATE RESOURCE POOL batch_pool
MEMORYSIZE '4G'
MAXMEMORYSIZE '4G'
MAXCONCURRENCY 10;
如果您有三个或更多不同类别的工作负载,此原则同样适用。
7 - 对不同用户发出的查询设置优先级
场景
您希望一个部门的用户查询比另一个部门的查询具有更高的优先级。
解决方案
解决方案类似于混合工作负载场景。在此场景中,您没有限制资源使用量;您设置了不同的优先级。若要这样做,可创建两个不同的池,每个池都具有 MEMORYSIZE=0% 以及一个不同的 PRIORITY 参数。这两个池都从 GENERAL 池中借用资源,但在争夺资源时,优先级决定了每个池的请求获得批准的顺序。例如:
=> CREATE RESOURCE POOL dept1_pool PRIORITY 5;
=> CREATE RESOURCE POOL dept2_pool PRIORITY 8;
如果您发现此解决方案不足以满足需要,或者一个部门的查询一直使另一个部门的用户难以执行查询,则可以通过设置 MEMORYSIZE 为每个池添加预留,这样会保证每个部门都可以使用一些内存。
例如,两个资源都使用 GENERAL 池获取内存,所以您可以通过使用 ALTER RESOURCE POOL 更改每个池的 MEMORYSIZE,为每个资源池分配一些内存。
=> ALTER RESOURCE POOL dept1_pool MEMORYSIZE '100M';
=> ALTER RESOURCE POOL dept2_pool MEMORYSIZE '150M';
8 - 持续加载和查询
场景
您希望应用程序运行连续加载流,但许多应用程序运行的是并行查询流。您希望确保性能是可预计的。
解决方案
此场景的解决方案取决于您的查询组合。在所有情况下,以下方法均适用:
-
确定所需的连续加载流数量。如果单个流没有提供足够的吐吞量,则这可能与所需加载速率有关,或者与要加载的数据源数量有更直接的关系。为加载创建一个专用资源池,并将其与要执行加载的数据库用户相关联。有关详细信息,请参阅CREATE RESOURCE POOL。
通常,加载池的并行设置应少于每个节点的内核数。除非源进程较慢,否则会更高效地为每个加载贡献更多内存,并且具有更多的加载队列。如果预计有队列,请调整加载池的 QUEUETIMEOUT 设置。
-
运行加载工作负载一会儿,观察加载性能是否符合预期。如果 Tuple Mover 没有经过充分优化以涵盖加载行为,请参阅管理 Tuple Mover。
-
如果系统中有多种类型的查询(例如,对于某些查询,必须为交互用户快速提供答复,而其他查询属于批量报告处理的一部分),请遵循处理混合工作负载:批处理与交互式处理中的准则。
-
运行查询并观察性能。如果某些类别的查询没有按预期执行,那么您可能需要按照限制临时查询应用程序的资源使用率中所述调整 GENERAL 池,或者为这些查询创建更多专用资源池。有关详细信息,请参阅CEO 查询和处理混合工作负载:批处理与交互式处理。
有关在混合工作负载环境中获得可预测结果的信息,请参阅关于管理工作负载和CREATE RESOURCE POOL的部分。
9 - 确定运行时短查询的优先级
场景
您最近为没有 SQL 方面经验并且经常运行临时报表的用户创建了一个资源池。到目前为止,您通过创建 MEMORYSIZE 和 MAXMEMORYSIZE 相等的资源池来管理资源分配。这可以防止该资源池中的查询从 GENERAL 池中借用资源。现在,您希望在运行时管理资源并优先考虑短查询,使其不会因为运行时资源有限而排队。
解决方案
-
将资源池的
RUNTIMEPRIORITY
设置为 MEDIUM 或 LOW。 -
将资源池的
RUNTIMEPRIORITYTHRESHOLD
设置为您希望确保始终以较高优先级运行的查询的持续时间。
例如:
=> ALTER RESOURCE POOL ad_hoc_pool RUNTIMEPRIORITY medium RUNTIMEPRIORITYTHRESHOLD 5;
由于 RUNTIMEPRIORITYTHRESHOLD
设置为 5,因此资源池 ad_hoc_pool
中在 5 秒内完成的所有查询都以高优先级运行。超过 5 秒的查询将下降到分配给该资源池的 RUNTIMEPRIORITY
MEDIUM。
10 - 删除运行时较长查询的优先级
场景
您希望资源池中的大部分查询以 HIGH 运行时优先级运行,但能够将长于 1 小时的作业调整为更低的优先级。
解决方案
将资源池的 RUNTIMEPRIORITY 设置为 LOW,将 RUNTIMEPRIORITYTHRESHOLD 设置为一个仅截断最长作业的数值。
示例
要确保向所有持续时间长于 3600 秒(1 小时)的查询分配低运行时优先级,请按如下所示修改资源池:
-
将 RUNTIMEPRIORITY 设置为 LOW。
-
将 RUNTIMETHRESHOLD 设置为 3600
=> ALTER RESOURCE POOL ad_hoc_pool RUNTIMEPRIORITY low RUNTIMEPRIORITYTHRESHOLD 3600;