Elasticsearch之利用bulk提高写入性能(含源码分析)

article/2025/10/3 22:50:02

什么是bulk操作

bulk是批量的意思,也就是把原来单个的操作打包好,通过批量的api提交到ES集群。下面是个示例:

单个操作:

PUT my-index-000001/_doc/1
{"@timestamp": "2099-11-15T13:12:00","message": "GET /search HTTP/1.1 200 1070000","user": {"id": "kimchy"}
}

bulk操作:

POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

另外,ES还提供了相关的API支持bulk操作,

BulkRequest bulkRequest = new BulkRequest();entityWrapperList.forEach(item -> {IndexRequest request  = new IndexRequest(item.getIndexName());request.id(item.getId());if (item.getVersion() > 0) {request.version(item.getVersion());request.versionType(VersionType.EXTERNAL_GTE);}request.source(JSON.toJSONString(item.getData()), XContentType.JSON);bulkRequest.add(request);});try {BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);

在这里插入图片描述
在这里插入图片描述

可以看到,我们可以把多个不同的命令打包好通过bulk提交。不过我个人的经验实际场景中多是相同的命令(比如批量index)。

bulk操作的顺序问题

一提到批量操作,有经验的人马上就会提出一个问题:一堆命令提交到ES,那么ES执行的顺序和我们提交的顺序是一致的吗?毕竟有些业务场景会对执行命令的顺序有要求。

答案是不一定。

在这里插入图片描述

根源在于ES的分布式架构。如上图所示,客户端的命令首先是请求到coordinating node(协调节点),然后协调节点根据命令提供的的路由字段(没有的话默认使用文档id),经过路由算法,找到对应的主shard(分片)。所以真正执行的节点就是shard所在的节点,而每条命令发送到节点上到底哪个先执行是没有保障的,取决于很多因素。比如发送到节点的时间,节点本身的空闲资源情况等。

不过从上面这段解释,我们也可以得出另外一个结论,就是对于同一个文档的操作是有序的。了解这点在一些业务场景下很重要。

虽然处理的顺序不能保证,但是ES会保证响应结果和提交的顺序是一致的。

{"took": 30,"errors": false,"items": [{"index": {"_index": "test","_id": "1","_version": 1,"result": "created","_shards": {"total": 2,"successful": 1,"failed": 0},"status": 201,"_seq_no" : 0,"_primary_term": 1}},{"delete": {"_index": "test","_id": "2","_version": 1,"result": "not_found","_shards": {"total": 2,"successful": 1,"failed": 0},"status": 404,"_seq_no" : 1,"_primary_term" : 2}},{"create": {"_index": "test","_id": "3","_version": 1,"result": "created","_shards": {"total": 2,"successful": 1,"failed": 0},"status": 201,"_seq_no" : 2,"_primary_term" : 3}},{"update": {"_index": "test","_id": "1","_version": 2,"result": "updated","_shards": {"total": 2,"successful": 1,"failed": 0},"status": 200,"_seq_no" : 3,"_primary_term" : 4}}]
}

这个返回的结果顺序,跟提交的顺序是一致的,标注每条命令执行的结果。

bulk操作的性能如何

ES官方是建议在业务场景允许的情况下,尽量使用bulk操作来提高index的性能,官方文档是这么说的。

Bulk requests will yield much better performance than single-document index requests. In order to know the optimal size of a bulk request, you should run a benchmark on a single node with a single shard. First try to index 100 documents at once, then 200, then 400, etc. doubling the number of documents in a bulk request in every benchmark run. When the indexing speed starts to plateau then you know you reached the optimal size of a bulk request for your data. In case of tie, it is better to err in the direction of too few rather than too many documents. Beware that too large bulk requests might put the cluster under memory pressure when many of them are sent concurrently, so it is advisable to avoid going beyond a couple tens of megabytes per request even if larger requests seem to perform better.

这句话的大概意思是,bulk的index操作性能是高于单文档的index操作的。至于bulk每个批次多少个文档是最优的,需要根据自己的实际环境进行压力测试,以实际的结果为准。

bulk性能高是自然的,因为它大大降低了业务和ES集群之间的IO。

bulk批量更新重复id的性能问题

之前在ES中文社区看到过一篇关于bulk更新重复id的文档情况下,性能低的问题。后来有时间专门去研究了一下源码,觉得这个问题很好这里分享下。

