如何强制执行资源限制

运行查询之前,Vertica 会确定该查询运行所需的内存量。如果查询含有在工厂类中实施 getPerInstanceResources() 函数的隔离模式 UDx,Vertica 将调用此函数以确定其所需的内存数量,并将此内存数量添加到查询所需的内存总量中。Vertica 会根据以下要求来确定如何处理查询:

  • 如果所需的内存总量(包括 UDx 报告的所需内存量)超过会话的 MEMORYCAP 或 资源池的 MAXMEMORYSIZE 设置,Vertica 将拒绝该查询。有关资源池的详细信息,请参阅资源池架构

  • 如果内存量低于会话所设置的限制和资源池限制,但目前没有足够的可用内存可用于运行查询,Vertica 会将该查询排入队列,直至足够资源变为可用为止。

  • 如果有足够的可用资源可用于运行查询,Vertica 会执行该查询。

如果执行 UDx 的进程尝试分配比 FencedUDxMemoryLimitMB 配置参数所设置的限制更多的内存,进程将收到 bad_alloc 异常。有关 FencedUDxMemoryLimitMB 的详细信息,请参阅为隔离模式 UDx 设置内存限制

下面是执行以下操作时的输出:加载使用 500 MB 内存的 UDSF,然后更改内存设置而导致发生内存不足错误。以下示例中的 MemoryAllocationExample UDSF 只是按照为 UDx 分配资源向 Vertica 通知资源要求中所示而更改的 Add2Ints UDSF 示例,用于分配 500 MB RAM。

=> CREATE LIBRARY mylib AS '/home/dbadmin/MemoryAllocationExample.so';
CREATE LIBRARY
=> CREATE FUNCTION usemem AS NAME 'MemoryAllocationExampleFactory' LIBRARY mylib
-> FENCED;
CREATE FUNCTION
=> SELECT usemem(1,2);
 usemem
--------
      3
(1 row)

以下语句演示了将会话的 MEMORYCAP 设置为比 UDSF 报告其使用的内存数量更低的值。此操作会导致 Vertica 在执行 UDSF 之前返回错误。

=> SET SESSION MEMORYCAP '100M';
SET
=> SELECT usemem(1,2);
ERROR 3596:  Insufficient resources to execute plan on pool sysquery
[Request exceeds session memory cap: 520328KB > 102400KB]
=> SET SESSION MEMORYCAP = default;
SET

如果 UDx 所需的内存量超过池中的可用容量, 资源池还会阻止该 UDx 运行。以下语句演示了所创建和使用的资源池具有太少内存而导致 UDSF 无法运行的结果。与会话的 MAXMEMORYCAP 限制相似,池的 MAXMEMORYSIZE 设置可防止 Vertica 执行包含该 UDSF 的查询。

=> CREATE RESOURCE POOL small MEMORYSIZE '100M' MAXMEMORYSIZE '100M';
CREATE RESOURCE POOL
=> SET SESSION RESOURCE POOL small;
SET
=> CREATE TABLE ExampleTable(a int, b int);
CREATE TABLE
=> INSERT /*+direct*/ INTO ExampleTable VALUES (1,2);
 OUTPUT
--------
      1
(1 row)
=> SELECT usemem(a, b) FROM ExampleTable;
ERROR 3596:  Insufficient resources to execute plan on pool small
[Request Too Large:Memory(KB) Exceeded: Requested = 523136, Free = 102400 (Limit = 102400, Used = 0)]
=> DROP RESOURCE POOL small; --Dropping the pool resets the session's pool
DROP RESOURCE POOL

最后,将 FencedUDxMemoryLimitMB 配置参数设置为比 UDx 实际分配的内存数量更低的值会导致该 UDx 抛出异常。此示例与前两个示例之一是不同情况,因为实际上会执行该查询。UDx 的代码需要捕获并处理该异常。在此示例中,该代码使用 vt_report_error 宏将错误报告回 Vertica 并退出。

=> ALTER DATABASE DEFAULT SET FencedUDxMemoryLimitMB = 300;

=> SELECT usemem(1,2);
    ERROR 3412:  Failure in UDx RPC call InvokeSetup(): Error calling setup() in
    User Defined Object [usemem] at [MemoryAllocationExample.cpp:32], error code:
     1, message: Couldn't allocate memory :[std::bad_alloc]

=> ALTER DATABASE DEFAULT SET FencedUDxMemoryLimitMB = -1;

=> SELECT usemem(1,2);
 usemem
--------
      3
(1 row)

另请参阅