[译]Elasticsearch Sequence ID实现思路及用途
原文地址:https://www.elastic.co/blog/elasticsearch-sequence-ids-6-0
如果
几年前,在Elastic,我们问自己一个"如果"问题,我们知道这将带来有趣的见解:
"如果我们在Elasticsearch中对索引操作进行全面排序会怎样?我们可以建立什么?
答案涵盖范围很广:
- 我们可以构建一种称为"变更API"的功能,它可以接受操作ID,并为您提供自那时以来数据更改的列表。很棒!
- 我们可以只查找发生变化的索引操作,从而建立增量reindex!
- 我们可以使用增量reindex功能,通过过滤/连续reindex建立以实体为中心的索引!
- 我们可以建立不依赖于数据按时、按顺序和全局精确时间戳到达的数据滚动/汇总索引!
- 我们可以建立类似物化视图的东西,在新数据/操作到达时进行更新!
- 如果节点之间的操作因网络断开等原因而丢失,我们可以建立一种重放操作的方法,这将大大加快恢复速度!
- 我们可以建立一种在集群之间重放操作的方法!跨数据中心复制!
所有这些都需要打破一个小小的障碍:为索引操作添加序列号。很简单:我们只需要在主索引的每个操作中添加一个计数器!太简单了,我们看到社区成员和员工尝试了好几次。但当我们层层剥开洋葱头时,我们发现它比最初看起来要复杂得多。在我们开始讨论变更应用程序接口的实用性近6年后,我们仍然没有一个变更应用程序接口。原因何在?本博客的目的是分享幕后发生的事情,并就这个问题的答案提供一些见解。
在过去两年中,我们几乎从头开始重写了复制逻辑。我们从已知的学术算法中汲取精华,同时确保我们仍能确保并行性,这正是Elasticsearch能够如此快速的原因:这是许多甚至所有传统共识算法都无法做到的。我们与分布式系统专家合作,为我们的复制模型建立了TLA+规范。我们增加了大量测试和测试基础设施。
这篇博客必然是技术性的,因为我们会深入探讨Elasticsearch如何进行复制的一些核心内容。不过,我们的目的是通过解释/定义/链接一些术语(即使您可能已经理解了这些术语),让更多读者能够理解这些术语。首先,让我们深入了解Elasticsearch所面临的一些挑战。
挑战
在继续深入之前,我们必须先谈谈我们的复制模型以及它的重要性。在Elasticsearch数据索引中,数据被分割成所谓的"分片",基本上就是索引的子分区。你可以有5个主分片(基本上是索引的5个子分区),每个主分片可以有任意数量的主分片副本(称为副本)。但重要的是,每个子分区只有一个"主分片"。主分片首先接受索引操作(索引操作包括"添加文档"或"删除文档"等操作),然后将索引操作复制到副本。因此,在将每个操作转发给副本之前,不断递增计数器并为每个操作分配一个序列号是非常简单的。只要没有人重启服务器,网络正常运行时间达到100%,硬件不出现故障,没有长时间的Java垃圾回收事件,也没有人升级软件,这种简单易行的方法就能真正奏效。
但我们生活在现实世界中,当这些假设发生变化时,Elasticsearch就会进入"故障"模式和"恢复"过程。如果它们影响到运行主分片的节点,可能需要主分片停机,由另一个副本取而代之。由于变化来得突然,一些正在进行的索引操作可能尚未完全复制。如果您有2个或更多副本,其中一些操作可能只到达了其中一个副本,而没有到达另一个副本。更糟糕的是,由于Elasticsearch会并发索引文档(这也是Elasticsearch速度如此之快的原因之一!),每个副本都可能有不同的操作集,而这些操作集在另一个副本中并不存在。即使只运行一个副本(Elasticsearch的默认设置),也可能会出现问题。如果旧的主副本回来并被添加为副本,它可能包含从未复制到新主副本的操作。所有这些情况都有一个共同点:主节点失效后,分片上的操作历史可能会发生偏离,我们需要一些方法来解决这个问题。
PrimaryTerms & Sequence Numbers
我们采取的第一步是能够区分旧的和新的主分片。我们必须有一种方法来识别来自旧主分片的操作与来自新主分片的操作。此外,整个集群需要就此达成一致,以确保在出现问题时不会发生争执。这促使我们实现了主要术语。这些主要术语是增量的,并在主分片被提升时更改。它们被持久化在集群状态中,因此代表了集群所处的主分片的"版本"或"生成"。有了主要术语,操作历史中的任何冲突都可以通过查看操作的主要术语来解决。新术语优于旧术语。我们甚至可以开始拒绝那些太旧的操作,避免混乱的情况发生。
一旦我们设置了主要术语的保护机制,我们添加了一个简单的计数器,并开始为每个操作分配一个来自该计数器的序列号。因此,这些序列号使我们能够了解在主分片上发生的索引操作的特定顺序,我们可以将其用于接下来几节中将要讨论的各种目的。您可以在响应中看到分配的序列号和主要术语:
$ curl -H 'Content-Type: application/json' -XPOST http://127.0.0.1:9200/foo/doc?pretty -d '{ "bar": "baz" }'{"_index": "foo","_type": "doc","_id": "MlDBm10BditXXu4kjj5E","_version": 1,"result": "created","_shards": {"total": 2,"successful": 1,"failed": 0},"_seq_no": 19,"_primary_term": 1
}
注意返回的响应中现在包含了_seq_no和_primary_term。
Local and Global Checkpoints
有了主要术语和序列号,我们理论上有了检测分片之间差异并在主分片失败时重新对齐它们的工具。拥有主要术语为x的旧主分片可以通过删除主要术语为x且不存在于新主分片历史记录中的操作来恢复,并且具有更高主要术语的缺失操作可以索引到旧主分片中。
不幸的是,当您同时每秒索引数十万甚至数百万个事件时,比较数百万次操作的历史记录实际上是不切实际的。存储成本过高,直接比较所需的计算工作将耗时过长。为了解决这个问题,Elasticsearch维护了一个名为全局检查点的安全标记。全局检查点是一个序列号,我们知道所有活动分片的历史记录都至少与之对齐。换句话说,所有序列号低于全局检查点的操作都已经被所有活动分片处理,并在各自的历史记录中是相等的。这意味着在主分片失败后,我们只需要比较新主分片和任何剩余副本之间最后已知的全局检查点以上的操作。当旧主分片恢复时,我们取其最后知道的全局检查点,并将其以上的操作与新主分片进行比较。这样,我们只需要比较需要比较的操作,而不是整个历史记录。
推进全局检查点的责任属于主分片。主分片通过跟踪副本上已完成的操作来实现这一点。一旦检测到所有副本已经超过给定的序列号,主分片将相应地更新全局检查点。分片副本不会一直跟踪所有操作,而是维护一个全局检查点的本地变体,称为本地检查点。本地检查点是一个序列号,该副本上处理了所有更低序列号的操作。每当副本确认(或ack)主节点的写操作时,它们也会向主节点提供更新的本地检查点。利用本地检查点,主节点就能更新全局检查点,然后在下一次索引操作中将全局检查点发送给所有分片副本。
下面的动画展示了在面对有损网络和突发故障等并发挑战时,随着序列号和全局/本地检查点的增加而发生的情况:

