功能回顾
当时编写的一个datax-plugin插件,进行定时去采集所有数据库(N个库)下面每一张表(n多表)里面到底有多少数据量(记录数),表更新记录数;有问题关闭不使用了,前几天被小伙伴开起来了,数据量上来了就出现各种问题。内存占用过高、数据库连接不上、依赖版本冲突…
告警消息
这两天遇到一个问题,内存高烧不退
[容器宕机][http://xxx] 无法连接,状态码[0]
[容器宕机][http://xxx] 无法连接,状态码[0]
[容器宕机][http://xxx] 无法连接,状态码[0]
[容器宕机][http://xxx] 无法连接,状态码[0]
[内存占用][IP/DOCKER-NAME] 内存占用过高,当前为[61G]
原因排查
- 发现任务调度被人开启了,自动调度的是每10分钟执行一次
- 日志打印内容里大量数据库无法连接
- 依赖包版本不一致,执行出现找不到类
- 查询获取值时候出现类型错误
- 大批量数据逻辑处理
… … 等问题
解决调整
- 调度自动时间改成每天一次,改成每天凌晨某时间采集一次;
- 依赖包版本调整一致
<commons-lang3-version>3.9</commons-lang3-version>
; - 大批量数据调整为分批处理
List<List<T>> gDataList = Lists.partition(dataList, 500);
- 大批量创建Dao查询优化
Map<Integer, MybatisSqlDao> cacheDao = new HashMap<>();
//切割数据集合
List<List<T>> gDataList = Lists.partition(dataList, 500);
for (List<T> dsList: gDataList) {
for (T item : dsList) {
MybatisSqlDao localDcSqlDao = cacheDao.get(item.getDid());
if (localDcSqlDao == null) {
localDcSqlDao = MybatisSqlDaoFactory.cDao(url, username, password, driverClass);
cacheDao.put(item.getDid(), localDcSqlDao);
}
//TODO 其他业务查询
}
}
- 获取空值转换异常
Object num= tableNum.get("NUM");
Long tableNum = Long.valueOf(String.valueOf(num));
调整
Object num = tableNum.get("NUM");
num= ObjectUtil.isNull(num) ? 0L : num; //补充判断
Long tableNum = Long.valueOf(String.valueOf(num));
- 数据库连接是否正常方式调整
原先写法(没有任何效果,一致卡在这里):
Connection conn = null;
try {
Class.forName(driverClass);
DriverManager.setLoginTimeout(15); //15秒超时
conn = DriverManager.getConnection(getJdbcUrl(url, driverClass), userName, passWord);
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
改造调整(部分参考代码,提供思路)
/**
* 判断jdbc连接是否可用
*
* @param url
* @param userName
* @param passWord
* @param driverClass
* @param timeOut 超时时间 单位秒
* @return
*/
public static boolean isCanConn(String url, String userName, String passWord, String driverClass, int timeOut) {
ExecutorService executor = Executors.newSingleThreadExecutor();
String finalUrl = url;
Future<Connection> future = executor.submit(() -> DriverManager.getConnection(finalUrl, userName, passWord));
Connection conn = null;
//TRUE 连接成功,FALSE 连接失败
boolean status = false;
try {
Class.forName(driverClass);
DriverManager.setLoginTimeout(timeOut); //15秒超时
if (!getDriverClassName(url).equalsIgnoreCase(driverClass)) {
throw new RuntimeException("数据库类型与JDBC链接串类型不匹配!");
}
conn = future.get(timeOut, TimeUnit.SECONDS);
status = true;
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
executor.shutdownNow();
JdbcUtils.closeConnection(conn);
}
return status;
}