内存满的排查过程

内存用满问题

环境准备
1 新建资源规格
#drop resource unit u1_mysql;
create resource unit u1_mysql max_cpu=1,min_cpu=1,max_memory=‘2G’,min_memory=‘2G’,max_iops=128,max_disk_size=‘20G’,max_session_num=100;

2 新建资源池
create resource pool pool_mysql unit=‘u1_mysql’,unit_num=1,zone_list=(‘zone1’,‘zone2’,‘zone3’) ;

3 新建 mysql 租户
#CREATE TENANT IF NOT EXISTS ob_mysql charset=‘utf8mb4’,resource_pool_list=(‘pool_mysql’) ,zone_list=(‘zone1’,‘zone2’,‘zone3’), PRIMARY_ZONE=‘zone1,zone2;zone3’SET ob_tcp_invited_nodes=’%’, ob_compatibility_mode=‘mysql’;

CREATE TENANT IF NOT EXISTS ob_mysql charset=‘utf8mb4’,resource_pool_list=(‘pool_mysql’) ,zone_list=(‘zone1’), PRIMARY_ZONE=‘zone1’ SET ob_tcp_invited_nodes=’%’, ob_compatibility_mode=‘mysql’;

SELECT * FROM oceanbase.gv$tenant where tenant_name=‘ob_mysql’;

#sql_audit_percentage参数 和ob_query_timeout参数 再换着试试

操作步骤
1 安装部署sysbench 工具
yum install -y sysbench
sysbench --version

2 创建 sbtest 数据库,准备对 ob_mysql 租户进行压力测试, 注意 sysbench 工具目前仅支持 MySQL 租户
obclient -h127.0.0.1 -P2883 -uroot@ob_mysql#obce_test
mysql> create database sbtest;

3 初始化测试表
sysbench /usr/share/sysbench/oltp_read_write.lua --tables=20 --table-size=200000 --mysql-host=127.0.0.1 --mysql-port=2883 --mysql-user=root@ob_mysql --threads=100 --report-interval=10 --time=60 --db-driver=mysql --db-ps-mode=disable cleanup

4 准备测试数据
sysbench /usr/share/sysbench/oltp_read_write.lua --tables=20 --table-size=200000 --mysql-host=127.0.0.1 --mysql-port=2883 --mysql-user=root@ob_mysql --threads=100 --report-interval=10 --time=60 --db-driver=mysql --db-ps-mode=disable prepare
注意:如果此步骤报错, 记录错误代码,如下截屏 , insert 语句向表 sbtest7 插入时报错, 下一步执行可以忽略, 目的是能看到应用由于内存不够报错(注意:本实验展示错误代码为 4030,实际环境中会有其他 40xx 的报错,后续步骤根据实际报错代码进行查询)

#FATAL: mysql_drv_query() returned error 4030 (Over tenant memory limits) for query 'INSERT INTO sbtest8(k, c, pad) VALUES(100782, '60544635103-31366196493-95558437650-32244069089-319

5 运行测试,如果上个步骤已经看到错误,可以忽略此步骤
sysbench /usr/share/sysbench/oltp_read_write.lua --tables=20 --table-size=200000 --mysql-host=127.0.0.1 --mysql-port=2883 --mysql-user=root@ob_mysql --threads=100 --report-interval=10 --time=60 --db-driver=mysql --db-ps-mode=disable prepare run

6 看到由于内存不够,引起测试命令报错,查看内存模块使用情况,按照使用内存容量继续排序
select context,count,used,alloc_count,free_count from v$memory where
TENANT_ID=1002 order by used desc limit 10;

±------------------±------±----------±------------±-----------+
| context | count | used | alloc_count | free_count |
±------------------±------±----------±------------±-----------+
| OB_MEMSTORE | 123 | 257832600 | 0 | 0 |
| TransAudit | 1 | 104855040 | 0 | 0 |
| MysqlRequesReco | 6 | 90444800 | 0 | 0 |
| OB_SQL_PHY_PLAN | 278 | 53045528 | 0 | 0 |
| OB_SQL_PLAN_CACHE | 416 | 27457667 | 0 | 0 |
| OB_KVSTORE_CACHE | 3 | 6288384 | 0 | 0 |
| LogAggreBuffer | 40 | 2621440 | 0 | 0 |
| MemtableCallbac | 273 | 2236416 | 0 | 0 |
| Election | 1 | 2096128 | 0 | 0 |
| ElectionGroup | 1 | 2096128 | 0 | 0 |
±------------------±------±----------±------------±-----------+
10 rows in set (0.012 sec)

