简述
最近开始又大数据统计分析,需要将亿级业务数据进行聚合查询统计,传统的关系型库(mysql)已经满足不了业务需求,经过精细的技术选型成本计算后,自建了一个单机(4c16g)的clickhouse。
效果
实现了一个占用内存不到400M,完美将亿级数据从mysql导到了clickhouse(流处理)
问题
建好DB后,接下来的数据导入是个难题。
开始准备使用阿里的datax导入,然后发现clickhouse write模块已经两年没更新了。
为了快速启动只能先试试用win服务器上的navicat直接导出成csv,然后用命令行导入数据。
两天后…我获得了一个10多个G的CSV,将他上传到clickhouse服务器,敲了下面指令
clickhouse-client --port=19101 --password ****** --input_format_allow_errors_ratio=0.0001 --date_time_input_format=best_effort --query="insert into db.table format CSVWithNames"< CSV.csv
经过几分钟漫长等待后,导入成功~
正当欣喜之时,对比了一下两边数据,发现clickhouse少了几W数据
一下就难受了起来。
此时我知道最佳方式就只能来炒一个datax的模式来进行数据的导入了。
又不是不能用
在接触数据导入这块之前,用法从来就是老spring项目里的getJdbcTemplate().query()
然后进行一些数据处理,或是输出,或是写入到其他表(库)
再加上现在用mybatis用的多
所以第一时间就写了个分片select(mysql)Map再 insert (clickhouse)
所谓分片也就是 count出来后再进行limit 0,500000
然后就成功的触发数据库慢查询告警+JVM outofmemory~
再然后就limit 0,10000,这次没告警但是显然不是很好的解决方案。
解决方案
在翻阅大量文献资料google后,发现jdbc里有一个从来没用过的方法
jdbcTemplate.query()
query(PreparedStatementCreator psc, RowCallbackHandler rch)
它可以通过自定义statement,来流处理查询。
然后就是长达数小时的代码改造(下面是流处理时序图)
代码
因为涉及到跨实体库,所以首先得需要个proxy来兼容不同库的io操作
于是有了DSMethodProxy这个interface,下面分别对应两个数据源的实现
在这里面写了流处理实现streamHandleBySql(String sql, RowCallbackHandler rch)
入参是查询的sql和流处理的RowCallbackHandler匿名函数,具体代码如下
default void streamHandleBySql(