
01
背景
目前线上的百万数据需要同步到 Elasticsearch,那么如何能够安全又快速的实现大数据量的同步呢?
02
方案验证
测试数据量:200w
方案一:单线程同步
| 线程数 | 耗时 |
| 1 | 1h |
单线程跑对于应用来说是非常安全的,但是在时间效率上,确实不太能容忍。
方案二:多线程
把同步数据分成多份,使用多线程同步

与上面单线程相比,这个速率可以说是一个质的飞跃。
| 线程数 | 耗时 |
| 4 | 5min |
| 5 | 4min |
| 8 | 2.5min |
| 16 | 1.6min |
很显然这是属于 IO 类型,瓶颈应该是在 MySQL 和 ES 的 IO 上,所以理论上线程数越多处理速度越快,这也跟上面的数据符合一致。
当然也不是线程数越多越好,CPU 核数就那么几个,线程数多了上下文切换的耗时也会增加,应用的其他业务也会被影响到。所以在全局的考虑下,选择最合适的 8 个线程数。
因为要等待所有的线程数完成任务,才算是完成整个同步的任务。这里使用了 CountDownLatch 作为计数器:
countDownLatch = new CountDownLatch(8);taskExecutor.submit(() -> {try {// 业务逻辑doSomething();} finally {countDownLatch.countDown();}});countDownLatch.await();log.info("task done!");
RestHighLevelClient抛出的一个异常:
Caused by: java.util.concurrent.TimeoutException: Connection lease request time out
RestHighLevelClient 的底层其实是 HttpClient,如果有使用过 HttpClient 的同学,看到这个异常应该也不陌生。
这里有三个比较重要的参数:
connectionRequestTimeout:从连接池获取连接的timeout connectionTimeout:客户端和服务器建立连接的timeout socketTimeout:客户端和服务器建立连接后,客户端从服务器读取数据的timeout
connectionRequestTimout方案三:多线程+多线程
要知道整个同步过程其实就是:
1. 读取 MySQL 数据
2. 写入 ES
打印了这两个步骤的耗时,发现步骤二的占用时间是70%-80%,那有办法能够提高步骤二的速度吗?

doSomething() {Semaphore semaphore = new Semaphore(2);try {semaphore.acquire();taskExecutor.submit(() -> {// ES写入write2Es()semaphore.release();});} catch (InterruptedException e) {e.printStackTrace();}}
| ES线程数 | 耗时 |
| 2 | 1.5min |
| 4 | 1.3min |
(8 个任务线程数)上面的数据可以看到,ES 写入线程数为 2 和 4 的时候区别不大,应该是 ES 线程数为 2 时整体耗时应该跟 MySQL 的读取耗时差不多。
03
总结与思考
这里还有一个问题,就是多个线程要保证完全高效利用:
END
「 往期文章 」

文章转载自卜几岛,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




