OceanBase的内存限制
- CTX内存限制
- 大部分 CTX 有内存大小限制,KVCACHE 没有。实际分配内存时,会检查是否超过 CTX 内存限制,超出则报错,比如 work area 超出限制的报错:alloc failed reason: ctx memory has reached the upper limit(ctx_name: WORK_AREA, ctx_hold: 320864256, ctx_limit: 322122545, alloc_size: 2097152)
- 租户内存限制
- 租户内所有 CTX 的内存大小设置加起来允许超过租户内存大小
- 实际分配内存时,如果超过租户内存大小限制,会报错: No memory or reach tenant memory limit( msg=tenant memory has reached the )
- observer 级别的内存限制
- 创建租户时所有租户内存+system_memory(500租户预留内存) 不能超过这个限制
- 500 租户的内存实际没有上限
- 集群运行时,所有租户实际分配内存时,如果超过这个限制,会报错 over total memory limit。
内存排查思路
内存排查顺序:
- server 级别:gv$sysstat、__all_virtual_server_memory_info
- 租户级别:gv$tenant_memory_info
- 上下文级别:__all_virtual_tenant_ctx_memory_info
- mod 级别:__all_virtual_memory_info、gv$memory
下面用 3 个示例展示不同级别内存超限的表现。
1. server 级别内存超限
报错:超出 observer 总内存日志解读:
- oops, over total memory limit, hold=13128171520 limit=13324949913 表示超过了 observer 的内存上限
- oops, alloc failed, tenant_id=500 表示SQL执行时 500 租户分配内存报错,超过了observer 的内存上限
1.1 通过 __all_virtual_server_memory_info 查看 OBServer 的内存使用情况:
- server_memory_limit 即为每个 observer 的内存上限
- server_memory_hold:OBServer已分配内存
- system_reserved:为500租户保留的内存,由system_memory直接指定。但是这个不是硬限制,只是预留给 500租户的,实际上可以超过这个值。
此案例中报错太快,查询 __all_virtual_server_memory_info 来不及观察到 server 内存用满
obclient [oceanbase]> select * from __all_virtual_server_memory_info;
+--------------+----------+--------------------+---------------------+-----------------+----------------------+---------------------+----------------------+----------------+
| svr_ip | svr_port | server_memory_hold | server_memory_limit | system_reserved | active_memstore_used | total_memstore_used | major_freeze_trigger | memstore_limit |
+--------------+----------+--------------------+---------------------+-----------------+----------------------+---------------------+----------------------+----------------+
| 10.186.58.85 | 2882 | 13058965504 | 13324949913 | 1073741824 | 695938400 | 704643072 | 7350724853 | 8575845662 |
| 10.186.58.87 | 2882 | 13077839872 | 13323580211 | 1073741824 | 637244800 | 645922816 | 7349903032 | 8574886870 |
| 10.186.58.86 | 2882 | 13031702528 | 13324949913 | 1073741824 | 628860000 | 637534208 | 7350724853 | 8575845662 |
+--------------+----------+--------------------+---------------------+-----------------+----------------------+---------------------+----------------------+----------------+
3 rows in set (0.029 sec)
1.2 查看 500 租户的 CTX 内存使用情况
500租户中 DEFAULT_CTX_ID 这个内存上下文使用的内存最多:
obclient [oceanbase]> SELECT tenant_id,ctx_name, sum(hold) FROM __all_virtual_tenant_ctx_memory_info WHERE svr_ip = '10.186.58.85' AND svr_port=2882 and tenant_id=500 GROUP BY ctx_name HAVING sum(hold)>0 order by 3 desc;
+-----------+--------------------------------+------------+
| tenant_id | ctx_name | sum(hold) |
+-----------+--------------------------------+------------+
| 500 | DEFAULT_CTX_ID | 5314183168 |
| 500 | CO_STACK | 1992987216 |
| 500 | STORAGE_SHORT_TERM_META_CTX_ID | 220200960 |
| 500 | LIBEASY | 195035136 |
| 500 | GLIBC | 171966464 |
| 500 | STORAGE_LONG_TERM_META_CTX_ID | 46137344 |
| 500 | LOGGER_CTX_ID | 29360128 |
| 500 | WORK_AREA | 16777216 |
| 500 | REPLAY_STATUS_CTX_ID | 14680064 |
+-----------+--------------------------------+------------+
9 rows in set (0.004 sec)
1.3 查看 500 租户中具体 mode 的内存使用情况
obclient [oceanbase]> select ctx_name,mod_name, mod_type, round(sum(hold)/1024/1024) as hold_mb, round(sum(used)/1024/1024) as used_mb, sum(count) as count from __all_virtual_memory_info where tenant_id=500 and svr_ip= '10.186.58.85' group by ctx_name, mod_name,mod_type order by used_mb desc, count desc limit 10;
+----------------+------------------+----------+---------+---------+-------+
| ctx_name | mod_name | mod_type | hold_mb | used_mb | count |
+----------------+------------------+----------+---------+---------+-------+
| CO_STACK | CO_STACK | user | 1901 | 1901 | 1 |
| DEFAULT_CTX_ID | CallbackTask | user | 812 | 809 | 223 |
| DEFAULT_CTX_ID | LinearHashMap | user | 494 | 493 | 7090 |
| DEFAULT_CTX_ID | ConcurObjPool | user | 421 | 418 | 4639 |
| DEFAULT_CTX_ID | OB_KVSTORE_CACHE | user | 270 | 264 | 10 |
| GLIBC | glibc_malloc | user | 156 | 135 | 39938 |
| DEFAULT_CTX_ID | FixeSizeBlocAll | user | 136 | 128 | 5 |
| DEFAULT_CTX_ID | LogHotCache | user | 132 | 128 | 2 |
| DEFAULT_CTX_ID | LightyQueue | user | 149 | 127 | 39 |
| DEFAULT_CTX_ID | ClogMgr | user | 122 | 120 | 5 |
+----------------+------------------+----------+---------+---------+-------+
10 rows in set (0.032 sec)
结论:500租户使用内存过多,测试租户分配内存时,所有租户使用的总内存加起来超过了 memory_limit 限制,导致分配内存报错。500租户的 DEFAULT_CTX_ID 上下文使用内存最多,其中又以 CallbackTask、LinearHashMap、ConcurObjPool 这3个 mode 使用的内存最多,无法看出原因。测试环境中尝试重启集群,只释放了少量 500 租户内存。
2. 租户内存超限
报错租户总内存超限,具体报在 plan cache 上。日志如下:2.1查看租户总使用内存:
select * from gv$tenant_memory_info where tenant_id=1002;
2.2 查看租户的CTX内存使用情况:
SELECT tenant_id,ctx_name, sum(hold) FROM __all_virtual_tenant_ctx_memory_info WHERE svr_ip = '10.186.58.85' AND svr_port=2882 and tenant_id=1002 GROUP BY ctx_name HAVING sum(hold)>0 order by 3 desc;
2.3 查看租户的 mode 内存使用情况:
select * from gv$memory where tenant_id=1002 and IP='10.186.58.85' order by USED desc limit 10;
或者:
select ctx_name,mod_name, mod_type, round(sum(hold)/1024/1024) as hold_mb, round(sum(used)/1024/1024) as used_mb, sum(count) as count from __all_virtual_memory_info where tenant_id=1002 and svr_ip= '10.186.58.85' group by ctx_name, mod_name,mod_type order by used_mb desc, count desc limit 10;
结论:这个例子中报错太快了,来不及观察租户哪块内存使用量增加明显(包括日志中每隔10秒输出的内存使用情况也抓不到),报错后再观察已经看不出异常。总的来说是租户总使用内存太多,当获取 plan cache 时已经超出租户内存上限,然后报错,这不是 plan cache 设置太大导致的。
3. work area 内存上下文超限
work area 超出限制,日志表现:解决:调大租户变量ob_sql_work_area_percentage