当前位置: 首页 > wzjs >正文

怎么学建网站天津seo排名费用

怎么学建网站,天津seo排名费用,武汉最好的网站建设公司,企业网络维护背景 一个简单的基于 JDBC 采集数据库表的功能,当采集 Postgre SQL 某表,其数据量达到 500万左右的时候,程序一启动就将 JVM 堆内存「6G」干满了。 问题是程序中使用了游标的只前进配置,且设置了 fetchSize 属性: q…

背景

一个简单的基于 JDBC 采集数据库表的功能,当采集 Postgre SQL 某表,其数据量达到 500万左右的时候,程序一启动就将 JVM 堆内存「6G」干满了。

问题是程序中使用了游标的只前进配置,且设置了 fetchSize 属性:

queryStat = connection.prepareStatement(executeSql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
queryStat.setFetchSize(batchSize);

为什么这个批量拉取数据的配置不生效呢?本文记录这个问题的排查过程及优化方法。

导出堆内存

程序一启动,jmap -heap 查看堆内存,老年代直接干到 99.98 % ,这时的程序直接 Stop all the world ,僵了。
在这里插入图片描述
JVM 启动最大堆内存已经调整到 6G 了,还是撑不住。感觉 SQL 查询的时候一下子将表的全部结果都加载到内存了,前面配置的批量拉取设置根本没生效。导出堆内存文件,进行分析。

nohup jmap -F -dump:live,format=b,file=/home/dump-result.hprof 23055 &

堆内存太大了,只能走后台进程的方式导出,接近一个小时才导出了 dump 文件,5.8G,确实跟 JVM 最大内存一样了。

堆内存分析

使用 mat 打开这个文件,直接内存溢出了。然后修改 mat 的 JVM 参数到8G后,得到分析结果不对,才几十M,明显不符合。

有很多 unreachable object,重新修改 mat 配置,勾选 “keep unreachable objects”,同时修改展示单位为 MB:
在这里插入图片描述

删除上次分析的结果文件后,重新导入 dump 文件分析,得到分析结果:
在这里插入图片描述
点开 Leak Suspects 查看内存泄漏的地方,发现最大的对象4.5G ,是一个列表,列表元素类型是 org.postgresql.core.Tuple ,盲猜这个类就是 JDBC 封装的查询结果
在这里插入图片描述
而这个类的对象总数跟表记录总数基本一致:
在这里插入图片描述
少掉的那些,应该是 GC 努力回收过的,但是剩余量还是很大。

这基本验证了前面的猜测,批量查询实际上成了全量查询了。为了再次确认,调整代码,造一张同结构、但是数据总量6万左右的表,然后在 while(result.next()) 遍历的循环里面加上 sleep 10 分钟后启动程序,导出堆内存。

这次程序老年代内存没有撑满,导出内存分析,Tuple 这个查询结果类对象的个数,跟数据库表总记录数「58000」多了21,基本可以确定这个批量size 没有生效。
在这里插入图片描述

问题分析

为什么批量加载不生效呢?是数据库的问题?驱动的问题?

尝试的方法:

  1. ❌升级数据库驱动为最新版本,无效。
  2. ❌在 while(result.next()) 遍历过程中,直接打印一个字符串后 continue,休眠5秒,手动调用 GC。不做任何操作,且手动触发 GC,JVM 内存还是满了。
  3. ❌怀疑数据库有问题,确定测试环境版本和出问题的现场环境一致。
  4. ❌目标数据库是基于 OpenGauss 自研的数据库,难道不支持游标的批量获取数据?

搜到一篇文章 《Postgres查询结果集的获取方法及其优缺点》 ,里面提到了 PostgreSQL 数据库的批量获取游标结果集生效的四个条件:

  1. 连到数据库服务的连接必须是基于V3协议的,V3协议是7.4及更新版本PG才能支持的,并且是他们的默认协议;
  2. Connection必须是非自动提交模式.后端会在事务的结束的时候关闭游标,所以,在自动提交模式里,还没从游标里获取任何东西的时候,后端就已经把游标关闭了。「冷知识:Connection 默认是自动提交的。」
  3. Statement必须以ResultSet.TYPE_FORWARD_ONLY的类型来创建,该结果集类型是默认的,所以可以直接使用stmt = conn.createStatement()来创建(或者stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY)).因此基于游标的结果集是只能向前获取,不能向后或者跳跃获取的。「PS:PostgreSQL默认就是这个类型,所以这个不是关键。
  4. 查询sql语句必须是一个单一的语句,不能是由分好分隔的多个语句。这个在本应用中不存在。