在ES 5.x的版本中,如果bulk update文档里面含有大量重复文档(文档id一样)的情况,实际项目环境中发现bulk性能非常低。

要理解其中的缘由,首先必须了解ES的update操作,是先get出来最新的文档,然后在内存里更新,最后再写回去。get操作的源码长这样:

在这里插入图片描述

从源码可以看出,在realtime=true(默认情况)的情况下,会先执行一个

refresh("realtime_get");

然后从searcher里获取文档(getFromSearcher)。

这个refresh的方法,会检查GET的文档是否都是可以被搜索到。如果已经写入了但无法搜索到,也就是刚刚写入到buffer里还未refresh这种情况,会强制执行一次refresh操作,保证getFromSearcher可以搜索到文档。

所以在大量重复id的情况下,会大量触发refresh操作,(不重复的情况就不会)产生很多小的segments,然后又触发很多segment merge操作。

这个问题在6.3的版本之后已经接近了,pull request的链接如下:

https://github.com/elastic/elasticsearch/pull/29264

其实接近方案就是在实时的情况下,从translog拿文档,而不是refresh后通过搜索拿。我本地的代码是7.10版本,就用这个版本的代码来看下。

在这里插入图片描述

在这里插入图片描述

可以看到,当readFromTranslog为true时,get操作是从translog读取数据,而初始化的时候这个值和realtime取的是同一个值。也就是实时情况下(realtime=true),会从translog读取文档。这样就解决了前面抛出来的问题。


参考:

  • https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-bulk.html
  • https://github.com/elastic/elasticsearch/pull/20102/commits/2738e00e15470f566aa33adcbaa39c4dba1d1828

http://chatgpt.dhexx.cn/article/cPXhNNoM.shtml

相关文章

.NET5必备工具——EF大数据批量处理----Bulk系列

之前做项目的时候,如果在大批量操作数据时,性能不好.因为在框架中使用了EntityFramework,于是就搜索到某著名插件,Z系列。 1.安装 然后在类里面添加引用之后,使用DbContext就可以直接点出来。 2.博客园有人做过对比试验 我们直接拿数据说话吧. EF传统…

初识ElasticSearch(5) -批量操作之bulk | 条件查询 | 其它查询

1. bulk:1.1. bulk语法:1.2. bulk行为-增删改: 2. bulk-index批量插入:3. bulk-update批量修改:4. bulk-delete批量删除:5. _update_by_query条件更新:6. _delete_by_query条件删除:…

mysql bulkupdate_Bulk Upsert for MySQL PostgreSQL

什么是 Upsert "UPSERT" is a DBMS feature that allows a DML statements author to atomically either insert a row, or on the basis of the row already existing, UPDATE that existing row instead, while safely giving little to no further thought to con…

JPA 2.1: Bulk Update and Delete

为什么80%的码农都做不了架构师?>>> JPA 2.1: Bulk Update and Delete In the JPA 2.0 and early version, if you want to execute a bulk updating query, you have to use update or delete clause in JPQL directly. JPA 2.1 introduce new Criteri…

ElasticSearch提供的bulk update性能对比

目的:为了对比update的数据中重复数据对性能的影响。

Java面试智力题逻辑题汇总2021

rand5()能够生成0-4的随机数 rand7()能够生成0-6的随机数 已知rand7()生成rand5() 已知rand5()生成rand7()

面试智力题精选:扑克牌问题

袁方同学在玩扑克牌。这幅扑克牌比较特别,没有花色,只有点数。每张牌的点数是1,2,3,...,20。一共20张牌。袁方把牌洗了很多遍以后,把所有牌正面朝下垒成一堆放在自己手上。他翻第一张牌,发现是1…

大厂面试常见智力题

1. 64匹马,8个赛道,找出前4名最少比赛多少场? 这是一道经常考的智力题 64匹马,我们要想知道哪匹🐎跑的最快,前提条件是每一匹🐎都要去比赛一场。所以刚开始的赛马规则是每匹马都要进行一次比赛。 步骤1: 把 64匹🐎…

盘点面试中常见的智力题

由于某些不可抗力,几篇文章做了删除,重新上架,希望于你有益。 面试为何会出现智力题? 可能是为了考察应聘者的综合分析能力、逻辑思维能力、反应能力和解决问题能力吧~ 也可能是...... “我去!这面试者能力可以啊&…

