Elasticsearch数据同步优化

背景

为了满足项目需求,需要将大量数据的数据写入到ES进行检索,预估数据量是40亿左右,目前需要同步进去的是2亿左右。

ES集群配置

  • 三台128G的国产服务器 国产linux系统 CPU主频低的拉跨
  • JDK8的版本
  • 机械硬盘

遇到的问题

后端使用Java调用es的bulk api进行数据同步,数据同步特别慢,在测试环境做同步的时候速度是很快的,但是在正式环境下速度出奇的慢。

直接上优化方案

  • 升级JDK版本 将JDK的版本升级到JDK17(中途先升级到JDK11的),升级之后速度提升明显 JDK8的垃圾回收器到底是比不过JDK17
  • ES索引的副本数据在数据同步阶段设置为0 多个副本就意味着要多写几份数据
  • ES索引的分片数量设置为3 和集群数量一致
  • 调整Java调用ES bulk api的代码 使用异步批量调用的方式,后面会详细介绍

    经过一阵鼓捣 数据同步速度极大提升,

Java调用ES bulk api

首先es是有一个bulk的批量接口的,一般来说做批量数据同步的时候是使用的这个api,实际上还有一种更加灵活的api,在ES7里面是BulkProcessor这个类,在ES8里面是BulkIngester类,两者功能基本一致。

先说一下这两个api的工作原理

bulk api 接收到批量数据之后 会立即将数据提交给es集群,es集群如果在使用默认写入配置的情况下,会很快将数据进行落盘的,数据落盘的这个过程是比较耗时的。

BulkProcessor BulkIngester 这两个类中是可以动态配置数据提交给es的机制,总体来说就是 数据会在内存中暂存起来,等数据的指标达到我们配置的值的时候 api就会异步的将数据提交给es集群,从而减少es集群数据落盘的次数

代码 ES7版本

    @Bean
public BulkProcessor bulkProcessor(RestHighLevelClient restHighLevelClient) { BulkProcessor.Listener listener = new BulkProcessor.Listener() {
@Override
public void beforeBulk(long executionId, BulkRequest request) {
LOGGER.info("【beforeBulk】批次[{}] 携带 {} 请求数量", executionId, request.numberOfActions());
} @Override
public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
if (!response.hasFailures()) {
LOGGER.info("【afterBulk-成功】批量 [{}] 完成在 {} ms", executionId, response.getTook().getMillis());
} else {
BulkItemResponse[] items = response.getItems();
for (BulkItemResponse item : items) {
if (item.isFailed()) {
LOGGER.info("afterBulk-失败】批量 [{}] 出现异常的原因 : {}", executionId, item.getFailureMessage());
break;
}
}
}
} @Override
public void afterBulk(long l, BulkRequest bulkRequest, Throwable throwable) {
throwable.printStackTrace();
}
}; BulkProcessor.Builder builder = BulkProcessor.builder(((bulkRequest, bulkResponseActionListener) -> {
restHighLevelClient.bulkAsync(bulkRequest, RequestOptions.DEFAULT, bulkResponseActionListener);
}), listener);
//到达指定条数时刷新 -1则禁用该配置
builder.setBulkActions(bulkActions);
//内存到达指定大小时刷新
builder.setBulkSize(new ByteSizeValue(bulkSize, ByteSizeUnit.MB));
//设置的刷新间隔 单位是s -1则禁用该配置
builder.setFlushInterval(TimeValue.timeValueSeconds(flushInterval));
//设置允许执行的并发请求数
builder.setConcurrentRequests(concurrentRequests);
//设置重试策略
builder.setBackoffPolicy(BackoffPolicy.constantBackoff(TimeValue.timeValueSeconds(1), maxNumberOfRetries));
return builder.build();
}

这里将该类配置为spring bean,在使用的时候直接注入使用即可,剩下的交给BulkProcessor即可

    @Resource