之前没仔细注意第2点,找了三天实在没办法了。又打开这篇文章,仔细看了一下,发现了这个点。

检查代码确实没有设置自动提交参数,加上它,还原 JVM 参数为2G,然后测试500万条数据顺利采集完成,老年代堆只占2%。

复测验证:再去掉这行代码,回到原点,还是一启动就堆满了,确定这行代码就是关键。排查了三天的问题,就这么简单的一行代码就解决了吗?赶在周末之前干掉问题,真是太幸运了。

优化结果

继续优化,循环遍历数据总量到达一个值后,手动触发 GC并休眠1秒:

// 手动触发GC,且休眠等待
if (count == maxFetchSize) {logger.info("Reach max batch size {}, sleep 1s to gc", maxFetchSize);count = 0;// 手动触发 GCRuntime.getRuntime().gc();// 等待GC完成Thread.sleep(1000);
}

将优化后的结果,加上 sleep 10分钟后,导出堆栈分析,发现这次 Tuple 类的个数就是 setFetchSize=2000,还多了21个。
在这里插入图片描述
跟上面那个一样,数据总量+21,说明额外还有 21 个对象,为查询操作提供了不为人知的功能。总归来说,只有加上这句话 connection.setAutoCommit(false); 才生效,才是真正的批量查询数据。

启示录

一开始就检索到了 《Postgres查询结果集的获取方法及其优缺点》 这篇文章,里面提到了 PostgreSQL 数据库的批量获取游标结果集生效的方法,但是忽略了重要的那个条件。

循环处理数据时,达到一个值后,手动触发 GC 还是有效的,可以让整个采集过程中老年代内存占用情况稳定在 2% 左右;如果去掉 GC 的话,内存会缓慢升至 10% 左右,但是已经不会再僵死了。

这个 JDBC 的批量查询不生效问题,前年冬天采集 Doris 的时候也发现了,只是后来没有细究。这次又碰到了,不知掉 Doris 能不能用这个配置解决呢?或者说 Doris 数据库支不支持批量查询呢?

http://www.dtcms.com/wzjs/281808.html

相关文章:

  • 丹灶网站建设案例百度推广非企代理
  • 如何做一个网站赚钱杭州优化公司哪家好
  • 中国建设电工立网站世界杯最新排名
  • 丰台深圳网站建设公司发外链软件
  • wordpress ios客户端郑州厉害的seo顾问公司
  • 惠州网络推广费用乐山网站seo
  • 网络运营商有哪些优化器
  • 建设网站的规划书营销方案网站
  • 网站开发工程师ppt在线外链推广
  • 做户外商城网站品牌推广方案
  • wordpress 显示友情链接网站seo设计
  • 今日头条十大新闻上海正规优化公司哪家好
  • 做民宿上几家网站好搜索推广竞价托管哪家好
  • 工作细胞樱花动漫志鸿优化网
  • 建设官方网站的主要作用百度指数如何提升
  • 网站开发环境搭建app推广一手单平台
  • 做外贸网站代理商深圳网站seo哪家快
  • 医药做网站免费网站模板网
  • 个人网站模板怎样申请网站
  • 网站开发项目中的rd百度销售系统
  • 长沙网站建设费用疫情防控最新信息
  • 中企动力网站建设营销推广策划方案范文
  • 网站建设 请示广告推广方式有哪几种
  • 湖州网站建设公司哪家好北京seo招聘网
  • 网站推广要多少钱在线智能识图
  • 三分钟做网站百度小说app下载
  • 重庆奉节网站建设公司成都公司建站模板
  • 做的比较简约的网站网络广告投放公司
  • 淮阳城乡建设局网站seo搜索优化软件
  • wap网站开发联系电话让顾客进店的100条方法