性能文章>一次MySql加载量太大导致程序数据库无响应的排查过程>

一次MySql加载量太大导致程序数据库无响应的排查过程转载

2月前
170412

导读

 
今天,系统中的一个业务处理莫名地执行了6个小时都没有结束,正常处理也就是3分钟左右,对原因进行定位,发现是在Oracle客户端上同步执行一个命令没有响应。今天来分享一下这个问题,让更多的人避开这个坑。
 

正文

1、业务场景

 
我们要把一个csv文件(文件名biz.csv)中的数据读取到Oracle数据库表(表名t_biz,t_biz)中,数据库表t_biz表结构如下:
 
 
biz.csv文件内容如下:
 
id,a,b,c
1,a1,b1,c1
2,a2,b2,c2
3,a3,b3,c3
把biz.csv文件的内容读入到表t_biz,为了提高效率,这里使用了sqlldr 命令,命令如下:
 
sqlldr test/test123@biz control=/home/jinjunzhu/biz/T_BIZ.ctl log=/home/jinjunzhu/biz/T_BIZ.log bad=/home/jinjunzhu/biz/T_BIZ.bad
 
解释一下这个命令,test/test123 是要访问的数据库实例的用户名/密码,biz 是数据库实例名称。T_BIZ.ctl是控制文件,内容如下:
 
options(skip=1,rows=10000,errors=0,parallel=true,bindsize=1048576,readsize=1048576)
load data 
infile '/home/jinjunzhu/biz/biz.csv'
fields terminated by ','
truncate into table day_data
trailing nullcols
(id,a,b,c)
业务代码中调用这个命令,代码如下:
 
private int execute(String cmd) throws Exception{
    Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
    process.waitFor(10, TimeUnit.SECONDS);
    Integer status = process.waitFor();
    return status == null ? -1 : status;
}
 

2、问题现场

 
程序执行到上面第4行的时候,程序hang住了,一直没有返回。这个代码之前从来没有出过问题,最近也没有上过线,今天唯一的不同就是文件数据量越来越大,今天比昨天大了几万行。
 
数据库情况:
 
看不到有sqlldr命令等待的情况
CPU正常
手工执行上面命令可以成功,但是打印的日志非常多,如下图:

4C75B994-FEFC-4061-887D-AF6AF3E2E1FD.png

 

3、原因分析

网上搜这个问题竟然很多,原因有下面三类:
 
3.1 Oracle版本低
 
Oracle版本低,建议升级到10.2.0.2或以上,这个方案忽略,因为我们的数据库版本是Oracle 11.2.0.4.0。
 
3.2 数据落库情况
 
本以为sqlldr命令执行失败了,但是文件数据已经全部落到t_biz表。这说明命令执行成功了,只是Oracle没有给应用返回结果。难道是Oracle数据库hang住了?但是上面的问题现场已经确认,Oracle并没有hang在sqlldr这个命令上。
 
3.3 最终答案
 
看了好多博客,最后发现竟然不是Oracle的原因。根本原因是使用java执行shell时,如果不读取标准输出,这个输出就会输出到缺省缓冲区,如果输出流太大,必将打满缓冲区,导致程序hang住。
 
从上面问题现场的手工执行中可以看到,因为加载的数据量很大大,结果输出也流非常大,这很容易超出缺省缓冲区大小。
 

4、解决方案

问题已经很明确了,解决方案也就有了,处理sqlldr的输出就可以解决。解决方法有下面三种。
 
4.1 增加参数
 
在sqlldr命令后面增加一个参数,silent=(ALL),最后命令如下:
 
sqlldr test/test123@biz control=/home/jinjunzhu/biz/T_BIZ.ctl log=/home/jinjunzhu/biz/T_BIZ.log bad=/home/jinjunzhu/biz/T_BIZ.bad silent=(ALL)
 
4.2 程序读取标准输出
 
程序中读取sqlldr命令返回的输出,修改后的代码如下:
 
 
private int execute(String cmd) throws Exception{
    Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
    process.waitFor(10, TimeUnit.SECONDS);
    Integer status;

    BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
    return (status = process.waitFor()) == null ? -1 : status;
}
 