private BulkProcessor bulkProcessor; IndexRequest request = new IndexRequest();
request.id(id);
request.index(tableToEs.getIndexName());
request.source(JSON.toJSONString(esTopicCollectModel, serializeConfig), XContentType.JSON);
bulkProcessor.add(request);

代码 ES8版本

    @Bean
public BulkIngester<String> bulkIngester() throws Exception { BulkListener<String> listener = new BulkListener<String>() { /**
*
* @param executionId 此请求的id
* @param request 将发送的批量请求
* @param contexts 数据集
*/
@Override
public void beforeBulk(long executionId, BulkRequest request, List<String> contexts) {
LOGGER.info("【beforeBulk】批次[{}】 携带 【{}】 请求数量", executionId, contexts.size());
} /**
* 批量请求之后调用
* @param executionId 此请求的id
* @param request 将发送的批量请求
* @param contexts 数据集
* @param response 返回值
*/
@Override
public void afterBulk(long executionId, BulkRequest request, List<String> contexts, BulkResponse response) {
LOGGER.info("【afterBulk】批次[{}】 提交数据量【{}】 提交结果【{}】", executionId,contexts.size(),response.errors()?"失败":"成功");
} /**
* 当批量请求无法发送到Elasticsearch时调用
* @param executionId 此请求的id
* @param request 将发送的批量请求
* @param contexts 数据集
* @param failure 异常信息
*/
@Override
public void afterBulk(long executionId, BulkRequest request, List<String> contexts, Throwable failure) {
LOGGER.error("Bulk request " + executionId + " failed", failure);
}
}; ElasticsearchClient elasticsearchClient = elasticsearchClient(); BulkIngester<String> ingester = BulkIngester.of(b -> b
.client(elasticsearchClient)
.maxOperations(-1)
.maxSize(bulkSize)
.maxConcurrentRequests(concurrentRequests)
.flushInterval(flushInterval, TimeUnit.SECONDS)
.listener(listener)
); return ingester;
}

使用方式

    @Resource
