不为失败找理由,要为成功找方法。

logstash input-jdbc 分页性能优化问题

Logstash | 作者 Boole li | 发布于2018年10月30日 | 阅读数:6160

场景:

    DB 数据全量同步 Elasticsearch 时,数据量过大时需要使用分页查询。在conf中配置jdbc_paging_enabled、jdbc_page_size这两个参数,input-jdbc插件会自动对SQL进行分页查询,分批同步数据。

问题:

    logstash导入mysql上亿级别数据的效率问题

    项目的ES升级至5.6后,全量数据同步由java定时任务改为logstash。线上数据量比较大,优化索引后单个分页查询执行依旧很慢,需要几十秒。

    原因在于input-jdbc插件的分页是使用临时表分页,每条分页SQL都是将全集查询出来当作临时表,再在临时表上分页查询。这样导致每次分页查询都要对主表进行一次全表扫描。

    举个例子:

    商品表(goods)有1000万条数据,每次同步1万条。input-jdbc插件执行的分页查询sql类似下面这样的。

    select * from (select * from goods left join ...) as T limit 0,10000
  • 解决方案


    通过修改input-jdbc插件源码,支持子查询分页。修改后执行的查询sql类似下面这样的,这样每次分页只需要扫描主表中需要的数量。

    select * from (select * from goods limit 0,10000 ) as T left join ...
  • 效果


    项目中单个分页查询都在2S内完成,并且优化后的插件由运维推广到了所有项目。

优化内容:
  • 源码


      1、logstash-input-jdbc\lib\logstash\plugin_mixins\jdbc.rb中添加subquery_paging_enabled、sum_statement变量;(具体参见我修改的源码 Line100)

      2、perform_query方法中优先判断是否进行子查询优化。(具体参见我修改的源码 Line255)

      jdbc.rb源码
  • 配置文件


      1、添加两个配置项:

      subquery_paging_enabled => "true"

      sum_statement => "select count(*) as sum from goods"

      2、优化statement SQL

      主表改为分页子查询,添加:data_offset、:jdbc_page_size分页参数。例如:

      statement => " select * from (select * from goods limit :data_offset , :jdbc_page_size ) as T left join ... "
  • 开发参考


      https://github.com/logstash-pl ... -jdbc

      https://github.com/jeremyevans/sequel
  • 插件构建和安装


      1、项目安装依赖(先去github下载项目源码)

      bundle install

      2、构建插件gem (在项目主目录下产生logstash-input-jdbc-4.3.5.gem文件)

      gem build logstash-input-jdbc.gemspec

      3、logstash卸载logstash-input-jdbc插件

      /bin/logstash-plugin uninstall logstash-input-jdbc

      4、logstash安装本地插件 (先将构建成功的gem文件拷贝至logstash主目录的trade_gem文件夹中)

      /bin/logstash-plugin install --no-verify --local ../logstash-input-jdbc-4.3.5.gem
 
PS:这是在公司遇到的一个实际问题,选择的方案是修改源码,大家可以看一下,可以讨论下还可以有其他优化方法或者解决办法没?
 
已邀请:

rochy - rochy_he

赞同来自:

在 Mysql 表里面需要有两个字段、第一个是数据修改时间、第二个是数据同步状态;
每一次同步结束后,批量修改同步状态;
查询的时候,限制修改时间和同步状态即可;
这样每一次只需要查询第一页即可

要回复问题请先登录注册