巧用ingest pipeline实现Elasticsearch索引的重定向
背景
在Elasticsearch的日常使用过程中,常常会碰到如下问题:
- 索引的分片数量设置的较少,集群中只有部分节点承担写入压力,导致出现热点,写入性能一直无法提升。
- 当前正在执行写入的索引因为某些配置不满足需求但又无法动态更新该配置,需要根据新的索引模板创建新索引承担写入。
对于第1个问题,在7.x版本的集群中比较常见,因为所以默认只有1分片1副本,该问题的一种解决方式就是切换一个新的索引进行写入,提高新的索引的分片数量(最好保持为节点数量的倍数),使得写入并行度提高,从而提高写入吞吐率。
第2个问题往往出现在以下场景中:
- 想要开启对索引的最优压缩以节省存储成本,比如指定codec为best_compression
- 在6.8版本的集群中,索引默认是不开启soft_deletes的(index.soft_deletes.enabled默认为false), 导致对于已经创建好的索引,不能使用CCR跨集群复制功能。
- 跨集群数据迁移过程中,需要切换一个新的索引承担写入,老的索引通过snapshot方式迁移至新的集群,新的索引因为文档数量较少可以使用logstash、reindex、CCR进行跨集群数据同步。
但是如果业务端不能修改写入的索引名称,或者是无法更新诸如logstash、filebeat的配置文件并进行重启,这时候该怎么办呢?
既然业务端不能有任何变更,那就不能够直接使用索引别名了,因为对于已经存在的索引,是无法创建同名称的别名的。当然,如果业务端一开始使用的就是别名,那就另当别论了,直接修改is_write_index配置项就可以切换索引了。
所以,对于业务端不能有任何变更,但是需要切换索引写入的场景,我们可以使用ES的default pipeline 来实现索引的重定向: 写入时指定了一个索引,实际上写入到了另外一个索引。
实战过程
default pipeline 与final pipeline
default pipeline与final pipeline实际上都是普通的ingest pipeline,只是和一般的pipeline执行时机不同;default pipeline的执行时机是当前写入请求没有指定pipeline时,final pipeline的执行时机是在所有pipeline执行完毕后,具体如图所示:
如果当前bulk或者index请求指定了pipeline参数,则会先执行自定义的普通pipeline,所有的pipelie执行完毕后在执行final pipeline(如果索引的显式的设置了index.final_pipeline);如果当前bulk或者index请求没有指定pipeline,当索引显式的设置了index.default_pipeline参数时,则会先执行default pipeline,然后再执行final pipeline。
索引重定向
使用set ingest processor可以对当前写入的索引名称_index字段进行重新赋值, 如下图所示:
因此我们可以创建一个pipeline, 将其配置为当前正在写入的索引的default pipeline,从而实现把所以重定向写入到另外一个索引中:
定义pipeline
PUT _ingest/pipeline/redirect
{
"description": "_description",
"processors": [
{
"set": {
"field": "_index",
"value": "new_index"
}
}
]
}
设置default_pipeline
PUT test/_settings
{
"index.default_pipeline": "redirect"
}
经过上述设置后,可以发现,向test索引写入的数据已经全部写入到了new_index索引。
为什么不用final pipeline呢?因为final pipeline强制要求不能进行索引的重新命名(可能因为需要避免出现循环)。
存在的问题
使用default pipeline,使得在业务端不用做任何变更的情况下,将数据写入到一个新的索引中去,但是该方式还存在以下问题:
- 性能问题:使用ingest pipeline是会带来一定的性能损耗的,pipeline的处理过程中需要遍历每个document,节点的cpu使用率势必会上升,在集群资源充足的情况下或者索引本身写入速率不高的情况下可以使用该方式解决索引切换的问题。
- 查询方式的问题:虽然解决了写入索引切换的问题,但是数据存储到新的索引中去了,查询时就必须去查询新的索引;如果业务使用的是通配符的方式去查询,则非常好解决,只需要把新索引命名为老的索引名称再增加一个后缀即可,不能使用通配符的方式查询索引的话,就不能使用该方式切换写入的索引了。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android 7.0 手电筒控制实现
- 【STM32H7】第13章 RL-TCPnet V7.X之创建多个TCP客户端
- Android倒计时的开始与停止 剩余时分秒的展示
- 由LFI引起的Zimbra邮件管理系统0day
- Android手电筒兼容各个手机与版本
- 【STM32F429】第13章 RL-TCPnet V7.X之创建多个TCP客户端
- RecyclerView仿应用列表实现网格布局
- Android实现带进度条的WebView
- Android实现记住密码功能
- 【- Flutter Web篇 -】 FlutterUnit web版闪亮登场
- Android简单实现弹幕效果
- 实现 Base64 的编码解码
- Android实现底部导航栏的主界面
- Spring注解@Autowired源码分析
- 使用RecyclerView实现水平列表