OceanBase的內(nèi)存限制

- CTX內(nèi)存限制
- 大部分 CTX 有內(nèi)存大小限制,KVCACHE 沒有。實(shí)際分配內(nèi)存時,會檢查是否超過 CTX 內(nèi)存限制,超出則報錯,比如 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)
- 租戶內(nèi)存限制
- 租戶內(nèi)所有 CTX 的內(nèi)存大小設(shè)置加起來允許超過租戶內(nèi)存大小
- 實(shí)際分配內(nèi)存時,如果超過租戶內(nèi)存大小限制,會報錯: No memory or reach tenant memory limit( msg=tenant memory has reached the )
- observer 級別的內(nèi)存限制
- 創(chuàng)建租戶時所有租戶內(nèi)存+system_memory(500租戶預(yù)留內(nèi)存) 不能超過這個限制
- 500 租戶的內(nèi)存實(shí)際沒有上限
- 集群運(yùn)行時,所有租戶實(shí)際分配內(nèi)存時,如果超過這個限制,會報錯 over total memory limit。
內(nèi)存排查思路
內(nèi)存排查順序:
- 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 個示例展示不同級別內(nèi)存超限的表現(xiàn)。
1. server 級別內(nèi)存超限
報錯:超出 observer 總內(nèi)存
日志解讀:
- oops, over total memory limit, hold=13128171520 limit=13324949913 表示超過了 observer 的內(nèi)存上限
- oops, alloc failed, tenant_id=500 表示SQL執(zhí)行時 500 租戶分配內(nèi)存報錯,超過了observer 的內(nèi)存上限
1.1 通過 __all_virtual_server_memory_info 查看 OBServer 的內(nèi)存使用情況:
- server_memory_limit 即為每個 observer 的內(nèi)存上限
- server_memory_hold:OBServer已分配內(nèi)存
- system_reserved:為500租戶保留的內(nèi)存,由system_memory直接指定。但是這個不是硬限制,只是預(yù)留給 500租戶的,實(shí)際上可以超過這個值。
此案例中報錯太快,查詢 __all_virtual_server_memory_info 來不及觀察到 server 內(nèi)存用滿
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 內(nèi)存使用情況
500租戶中 DEFAULT_CTX_ID 這個內(nèi)存上下文使用的內(nèi)存最多:
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 的內(nèi)存使用情況
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)
結(jié)論:500租戶使用內(nèi)存過多,測試租戶分配內(nèi)存時,所有租戶使用的總內(nèi)存加起來超過了 memory_limit 限制,導(dǎo)致分配內(nèi)存報錯。500租戶的 DEFAULT_CTX_ID 上下文使用內(nèi)存最多,其中又以 CallbackTask、LinearHashMap、ConcurObjPool 這3個 mode 使用的內(nèi)存最多,無法看出原因。測試環(huán)境中嘗試重啟集群,只釋放了少量 500 租戶內(nèi)存。
2. 租戶內(nèi)存超限
報錯租戶總內(nèi)存超限,具體報在 plan cache 上。日志如下:
2.1查看租戶總使用內(nèi)存:
select * from gv$tenant_memory_info where tenant_id=1002;
2.2 查看租戶的CTX內(nèi)存使用情況:
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 內(nèi)存使用情況:
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;
結(jié)論:這個例子中報錯太快了,來不及觀察租戶哪塊內(nèi)存使用量增加明顯(包括日志中每隔10秒輸出的內(nèi)存使用情況也抓不到),報錯后再觀察已經(jīng)看不出異常??偟膩碚f是租戶總使用內(nèi)存太多,當(dāng)獲取 plan cache 時已經(jīng)超出租戶內(nèi)存上限,然后報錯,這不是 plan cache 設(shè)置太大導(dǎo)致的。
3. work area 內(nèi)存上下文超限
work area 超出限制,日志表現(xiàn):
解決:調(diào)大租戶變量ob_sql_work_area_percentage