ES 5.x Bulk update重复的文档id性能低下
现在很多公司(包括我们自己)将ES用作数据库数据的索引,将多个数据库的数据同步到ES是非常常见的应用场景。所以感觉这个问题可能会困扰不止一个用户,而官方的文档也没有对update的底层机制及局限做特别说明,特将该问题的讨论和结论整理成文,供社区用户参考。
问题描述
在ES5.x里通过bulk update将数据从数据库同步到ES,如果短时间更新的一批数据里存在相同的文档ID,例如一个bulk update里大量写入下面类型的数据:
{id:1,name:aaa} {id:1,name:bbb}{id:1,name:ccc}{id:2,name:aaa}{id:2,name:bbb}{id:2,name:ccc}.......
则更新的速度非常慢。 而在ES 1.x和2.x里同样的操作快得多
根源追溯
update操作是分为两个步骤进行,即先根据文档ID做一次GET,得到最新版本的文档,然后在内存里做好更新后,再写回去。问题就出在这个GET操作上面。
在core/src/main/java/org/elasticsearch/index/engine/InternalEngine.java
这个类里面,get函数会根据一个realtime
参数(默认是true
),决定如何获取原始文档。
public GetResult get(Get get, Function<String, Searcher> searcherFactory, LongConsumer onRefresh) throws EngineException {assert Objects.equals(get.uid().field(), uidField) : get.uid().field();try (ReleasableLock lock = readLock.acquire()) {ensureOpen();if (get.realtime()) {VersionValue versionValue = versionMap.getUnderLock(get.uid());if (versionValue != null) {if (versionValue.isDelete()) {return GetResult.NOT_EXISTS;}if (get.versionType().isVersionConflictForReads(versionValue.getVersion(), get.version())) {throw new VersionConflictEngineException(shardId, get.type(), get.id(),get.versionType().explainConflictForReads(versionValue.getVersion(), get.version()));}long time = System.nanoTime();refresh("realtime_get");onRefresh.accept(System.nanoTime() - time);}}// no version, get the version from the index, we know that we refresh on flushreturn getFromSearcher(get, searcherFactory);}
可以看到realtime
参数决定了是否以实时的方式获取数据。 如果设置为false
,意味着不关心实时性,此时直接从searcher
对象里面拿数据。因为searcher
只能访问refresh过的数据,那些刚写入到indexing writter buffer里,还未经历过refresh的数据不会被访问到,故而该读取方式是准实时(Near Real Time)。 而这个realtime
参数默认设置是true
,说明需要以实时的方式访问数据,也就是说writter buffer里未经refresh的数据也要能被检索到,如何保证这块数据也能被实时访问呢?
从代码里可以看到,其中存在一个refresh("realtime_get")
的函数调用。这个函数调用会检查,GET的doc id是否都是可以被搜索到。 如果已经写入了但无法搜索到,也就是刚刚写入到writter buffer里还未refresh这种情况,就会强制执行一次refresh操作,让数据对searcher可见,保证getFromSearcher
调用拿的是完全实时的数据。
实际上测试下来,正是这样的结果: 在关闭索引的自动刷新的情况下(设置refresh_interval: -1
,只写入一条文档,然后对该文档ID执行一个GET操作,就会看到有一个新的segment生成。 说明GET的过程触发了refresh。
查了下文档,如果仅仅是做GET API调用,这个实时性可以人为控制,只需要在url里带可选参数realtime=[true/|false]
。 参考: reference/5.6/docs-get.html#realtime。
然而,不幸的是,update API的文档和源码都没有提供一个禁用实时性的参数。 update对GET的调用,传入的realtime参数是在代码里写死为true的,意味着update的时候,必须强制执行一次realtime GET.
为什么是这样的代码逻辑,仔细想一下就也就了然了。因为update允许对文档做部分字段更新,如果有2个请求分别更新了同一个文档的不同字段, 可能先更新的数据还在writter buffer里,没来得及refresh,因而对searcher不可见。如果后续更新不做一次refresh,前面的更新可能就丢失了。
另外一个问题,为啥5.x之前的版本没有这个性能问题? 看了下2.4的GET方法源码,其的确没有采用refresh的方式来保障数据的实时性,而是通过访问translog来达到同样的目的。官方在这个变更里pull#20102将机制从访问translog改为了refresh。理由是之前ES里有很多地方利用translog来维护数据的位置,使得很多操作变得很慢,去掉对translog的依赖可以全面提高性能。
很遗憾,这个更改对于短时间反复大量更新相同doc id的操作,会因为过于频繁的强制refresh,短时间生成很多小segment,继而不断触发segment合并,产生显著的性能损耗。 从上面链接里的讨论看,官方认为,在提升大多数应用场景性能的前提下,对于这种较少见的场景下的性能损失是值得付出的。所以,建议从应用层面去解决。
因此,如果实际应用场景里遇到类似的数据更新问题, 只能是优化应用数据架构,在应用层面合并相同doc id的数据更新后再写入ES,或者只能使用ES 2.x这样的老版本了。
注意:此问题在es6.3以上的版本已经解决
文章来源:https://elasticsearch.cn/article/273
ES 5.x Bulk update重复的文档id性能低下相关推荐
- ES 5.x bulk update重复的文档ID性能低下分析
目前很多公司将ES作为数据库数据的索引,将多个数据库的数据同步到ES是非常常见的应用场景.所以感觉问题可能会困扰不止一个用户,而官方的文档没有对update底层机制作了详细的说明,特将该问题整理成文章 ...
- es springboot 不设置id_springboot整合ES_文档ID删除
1.本课程涵盖**SpringBoot2.x版本10个常用技术点 适应企业开发要求,学习IDEA开发工具下的SpringBoot2.x开发 学习SpringBoot2.x - 基于Restful接口开 ...
- Elasticsearch——使用Java API实现ES中的索引、映射、文档操作
文章目录: 1.开篇 2.案例详解 2.1 创建ES客户端:完成与ES服务端的连接 2.2 创建索引 2.3 查看索引 2.4 删除索引 2.5 创建文档 2.6 修改文档 2.7 查看文档 2.8 ...
- java spark es_JavaSpark写RDD到ES时指定文档ID的
spark版本:2.3 ES版本:7.1 问题描述: 在通过JavaSpark写入数据到ES过程中,需要对文档id进行手动指定. 在查询ES官网之后,返现官网介绍中是有次方法的: 可以看到,JavaE ...
- Logstash:运用 fingerprint 过滤器处理重复的文档
这篇文章介绍了使用 Logstash 在 Elasticsearch中 对数据进行重复数据删除的方法. 根据你的用例,Elasticsearch中 的重复内容可能不被接受. 例如,如果你要处理指标,则 ...
- 索引重建的必要性与影响 (文档 ID 1525787.1)
索引重建的必要性与影响 (文档 ID 1525787.1) Index Rebuild, the Need vs the Implications (文档 ID 989093.1) 索引重建的必要性与 ...
- 如何修改集群的公网信息(包括 VIP) (文档 ID 1674442.1)
如何修改集群的公网信息(包括 VIP) (文档 ID 1674442.1) 文档内容 用途 适用范围 详细信息 情况1. 修改公网对应的主机名 情况2. 只修改公网 IP或者VIP, 但 ...
- RAC 和 Oracle Clusterware 最佳实践和初学者指南(平台无关部分) (文档 ID 1526083.1)
RAC 和 Oracle Clusterware 最佳实践和初学者指南(平台无关部分) (文档 ID 1526083.1) 转到底部 文档内容 用途 适用范围 详细信息 RAC 平台特 ...
- Pre-Upgrade Utility---下载并运行Oracle数据库预升级实用程序 (文档 ID 1577379.1)
如何下载并运行Oracle数据库预升级实用程序 (文档 ID 1577379.1) 文档内容 目标 脚本来源 解决方案 脚本指导 下载并安装说明 请参阅下表以确定您需要的pre-upgrade脚本的版 ...
最新文章
- HTML Window.document
- 8086逻辑运算和移位
- pip安装软件时出现Command python setup.py egg_info failed with error code 1 in /tmp/pip-build*的解决方案
- SAP UI5 初学者教程之十 - 什么是 SAP UI5 应用的描述符 Descriptor 试读版
- IDE-Ecplise-代码注释 模版 编码规范 配色
- Homebrew命令具体解释
- 敏捷开发“松结对编程”系列之七:问题集之一
- 计算机视觉基础:图像处理Task01-图像插值算法
- python编程入门-Python编程:从入门到实践 PDF 中文扫描版
- 枚举算法典型的三个例子
- 基于springboot助学贷款管理毕业设计源码061528
- 11月 第4周 GitChat 话题排行榜
- FATAL Exited too quickly (process log may have details)
- C语言中用零作为终止标记,求出一批非零整数中的偶数.奇数的平均值,用零作为终止标记的程序...
- 搭建简单windows版NAS
- Laravel执行定时任务
- Polar SC的C++实现
- SeNet || 注意力机制——源代码+注释
- 寒假学习打卡第一篇文章-----numpy的学习
- matlab画图中颜色渐变
热门文章
- 微软一年从中国挣走8亿美金 - 老杳 - 网易博客
- 车速表 html 效果,车速表速度显示的问题,终于弄明白了!
- php生成密码及密码检验
- 西门子200恒压供水梯形图_西门子plc如何做恒压供水【实例】
- 计算机考研407,407分考入985高校,考研经验分享给大家!
- mysql查询姓名第二个字_Mysql(2)查询实例
- Xiyou Linux Group 2017,2018,2019面试题
- MOF (Meta Object Facility) 规范
- 在哪下载应聘岗位通用求职简历Word模板
- Android 一个应用启动另外一个应用