4.3 文件接收标准输出

 
可以在sqlldr命令中增加文件参数来接收命令的标准输出,最后我采用了这种方式,命令如下:
 
sqlldr test/test123@biz control=/home/jinjunzhu/biz/T_BIZ.ctl log=/home/jinjunzhu/biz/T_BIZ.log bad=/home/jinjunzhu/biz/T_BIZ.bad 1>/home/jinjunzhu/biz/std.log 2>/home/jinjunzhu/biz/err.log
 

5、总结

 
这个问题刚出现的时候,一直以为是Oracle的问题,但是后来研究发现,这个锅真的不能让Oracle来背。关于sqlldr命令的详细参数介绍,已经比较成熟,大家可以自行网络查找。
分类:标签:
请先登录,查看1条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

Oracle实战优化!一次gc buffer busy acquire诊断
本案例来自某客户两节点rac的一次生产故障,现象是大面积的gc buffer busy acquire导致业务瘫痪。首先查看1节点AWR头部信息和load profile:1节点AWR 得到的关键信息点:对于LCPU 256的系统,AAS=13379.42/59.91
一次非常艰难的drop多个PDB的恢复
导言 关于Oracle的性能优化能保证Oracle性能的保障性,本篇给大家介绍的是Oracle的数据被误删后如何恢复的优化。 背景 在一次恢复中,遇到了一个非常棘手的case,客户环境中的一套rac cdb中原本存在10个PDB在同一个ASM磁盘组中,但误删
一次MySql加载量太大导致程序数据库无响应的排查过程
导读 今天,系统中的一个业务处理莫名地执行了6个小时都没有结束,正常处理也就是3分钟左右,对原因进行定位,发现是在Oracle客户端上同步执行一个命令没有响应。今天来分享一下这个问题,让更多的人避开这个坑。 正文1、业务场景 我们要把一个csv文件(文件名
Mysql高并发下重复插入问题排查和优化
前言最近测试给我提了一个bug,说我之前提供的一个批量复制商品的接口,产生了重复的商品数据。追查原因之后发现,这个事情没想象中简单,可以说一波多折。正文1、需求产品有个需求:用户选择一些品牌,点击确定按钮之后,系统需要基于一份默认品牌的商品数据,复制出一批新的商品。拿到这个需求时觉得太简单了
一次 MySQL 误操作导致的事故,「高可用」都顶不住了!
你好,我是悟空。上次我们项目不是把 MySQL 高可用部署好了么,MySQL 双主模式 + Keepalived,来保证高可用。简单来说就是有两个 MySQL 主节点,分别有两个 Keepalived 安装在宿主机上监控 MySQL 的状态,一旦发现有问题,就重启 MySQL,而客户端也会自动连
MySQL-Seconds_behind_master 的精度误差
前言Seconds_behind_master 是我们观察主从延迟的一个重要指标。但任何指标所能表示的精度都是有限的。例如用精度只能到秒的指标去衡量毫秒级的表现就会产生非常大的误差。如果再以此误差去分析问题,就会让思维走上弯路。例如用 Seconds_behind_master 去评估 1s 内的
一次 Keepalived 高可用的事故,让我重学了一遍它!
你好,我是悟空。前言上次我们遇到了一个 MySQL 故障的事故,这次我又遇到了另外一个奇葩的问题:Keepalived 高可用组件的虚拟 IP 持续漂移,导致 MySQL 主从不断切换,进而导致 MySQL 主从数据同步失败。虽然没能重现 Keepalived 的这个问题,但是我深入研究了下
MySQL 千万数据量深分页优化, 拒绝线上故障!
优化项目代码过程中发现一个千万级数据深分页问题,缘由是这样的库里有一张耗材 MCS_PROD 表,通过同步外部数据中台多维度数据,在系统内部组装为单一耗材产品,最终同步到 ES 搜索引擎MySQL 同步 ES 流程如下:1、通过定时任务的形式触发同步,比如间隔半天或一天的时间频率2、同步的形