当索引操作从主分片发送到副本时,我们会跟踪每个副本确认收到的最高序列号,并将其称为全局检查点。主分片会告诉所有副本全局检查点是多少。因此,如果主分片切换,我们只需要比较和可能重新处理自上次全局检查点以来的操作,而不是磁盘上的所有文件。
全局检查点还具有另一个很好的特性——它代表了那些被保证会留下的操作(它们在所有活动分片的历史记录中),以及可能会被回滚的操作所在的区域,如果主分片在它们被完全复制并向用户确认之前恰好发生故障。这是一个微妙但重要的特性,对于未来的变更API或跨数据中心复制功能将是至关重要的。
第一个好处:更快恢复
在Elasticsearch6.0之前,我们跳过了实际恢复过程的工作原理。当Elasticsearch在副本处于离线状态后恢复副本时,它必须确保该副本与活动主分片完全相同。非活动分片具有同步刷新标记,以便快速进行验证,但具有活动索引的分片则没有任何保证。如果一个分片在仍有活动索引的情况下掉线,那么新的主分片将通过网络复制Lucene段(即磁盘上的文件)。如果这些分片很大,这可能是一个繁重且耗时的操作。这是因为在6.0之前,我们没有跟踪个别写操作(序列号),而在幕后,Lucene会将所有添加/更新/删除合并到更大的分段中,这样就无法恢复构成更改的单个操作…也就是说,除非你将事务日志保留一段时间。
这就是我们现在所做的:我们保留事务日志,直到它变的"过大"或"过旧",不再有必要继续保留它。如果副本需要"更新",我们会使用该副本已知的最后一个全局检查点,仅从主事务日志中回放相关更改,而不是昂贵的大文件复制。如果主事务日志"过大"或"太旧"而无法重放到副本,那么我们将回退到旧的基于文件的恢复方式。
如果您一直在运行一个大型集群,而该集群经常出现网络断开、重启、升级等情况,我们希望这将大大提高您的工作效率,因为您不必在分片恢复时长时间等待。
须知
正如上一节中提到的,事务日志保留直到它"过大"或"过旧"而不再需要保留。我们如何确定什么是"过大"或"过旧"呢?当然是可配置的!在6.0中,我们引入了两个新的事务日志设置:
*index.translog.retention.size:默认为512MB。如果事务日志超过这个大小,我们只保留这么多数据。
*index.translog.retention.age:默认为12小时。超过这个时间段,我们将不再保留事务日志文件。
这些设置很重要,因为它们影响新的、更快的恢复工作以及磁盘使用情况。较大的事务日志保留大小或较长的保留时间意味着您有更高的机会通过新的更快恢复来进行恢复,而不是依赖于旧的基于文件的恢复。然而,它们也伴随着一定的成本:这会增加磁盘利用率,而且请记住事务日志是按分片进行的。举个实际的例子,如果您有20个索引,每个索引有5个主分片,并且在12小时内写入大量数据,那么可能会导致额外205512mb=50GB的磁盘利用率,直到那12小时窗口过期为止。如果您在不同索引上有不同的恢复和大小需求,您可以根据需要在每个索引上进行调整。例如,如果您预计进行机器或节点维护,您可能需要考虑对事务日志保留窗口进行任何调整。
注意:在6.0之前,事务日志的大小在索引过程中也可以增长到512MB(默认值),根据index.translog.flush_threshold_size设置。这意味着新的保留策略不会改变活动分片的存储需求。这一变化影响了停止索引的分片。现在,我们不清理事务日志,而是将其保留另外12小时。
下一个优势:跨数据中心复制
正如文章开头提到的,如果我们能进行有序的索引操作,我们就能在Elasticsearch中做很多美妙的事情。虽然花了一些时间,但现在我们做到了。更快的恢复是我们决定构建的第一个用例:它允许我们测试我们添加的新功能。
但我们知道跨数据中心复制也是我们企业客户常常要求的功能,所以这是我们即将添加的另一个功能。这需要构建新的API、在复制之上增加新的监控功能,以及是的,还需要进行更多的测试和文档编写。
还有更多工作要做
正如您在序列号GitHub问题上看到的,我们在序列号功能上有了一个良好的开端,但仍有许多工作要做!我们认为迄今为止所做的工作代表了我们向前迈出的一大步,即使它还没有涵盖我们可以建立/围绕序列号的所有功能。如果您有兴趣继续关注我们的工作,请随时关注标有:Sequence IDs的ticket或PR,或直接在讨论区与我们联系!
相关文章:
[译]Elasticsearch Sequence ID实现思路及用途
原文地址:https://www.elastic.co/blog/elasticsearch-sequence-ids-6-0 如果 几年前,在Elastic,我们问自己一个"如果"问题,我们知道这将带来有趣的见解: "如果我们在Elasticsearch中对索引操作进行全面排序会怎样…...
Java基于SpringBoot+Vue的藏区特产销售平台
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
12-表的约束
知识背景 表的约束,就是在表中的数据上加上约束,也被称为数据完整性约束。数据完整性约束的目的是为了不被规定的、不符合规范的数据进入数据库 在录入数据库或数据发生变化时,DBMS(数据库管理系统)会按照一定的约束条件对数据进行监测&…...
【人工智能】深度学习入门:用TensorFlow实现多层感知器(MLP)模型
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 多层感知器(MLP)是一种基础的神经网络结构,广泛应用于分类和回归任务。作为深度学习的重要组成部分,理解并实现MLP是学习更复杂神经网络模型的基础。本文将介绍多层感知器的核心概念、数学原理,并使用…...
【Go】-go中的锁机制
目录 一、锁的基础知识 1. 互斥量/互斥锁 2. CAS(compare and swap) 3. 自旋锁 4. 读写锁 5. 乐观锁 & 悲观锁 6. 死锁 二、go中锁机制 1. Mutex-互斥锁 2. RWMutex-读写锁 2.1 RWMutex流程概览 2.2 写锁饥饿问题 2.3. golang的读写锁源…...
c ++零基础可视化——vector
c 零基础可视化——vector 初始化 vector<int> v0(5); // 0 0 0 0 0 vector<int> v1(5, 1); // 1 1 1 1 1 vector<int> v2{1, 2, 3} // 1 2 3 vector<int> v3(v1); // 1 1 1 1 1 vector<vector<int>> v4(2, vect…...
Centos 7 安装 Docker 最新版本
文章目录 一、卸载旧版本二、安装最新版本docker三、问题解决3.1 启动docker报错3.2 启动容器报错 一、卸载旧版本 #如果之前安装过旧版本的Docker,可以使用下面命令卸载 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest …...
构建高效在线教育:SpringBoot课程管理系统
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理在线课程管理系统的相关信息成为必然。开发…...
二进制与网络安全的关系
二进制与网络安全的关系 声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以…...
【计算机网络】网段划分
一、为什么有网段划分 IP地址 网络号(目标网络) 主机号(目标主机) 网络号: 保证相互连接的两个网段具有不同的标识 主机号: 同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号 互联网中的每一台主机,都要隶属于某一个子网 -&…...
VB、VBS、VBA的区别及作用
VB、VBS 和 VBA 是三种与微软 Visual Basic 相关的编程语言或环境,它们在功能和用途上有所不同: # Visual Basic (VB) Visual Basic 是一种面向对象的编程语言,最初由微软公司开发。它是一种高级编程语言,旨在简化开发过程&…...
深度学习中的循环神经网络(RNN)与时间序列预测
一、循环神经网络(RNN)简介 循环神经网络(Recurrent Neural Networks,简称RNN)是一种专门用于处理序列数据的神经网络架构。与传统神经网络不同,RNN具有内部记忆能力,能够捕捉数据中的时间依赖…...
Unity 设计模式-原型模式(Prototype Pattern)详解
原型模式 (Prototype Pattern) 原型模式 (Prototype Pattern) 是一种创建型设计模式,它允许通过复制现有的对象来创建新对象,而不是通过直接实例化类。这意味着你可以通过克隆原型对象来生成新的实例,而不必依赖类的构造函数。该模式的核心思…...
如何在 RK3568 Android 11 系统上排查以太网问题
1. 硬件连接检查 在进行软件诊断之前,首先确保所有硬件连接正常: 确认网线可靠插入设备的以太网端口。交换机、路由器中与设备连接的端口是否正常工作。若有可能,尝试更换网线或使用其他端口。2. 使用命令行工具进行基本检查 检查网络接口状态 连接设备并使用 ADB 或终端…...
如何在WPF中嵌入其它程序
在WPF中嵌入其它程序,这里提供两种方案 一、使用WindowsFormHost 使用步骤如下 1、添加WindowsFormsIntegration和System.Windows.Forms引用 2、在界面上放置WindowsFormHost和System.Windows.Forms.Panel 1 <Grid> 2 <WindowsFormsHost> 3…...
大模型呼入系统是什么?
大模型呼入系统是什么? 作者:开源呼叫中心系统 FreeIPCC,Github地址:https://github.com/lihaiya/freeipcc 在呼叫中心领域,大模型呼入是指利用大型语言模型(如GPT等)处理客户呼入的电话请求&a…...
Flutter:SlideTransition位移动画,Interval动画延迟
配置vsync,需要实现一下with SingleTickerProviderStateMixinclass _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{// 定义 AnimationControllerlate AnimationController _controller;overridevoid initState() {super.…...
【Elasticsearch入门到落地】2、正向索引和倒排索引
接上篇《1、初识Elasticsearch》 上一篇我们学习了什么是Elasticsearch,以及Elastic stack(ELK)技术栈介绍。本篇我们来什么是正向索引和倒排索引,这是了解Elasticsearch底层架构的核心。 上一篇我们学习到,Elasticsearch的底层是由Lucene实…...
网络安全概论
一、 网络安全是一个综合性的技术。在Internet这样的环境中,其本身的目的就是为了提供一种开放式的交互环境,但是为了保护一些秘密信息,网络安全成为了在开放网络环境中必要的技术之一。网络安全技术是随着网络技术的进步逐步发展的。 网络安…...
后端开发如何高效使用 Apifox?
对于后端开发者来说,日常工作中少不了接口的设计、调试和文档编写。你是否也曾因接口文档更新不及时、测试工具分散而头疼不已?Apifox,这款全能型工具,或许能成为你的效率神器! Apifox究竟有哪些功能能帮助后端开发者…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...
小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...