private BulkIngester<String> bulkIngester; IndexOperation<EsTopicCollectModel> indexOperation = new IndexOperation.Builder<EsTopicCollectModel>()
// 索引
.index(tableToEs.getIndexName())
// 文档id
.id(tableToEs.getTableName() + "_" + data.getOrDefault(StrUtil.toCamelCase(tableToEs.getPkColumn()), ""))
// 文档内容
.document(esTopicCollectModel)
.build(); BulkOperation bulkOperation = new BulkOperation.Builder()
.index(indexOperation)
.build(); bulkIngester.add(bulkOperation);
```java

Elasticsearch数据同步优化的更多相关文章

  1. Oracle和Elasticsearch数据同步

    Python编写Oracle和Elasticsearch数据同步脚本 标签: elasticsearchoraclecx_Oraclepython数据同步    Python知识库 一.版本 Pyth ...

  2. 基于 MySQL Binlog 的 Elasticsearch 数据同步实践 原

    一.背景 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品.订单等数据的多维度检索. 使用 Elasticsearch 存储业务数据可以 ...

  3. Neo4j与ElasticSearch数据同步

    Neo4j与ElasticSearch数据同步 针对节点删除,加了一些逻辑,代码地址 背景 需要强大的检索功能,所有需要被查询的数据都在neo4j. 方案 在Server逻辑中直接编写.后端有一个St ...

  4. 基于MySQL Binlog的Elasticsearch数据同步实践

    一.为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品.订单等数据的多维度检索. 使用 Elasticsearch 存储业务数 ...

  5. kafka2x-Elasticsearch 数据同步工具demo

    Bboss is a good elasticsearch Java rest client. It operates and accesses elasticsearch in a way simi ...

  6. MQ异步同步搜索引擎ElasticSearch数据踩坑

    业务背景 在大型网站中,为了减少DB压力.让数据更精准.速度更快,将读拆分出来采用搜索引擎来为DB分担读的压力,ElasticSearch就是目前市面上比较流行的搜索引擎,他的检索速度奇快.支持各种复 ...

  7. ElasticSearch 集群 & 数据备份 & 优化

    ElasticSearch 集群相关概念 ES 集群颜色状态 ①. - 红色:数据都不完整 ②. - 黄色:数据完整,但是副本有问题 ③. - 绿色:数据和副本全都没有问题 ES 集群节点类型 ①. ...

  8. 几篇关于MySQL数据同步到Elasticsearch的文章---第三篇:logstash_output_kafka:Mysql同步Kafka深入详解

    文章转载自: https://mp.weixin.qq.com/s?__biz=MzI2NDY1MTA3OQ==&mid=2247484411&idx=1&sn=1f5a371 ...

  9. elasticsearch与mongodb分布式集群环境下数据同步

    1.ElasticSearch是什么 ElasticSearch 是一个基于Lucene构建的开源.分布式,RESTful搜索引擎.它的服务是为具有数据库和Web前端的应用程序提供附加的组件(即可搜索 ...

  10. Elasticsearch和mysql数据同步(logstash)

    1.版本介绍 Elasticsearch: https://www.elastic.co/products/elasticsearch 版本:2.4.0   Logstash: https://www ...

随机推荐

  1. 1. zookeeper简介与应用场景

    1.1 zookeeper介绍   zookeeper是一个高可用的分布式管理与协调框架,基于ZAB算法(原子消息广播协议)的实现. 能够很好保证分布式环境中数据的一致性.正是基于这样的特性,使得zo ...

  2. CTF中常见编码

    ASCII编码 ASCII HEX DEC flag{hello_ctfer} 66 6c 61 67 7b 68 65 6c 6c 6f 5f 63 74 66 65 72 7d 102 108 9 ...

  3. mysql中innodb创建表的一些限制

    1. 背景 在新创建mysql数据表的时候.不太确定表能创建多少个字段,多少个索引.索引多少有限制么?mysql的数据是怎么存储的存在在哪里. 2.基本个数限制 在MySQL5.6.9以后的版本,一个 ...

  4. Go和TinyGo

    Go和TinyGo是两种不同的Go语言编译器,它们之间有以下几点区别: 目标平台: Go:Go语言编译器主要面向通用计算机平台,如Windows.Linux.macOS等. TinyGo:TinyGo ...

  5. Sagas论文原文读后总结

    一.引子 分布式事务组件seata最近社区很活跃,刚好公司有对接seata的计划.刚好借此机会,彻底了解下seata的价值.其中有一个比较特殊的模式叫SAGA模式,听起来就很懵逼,按照官网的介绍起源于 ...

  6. zabbix“专家坐诊”第178期问答汇总

    大家好,我是乐乐.早在三年前,我们就在社区举办了zabbix公益问答活动,并且定在每周三邀请资深的zabbix技术工程师,为社群的小伙伴进行免费的答疑.到现在已经178期了.后续我将会把每期的答疑汇总 ...

  7. Alt+Space 快速打开切换程序 - Everything - AutoHotKey

    Alt+Space 快速打开切换程序 - Everything - AutoHotKey 需求 电脑切换任务 需要用鼠标找,效率比较低,用快捷键Alt+Space 打开列表,输入指定关键字回车,切换或 ...

  8. vscode 创建 git tag,并推送到远程

    Step. 1: 创建tag 左侧 源代码管理 右上角 ... 标记 -> 创建标记 输入tag名称 回车 输入tag描述 Step. 2: 查看tag 使用命令 git tag 查看当前所有的 ...

  9. Linux 上 libcurl库 curl_easy_perform Crash(signal 11 - SIGSEGV)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  10. webpack 项目接入Vite的通用方案介绍(下)

    愿景 希望通过此系列文章,能给读者提供一个存/增量项目接入Vite的点子,起抛砖引玉的作用,减少这方面能力的建设成本 在阐述过程中同时也会逐渐完善webpack-vite-serve这个工具 读者可直 ...