7 查看 gv$sql_audit 中此 SQL 语句的执行情况, 可以看到数据字典中已经存放了这个 SQL的 trace_id, 记录此 trace_id 准备下个步骤
注意:错误代码及表名称根据实际反馈进行修改

select svr_ip,query_sql,sql_id,plan_id, trace_id,rpc_count,plan_type,elapsed_time,
get_plan_time from gv$sql_audit where ret_code= ‘-4030’ and query_sql like ‘%sbtest9%’ order by elapsed_time limit 5 \G

sql_id: 613E5368B572A7E2C8E1613C2DB3DEEB
plan_id: 8
trace_id: YB427F000001-0005F90516C9C18C-0-0
rpc_count: 0
plan_type: 1
elapsed_time: 72272
get_plan_time: 3534
1 row in set (0.028 sec)

8 在 observer.log 或者前一个日志中查询此 trace_id , 可以关联 sysbench 的执行时间
grep YB427F000001-0005F90516C9C18C-0-0 /home/admin/oceanbase/log/observer.log --如果此文件中没有结果,搜索前一个 observer 日志文件
grep YB427F000001-0005F90516C9C18C-0-0 /root/observer/log/observer.log

grep YB427F000001-0006047F0FE6F23A-0-0 /root/observer/log/observer.log

打开此文件查询相关详细信息,发现日志文件报告 memstore 内存到达上限的错误。确认是memstore 的内容总容量不够引起应用报错。

[2023-04-11 10:09:36.755572] WARN [STORAGE] check_query_allowed (ob_partition_service.cpp:3800) [2046][0][YB427F000001-0005F90516C9C18C-0-0] [lt=4] [dc=0] this tenant is already out of memstore limit(tenant_id=1002, ret=-4030)

9 再次执行 sysbench 压测,将 tables 个数减为 5,看到执行成功,查看各内存模块使用情况
sysbench /usr/share/sysbench/oltp_read_write.lua --tables=5 --table-size=200000 --mysql-host=127.0.0.1 --mysql-port=2883 --mysql-user=root@ob_mysql --threads=100 --report-interval=10 --time=60 --db-driver=mysql --db-ps-mode=disable cleanup
sysbench /usr/share/sysbench/oltp_read_write.lua --tables=5 --table-size=200000 --mysql-host=127.0.0.1 --mysql-port=2883 --mysql-user=root@ob_mysql --threads=100 --report-interval=10 --time=60 --db-driver=mysql --db-ps-mode=disable prepare
sysbench /usr/share/sysbench/oltp_read_write.lua --tables=5 --table-size=200000 --mysql-host=127.0.0.1 --mysql-port=2883 --mysql-user=root@ob_mysql --threads=100 --report-interval=10 --time=60 --db-driver=mysql --db-ps-mode=disable run

select context,count,used,alloc_count,free_count from v$memory where
TENANT_ID=1002 order by used desc limit 10;

结论: 在租户总内存为 2GB 的场景中, 模拟多用户应用并发, 由于内存不够引起应用报错,查询数据字典获取各个内存的消耗情况。判断某个内存模块不够时的处理方法,本例中由于 memstore 内存不够时,可能需要扩容租户总量。

设置限流

alter system set writing_throttling_trigger_percentage=90 tenant= ‘ob_test’ !
示例:假设租户的memstore内存大小为10GB,并做了如下配置
writing_throttling_trigger_percentage = 90;
writing_throttling_maximum_duration = ‘1h’;
当租户的memstore内存写满90%时,触发写入限速,
限速的速率为:10 * 1024MB * (1-0.9)/ 3600 = 1024MB / 3600 = 0.28MB / s

1 个赞

真不错 :face_in_clouds: :face_in_clouds: