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

2023-11-08

什么是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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Elasticsearch之利用bulk提高写入性能(含源码分析) 的相关文章

  • Logstash 错误 Java::JavaLang::NoClassDefFoundError 无法解决

    我是elasticsearch ES 和logstash 的新手 我已经使用它成功设置了elasticsearch和kibanalink https www youtube com watch v hVgrXi 9L6Y 之后我尝试使用lo
  • 使用elasticsearch按一天中的时间累积流量

    我正在接收来自大量客户端应用程序的请求 事件 我想使用elasticsearch 来找出我的最高流量点是什么时候 我尝试过的一件事是使用嵌套直方图进行过滤器聚合 然后使用嵌套的 术语 聚合 通过脚本字段获取一天中的不同时间 以下是我的尝试
  • Spark任务仅在一个执行器上运行

    大家好 首先我知道这个线程的存在 Spark 中的任务仅在一个执行器上运行 https stackoverflow com questions 53425983 task is running on only one executor in
  • Elasticsearch 过滤器/计算嵌套字段

    我有带有嵌套字段的文档 如下所示 results id 1234 name asdf id 5678 name jkl ip 1 2 3 4 嵌套字段的映射如下所示 results type nested properties id typ
  • ElasticSearch:对聚合键进行排序,不区分大小写,并保持键的大小写

    我想从汽车中获得不同的制造值 并且制造值应该不区分大小写地按升序排序 我使用的是elasticsearch版本2 4 4 颜色和制作字段的映射 color type string fields keyword type string ind
  • Elastic Search 5.x 嵌套多个查询 C#

    我将 C 与这些 nuget 包一起使用
  • Elasticsearch TransportClient NetworkPlugin NoClassDefFoundError

    我期待将 Elasticsearch 集成到 Spring Boot Web 应用程序中 这是创建传输客户端的配置 Configuration public class ElasticsearchConfig private Transpo
  • match_none 有什么用?

    我浏览了docs https www elastic co guide en elasticsearch reference current query dsl match all query html query dsl match no
  • Python elasticsearch DSL 聚合/每个文档嵌套值的度量

    我试图找到 2 级嵌套中的最小值 每个文档单独的最小值 到目前为止 我能够进行聚合 计算搜索结果中所有嵌套值的最小值 但无需按文档进行分隔 我的示例架构 class MyExample DocType myexample id Intege
  • Elasticsearch:如何查询连接数?

    如何询问我的 Elasticsearch 服务器现在有多少个连接 这与插座数量相同吗 我也不知道如何获得这些数字 这与客户端的数量不同 对吧 因为每个客户端可能打开多个连接 找不到任何相关信息 但我确实发现您可以在 Elasticsearc
  • 批量删除如何工作?

    我尝试使用bulkDelete让我的机器人删除其消息 但我收到此错误 node 5724 UnhandledPromiseRejectionWarning Unhandled promise rejection rejection id 1
  • Elasticsearch 单个字段的多个分析器

    我使用严格的预定义映射将不同类型的文档存储在单个索引中 它们都有一些字段 例如 body 但我希望在索引时对它们进行稍微不同的分析 例如 对特定文档使用不同的标记过滤器 并在搜索时以相同的方式处理 据我所知 分析器不能按文档指定 我还考虑使
  • Nest Elastic - 构建动态嵌套查询

    我必须使用 Nest 查询嵌套对象 但是查询是以动态方式构建的 下面的代码演示了以静态方式对嵌套 书籍 进行查询 QueryContainer qry qry new QueryStringQuery DefaultField name D
  • 无法使用 java 8 在 Windows 10 上安装 elasticsearch 5.1.1

    我正在尝试在安装了 java 8 111 的 Windows 10 笔记本电脑上安装 ElasticSearch 5 1 1 当我尝试安装 Elastic search 时触发错误 C Users 用户名 Downloads elastic
  • 如何使用ElasticSearch来实现社交搜索?

    我正在尝试使用 ElasticSearch 创建具有社交功能的商业搜索 我有一个企业目录 用户可以通过不同的方式与这些企业进行交互 通过查看它们 检查它们等 当用户搜索商家时 我希望能够在结果顶部向他们显示他们的朋友与之互动过的商家 或根据
  • 从 node.js 创建对 AWS ES 实例的有效签名请求

    我试图找到一个示例 说明如何连接到 Node js 中的 AWS ES 实例 然后通过一个简单的请求访问 ES 集群 我正在尝试使用elasticsearch节点包 https www npmjs com package elasticse
  • Elasticsearch - 使用“标签”索引来发现给定字符串中的所有标签

    我有一个 elasticsearch v2 x 集群 其 标签 索引包含大约 5000 个标签 tagName tagID 给定一个字符串 是否可以查询标签索引以获取在该字符串中找到的所有标签 我不仅想要精确匹配 而且还希望能够控制模糊匹配
  • 如何增加vm.max_map_count?

    我正在尝试在 Ubuntu EC2 计算机 t2 medium 中运行弹性搜索 但我收到消息 最大虚拟内存区域 vm max map count 65530 太低 至少增加到 262144 我怎样才能增加vm max map count v
  • NEST 1.0:请参阅 Fiddler 上的请求

    我刚刚更新到 NEST 1 0 我在远程服务器 不是本地主机 上有 Elastic Search 通常我在使用 Fiddler 发送和接收请求时没有任何问题 更新后 bammm 没有检测到任何请求 但我的应用程序发出这些请求没有任何问题 你
  • Elasticsearch 在 Mac 上存储数据的位置

    类似的问题this one https stackoverflow com questions 24694201 where are data files of elasticsearch on a standard debian inst

随机推荐

  • 基于VS平台的库生成与使用

    基于VS平台的库生成与使用 动态库的创建连接参考链接 https www cnblogs com codingmengmeng p 6287425 html 静态库的创建连接参考链接 https www cnblogs com zqh201
  • 【华为OD机试真题】We Are A Team(C++&java&python)100%通过率 超详细代码注释 代码优化

    We Are A Team 题目描述 总共有n个人在机房 每个人有一个标号 1 lt 标号 lt n 他们分成了多个团队 需要你根据收到的m条消息判定指定的两个人是否在 一个团队中 具体的 1 消息构成为abc 整数a b分别代表两个人的标
  • python生成100个随机数_每日任务:Python对随机生成的100个数进行排序

    author wuwa coding utf 8 import random 随机生成100个10至1000之间的数 对生成的100个数进行排序 禁止使用Python自带的排序函数 要自己实现排序函数 class MySort 生成随机数
  • 动态规划算法刷题

    第一天 使用滚动数组 1 菲波那切数列 斐波那契数 通常用 F n 表示 形成的序列称为 斐波那契数列 该数列由 0 和 1 开始 后面的每一项数字都是前面两项数字的和 也就是 F 0 0 F 1 1 F n F n 1 F n 2 其中
  • C++按行读/写txt文件

    将 hello 写入F test txt的第1行 include
  • 在ASP.NET中显示进度条

    在ASP NET中显示进度条 孟宪会之精彩世界 对于加载时间比较长的ASP NET页面 我们可以在客户端浏览器中显示进度条来显示页面正在装载 下面就是具体的实现过程 新建项目 名字为WebPortal 在项目类型中选择Visual C 项目
  • STM32单片机并口通信编程实例:代码详解与应用案例

    引言 单片机并口通信是一种传统而常用的通信方式 通过并行方式进行数据传输 尽管串口通信在现代应用中更加普遍 但并口通信在一些特定领域的应用仍然具有重要意义 本文将介绍单片机并口通信的原理 配置和实践方法 并给出STM32单片机的示例代码和详
  • 类属性、实例属性

    实例属性 对象属性 顾名思义 类属性就是类对象所拥有的属性 它被所有类对象的实例对象所共有 在内存中只存在一个副本 这个和C 中类的静态成员变量有点类似 对于公有的类属性 在类外可以通过类对象和实例对象访问 类属性 实例如下 class P
  • 根据字节大小分割字符串(java)

    public List
  • JAVA学习进程、线程

    1 进程 进程 是正在进行的程序 是系统进行资源分配和调用的独立单位 每一个进程都有它自己的内存空间和系统资源 2 线程 线程 是进程中的单个顺序控制流 是一条执行路径 分为 单线程和多线程 多线程的实现方式 设置和获取线程名称 线程的调度
  • t-SNE手写字识别案例

    参考链接 https scikit learn org stable auto examples manifold plot lle digits html sphx glr auto examples manifold plot lle
  • Unity C# 计算导弹抛物线弹道和转向

    在三维空间中 利用抛物线公式计算弹道 得到一个发射初速度 让导弹打击到指定地点效果 脚本使用 只需指定目标点即可可以通过Hight调整导弹的飞行高度可以通过Gravity调整导弹的飞行速度 通过以下两个脚本实现 工具脚本计算弹道 Missi
  • Docker部署ELK(配置密码登录)及Elastalert企业微信告警配置

    ELK部署记录 部署Elasticsearch Kibana Cerebro 通过docker进行部署 可以避免很多缺少依赖的问题 推荐使用centos7环境进行部署 请提前安装好docker服务 docker compose服务 先新建一
  • jquery two class

    This should work a b If you want an intersection just write the selectors together without spaces in between So for some
  • 基于Flume日志收集系统架构和设计(一)

    问题导读 1 Flume NG与Scribe对比 Flume NG的优势在什么地方 2 架构设计考虑需要考虑什么问题 3 Agent死机该如何解决 4 Collector死机是否会有影响 5 Flume NG可靠性 reliability
  • TCP flag注释

    三次握手Three way Handshake 一个虚拟连接的建立是通过三次握手来实现的 1 B gt SYN gt A 假如服务器A和客户机B通讯 当A要和B通信时 B首先向A发一个SYN Synchronize 标记的包 告诉A请求建立
  • 【Maven拉不到】Cannot resolve plugin org.apache.maven.plugins:maven-deploy-plugin:2.8.2

    问题 Cannot resolve plugin org apache maven plugins maven deploy plugin 2 8 2 与本地原来的有冲突或者是有多个版本的 解决办法 1 找到本地安装Maven的路径 2 找
  • Jenkins+Docker自动化部署Spring boot项目 (三)搭建jenkins

    Jenkins Docker自动化部署Spring boot项目 三 搭建jenkins 搭建jenkins jenkins我是通过下载镜像完成安装的 建议使用docker hub的镜像 它提供的版本比较新 一开始为了图快 我用了163镜像
  • Selenium进阶——解决web 自动化中上传文件的问题

    在做ui自动化测试中 经常会遇到上传文件或者图片的场景 通常的解决方案是自动化工具 autoIT 在这里我介绍一种 通过jdk自带api java awt Robot 来解决类似问题的方法 java awt Robot类主要用于模拟用户点击
  • Elasticsearch之利用bulk提高写入性能(含源码分析)

    什么是bulk操作 bulk是批量的意思 也就是把原来单个的操作打包好 通过批量的api提交到ES集群 下面是个示例 单个操作 PUT my index 000001 doc 1 timestamp 2099 11 15T13 12 00