副本数量的选定原则对于副本数比较好确定可以根据我们集群节点的多少与我们的存储空间决定我们的集群服务器多并且有足够大多存储空间可以多设置副本数一般是1-3个副本数如果集群服务器相对较少并且存储空间没有那么宽松则可以只设定一份副本以保证容灾副本数可以动态调整举个栗子#在一个三节点组成的集群中 设置一个主分片数为5副分片为0的索引 PUT/haizhi1{settings:{index:{number_of_shards:5,number_of_replicas:0}}}副分片数量为0则意味着集群中的任何一台机器宕机都会导致集群不可用数据不完整。副本数量是可以动态修改的PUT/haizhi1/_settings{settings:{index:{number_of_replicas:1}}}动态修改数据副本为1可以容忍一台机器宕机提高可用性模块简介Elasticsearch集群中保持数据一致性的过程中涉及到内部之间的通讯先简单介绍一下es中各模块的作用和功能1clustercluster模块是主节点执行集群管理和封装的实现管理集群状态维护集群层面的配置信息。管理集群状态将新生成的集群状态发布到集群中所有的节点调用allocation模块执行分片分配决策哪些分片应该分配到哪个节点在集群各节点中直接迁移分片保持数据平衡2allocation封装了分片分配相关的功能和策略包括主分片的分配和副分片的分配本模块由主节点调用。创建新索引、集群完全重启都需要分片分配的过程3discovery发现模块负责发现集群中的节点以及选举主节点当节点加入或者退出集群是主节点会采取像一个的行动(选主或者是集群拓扑)。4gateway负责对收到 Master 广播下来的集群状态 cluster state 数据的持久化存储并在集群完全重启时恢复它们 。5Indices索引模块管理全局级的索引设置不包括索引级的索引设置分为全局级和每个索引级。 它还封装了索引数据恢复功能 。 集群启动阶段需要的主分片恢复和副分片恢复就是在这个模块 实现的 。6HTTPHTTP 模块允许通过 JSON over HTTP 的方式访 问 ES 的 API, HTTP 模块本质上是完全异步的这意味着没有阻塞线程等待响应 。7Transport传输模块用于集群内节点之间的内部通信 。 从一个节点到另 个节点的每个请求都使用传输模块。 如同 HTTP 模块 传输模块本质上也是完全异步的。传输模块使用 TCP 通信每个节点都与其他节点维持若干 TCP 长连接。内 部节点间的所有通信都是本模块承载的。8EngineEngine 模块封装了对 Lucene 的操作及 translog 的调用它是对一个分片读写操作的最终提供者 。写操作如何保证数据的一致性算法概念ES的数据副本模型基于主从模式是基于微软的PacificA算法实现PecificA的算法特点如下Replica Group: 一个互为副本的的数据集合称为副本组该副本组中只有一个副本是主数据(Primary)其他的都为从数据(Secondary)在ES则是我们对应的主分片和副分片。Configuration: 配置信息中描述了一个副本组中的副本信息(谁是主数据谁是从数据分别位于哪个节点)Configuration Version配置信息的版本号每次发生变更时递增Serial Number代表每个写操作的数据每次写操作是会将该值递增简称SN。每个主副本维护自己的递增SNPrepared List:写操作的准备序列。存储来自外部的请求列表将请求按照SN进行从小到大排序Committed List:写操作的顺序提交新建、索引和删除请求都是写操作写操作必须先在主分片执行成功后才能复制到相应的副本组中的其他副分分片[外链图片转存失败(img-7e7Iqlmw-1567323878796)(/Users/haizhi/Library/Application Support/typora-user-images/image-20190707100909138.png)]1写请求进入到协调节点协调节点通过ID进行转发2写操作进入主副本节点(Primary)主副本节点为该操作分配SN使用该SN构建写操作请求数据结构(UpdateRequest)然后将该UpdateRequest写入自己的prepare list。3一旦主副本节点收到所有从副本节点收到所有的从副本节点的相应确定该数据已经被正确写入所有的从副本节点此时认为可以提交了将此UpdateRequest放入committed list4主副本回复客户端更新成功。此时主副本节点向从副本节点发送一个commit通知告诉所有的副本节点自己的 committed point位置从副本节点收到通知后根据指示移动到 committed point相同的位置写一致性默认的策略是qourum即多数的分片(其中分片副本可以是主分片或副分片)在写入操作的时候处于可用状态quorumint( (primary number_of_replicas) / 2 ) 1也可以通过wait_for_active_shards参数来指定必须多少个shard响应写请求才算成功#设置等待写入结果 PUT/haizhi1/type1/4?wait_for_active_shards5{key1:value12}协调节点的作用和流程协调节点在整个流程中负责参数检验创建索引和转发请求到主分片节点、等待响应并回复客户端参数检验参数检查index不可为空type不可为空source不可为空contentType不可为空opType当前操作类型如果是创建索引则校验VersionType必须为internal且Version不可为MATCH_DELETEDresolvedVersion校验解析的Version是否合法versionType不可为FORCE类型此类型已废弃id非空是长度不可大于512以及为空时则需要对versionType和resolvedVersion的检查任何一项检查未通过都会拒绝请求自动创建索引如果配置为允许自动创建索引(默认允许)则计算请求中涉及的索引可能有多个其中有哪些索引是不存在的则需要进行创建如果部分索引创建失败则实际的请求被标记为失败其他索引正常执行写流程创建索引的请求会被转发到Master节点待收到全部创建请求的结果(无论是成功还是失败)都会进行到处理下一个流程对请求的预先处理对请求的预先处理不同于对数据的预处理只是检查参数自动生成ID处理routing检查集群状态价差当前集群中是否存在主节点如果不存在会阻塞等待主节点的选举直到超时内容路由构建基于shard的请求将用户的bulkRequest重新组织为基于shard的请求列表。栗子如果用户请求有10个写操作会将这10个写操作按照路由算法确定分片是否是同一个批量操作。路由算法 : shard_num hash(_routing) % num_primary_shards默认情况下 _routing是指文档的IDES使用随机id和hash算法来确保文档均匀分布给分片当使用自定义id或者routing是id或routing值不够随机造成数据倾斜部分分片过大。可以使用index.routing_partition_size配置来减少倾斜的风险routing_partition_size越大则数据分布的越均匀。shard_num (hash(_routing) hash(_id) % routing_partition_size) % num_primary_shards也就是说一routing 字段用于计算索引中的一组分片然后使用一id 来选择该组内的分片。 index.routing_partition_size 取值应具有大于等于 1 且小于 index.number_of_ shards 的值。转发请求并等待响应根据集群状态中的内容路由表确定主分片所在的节点转发请求并等待响应PUT/haizhi1{settings:{index:{number_of_shards:5,routing_partition_size:0,#可以再创建索引的时候指定routing_partition_sizenumber_of_replicas:1}}}主分片节点作用和流程主分片所在的节点负责在本地写主分片写成功后(Prepared List)转发写副本请求等待响应回复协调节点检查请求收到协调节点发来的请求需要检测要写的是否是朱分片索引是否处于关闭状态是否延迟执行判断是否需要延迟执行如果需要延迟则放入队列否则继续往下执行判断主分片是否发生迁移如果发生迁移则转发请求到迁移的节点检测写一致性在写操作开始前。检测本次写操作涉及的shard活跃数量是否足够不足则不执行写入默认为1只要主分片可用就执行写入写Lucene和事物日志遍历请求处理动态更新字段映射然后逐条对doc索引。索引的过程是先写Lucene后写translog。处理副本信息主分片操作成功后则将请求转发到副分片上索引恢复流程索引恢复是ES数据恢复过程待恢复的数据是客户端写入成功但未执行刷盘(flush)的Lucene分段。副分片同步主分片数据根据分片的性质索引恢复过程可以分为朱分片恢复流程和副分片恢复流程主分片从translog中自我恢复尚未执行flush到磁盘lucene分段的数据可以从translog中重建副分片需要从主分片中拉取Lucene分段和translog进行恢复。索引恢复的触发条件包括从快照备份恢复节点加入和离开索引的_open操作阶段简介INIT恢复尚未启动INDEX恢复Lucene文件以及在节点间复制索引数据VERIFY_INDEX验证索引TRANSLOG启动engine重放translog建立Lucene索引FINALIZE清理工作DONE完毕主分片和副分片恢复都会经历这些阶段 但有时候会跳过具体执行过程 只 是在流程上体 现出 经历了这个短暂阶段 。 例如 副分片恢复时会跳过 TRANSLOG 重放过程 主分片恢复过 程中 的卧IDEX 阶段不会在节点之 间 复制数据。主分片恢复流程INIT 阶段一个分片的恢复是从启动开始检验当前分片是否为主分片分片状态等信息校验INDEX阶段从Lucene读取最后一次提交的分段信息VERIFY_INDEX阶段验证Lucene中的index是否被损坏 是否检验本项检查取决于配置index.shard.check_on_startup,在分片数据过多的时候分片检查会消耗更多的时间影响启动速度TRANSLOG阶段根据Lucene最后一次提交的记录和translog对比将需要重新操作的数据遍历重新索引FINALIZE阶段本阶段执行刷新(refresh)操作将缓冲的数据写入文件但不刷盘数据还在操作系统的cache中DONE阶段DONE阶段将再次执行refresh然后更新分片状态为恢复完成副分片恢复流程副分片恢复的核心思想是从主分片拉取 Lucene 分段和 translog 进行恢复 。 按数据传递的方向主分片节点称为 Source 副分片节点称为 Target。索引恢复过程的一个难点在于如何维护主副分片的一致性。 假设副分片恢复期间 一直有写操作如何实现一致呢我们先看看早期的做法在 2.0 版本之前副分片恢复要经历三个阶段 。阶段1 将主分片的 Lucene 做快照发送到 target 。期间不阻塞索引操作新增数据写到主分片的 translog 。 阶段2 将主分片 translog 做快照发送到 target 重放期间不阻塞索引操作 。阶段3 为主分片加写锁将剩余的 translog 发送到 target。 此时数据量很小写入过程的阻塞很短 。从2.0版本开始 引入 translog.view 概念的同时 阶段3被删除 。这个阶段是重放操作 operations 同时防止新的写入 Engine 。 这是不必要的因为自恢复开始标准的 index 操作会发送所有的操作到正在恢复中的分片。 重放恢复 开始时获取的 view 中的所有操作足够保证不丢失任何操作 。阶段1在主分片所在节点 获取 translog 保留锁 从获取保留锁开始会保留 translog不受其刷盘清空的影响 。然后调用 Lucene 接口把 shard 做快照快照含有 shard 中己经刷到磁盘的文件引用把这些 shard 数据复制到副本节点。在 phase1结束前 会向副分片节点发送告知对方启动 Engine 在 phase2 开始之前副分片就可以正常处理写 请求了。阶段2 对 translog 做快照这个快照里包含从 phase 开始到执行 translog 快照期间 的新增索引 。 将这些 translog 发送到副分片所在节点进行重放。[外链图片转存失败(img-0DvuW7de-1567323878798)(/Users/haizhi/Library/Application Support/typora-user-images/image-20190707182408714.png)]查看集群中所有索引恢复的状态和进度#查看集群中所有的索引恢复进度 GET _cat/recovery?v查看单个索引的恢复状态、进度#查看单个索引恢复详情 GET /haizhi1/_recovery?pretty查看索引恢复状态统计GET /_all/_stats?levelshardspretty查看索引恢复信息https://www.elastic.co/guide/en/elasticsearch/reference/current/cat-recovery.html