面试中常见的智力题

文章目录 一、提灯过桥问题?二、有两个鸡蛋,如何最快的试出100层楼中刚好那一层扔下鸡蛋会碎?三、在地球什么地方能够,往南走1公里,然后往东走1公里,再往北走1公里能回到原点?四、一块N x M的巧…

面试中常见智力题汇总

面试中常见智力题汇总 1. 二进制问题1.1 毒药问题1.2 分金块问题 2. 先手必胜问题2.1 抢 30的必胜策略2.2 100本书,每次能够拿1~5本,怎么拿能保证最后一次是你拿?2.3 轮流拿石子 3. 推理题3.1 掰巧克力问题3.2 辩论赛问题3.3 在24小时里面时针…

2020秋招华为笔试题-买钉子

1.题目描述 2.代码实现 主要思路&#xff1a;类似零钱兑换 #include <iostream> #include <vector> using namespace std;class Solution { public:int buyNails(vector<int>& nails, int count) {vector<int> dp(count1, -1);dp[0] 0;for(int …

华为2022硬件逻辑笔试题

单选题&#xff08;每题两分&#xff09; 1.以下关于过程赋值的描述&#xff0c;不正确的是&#xff08;&#xff09; A在非阻塞性过程赋值中&#xff0c;使用赋值符号“< ” B赋值操作符是“”的过程赋值是阻塞性过程赋值 C在非阻塞性过程赋值中&#xff0c;对目标的赋…

AJAX原理快速入门

AJAX的原理 Ajax 的原理简单来说通过 XmlHttpRequest 对象来向服务器发异步请求&#xff0c;从服务器获得数据&#xff0c;然后用 javascript 来操作 DOM 而更新页面的局部显示。 Ajax 的优点&#xff1a; 1.最大的一点是页面无刷新&#xff0c;给用户的体验非常好。 2.使用异…

Ajax详解~及原理刨析

目录 什么是Ajax 同步和异步 Ajax如何实现异步和局部刷新 Ajax工作原理 Ajax工作流程 1、创建XMLHttpRequest对象 2、创建HTTP请求 3、向服务器发送数据 4、设置回调函数 &#xff0c;在回调函数中针对不同的响应状态进行处理 完整实例 Jquery中的ajax 什么是Ajax…

和vue相似的ajax原理及vue中运用ajax

和vue相似的ajax原理及vue中运用ajax。 一&#xff0c;默认的app.vue/文件 App.vue     App.vue是项目的主组件&#xff0c;页面入口文件 &#xff0c;所有页面都在App.vue下进行切换&#xff0c;app.vue负责构建定义及页面组件归集。                二&…

ajax工作原理

ajax工作原理 在写这篇文章之前&#xff0c;曾经写过一篇关于AJAX技术的随笔&#xff0c;不过涉及到的方面很窄&#xff0c;对AJAX技术的背景、原理、优缺点等各个方面都很少涉及null。这次写这篇文章的背景是因为公司需要对内部程序员做一个培训。项目经理找到了我&#xff0…

Ajax原理学习

一、AJAX 简介 AJAX即“Asynchronous Javascript And XML”&#xff08;异步JavaScript和XML&#xff09;&#xff0c;是指一种创建交互式网页应用的网页开发技术。 AJAX 是一种用于创建快速动态网页的技术。 通过在后台与服务器进行少量数据交换&#xff0c;AJAX 可以使网页…

Ajax工作原理和实现步骤

目录 一 Ajax技术与原理 1.1 Ajax简介 1.2 Ajax所包含的技术 1.3 Ajax的工作原理 1.4 XMLHttpRequest 对象的三个常用的属性 1. onreadystatechange 属性 2. readyState 属性 3. responseText 属性 1.5 xmlhttprequst的方法 1. open() 方法 2. send() 方法 二 Ajax…

Ajax原理,技术封装与完整示例代码

在做项目和学习的时候&#xff0c;经常用到Ajax的相关技术&#xff0c;但是这方面的技术总是运用的不是十分好&#xff0c;就寻找相关博客来学习加深Ajax技术相关。 一、Ajax简介二、同步、异步传输区别 2.1 异步传输2.2 同步传输 三、Ajax所包含的技术四、基础Ajax示例五、完整…