ES集群配置

这篇具有很好参考价值的文章主要介绍了ES集群配置。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、高并发下如何保证读写一致

1.1 写操作

        对于写操作,一致性级别支持 quorum/one/all,默认为 quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,副本将会在一个不同的节点上重建。

one:写操作只要有一个primary shard是active活跃可用的,就可以执行
all:写操作必须所有的primary shard和replica shard都是活跃可用的,才可以执行
quorum:默认值,要求ES中大部分的shard是活跃可用的,才可以执行写操作

1.2 读操作

        对于读操作,可以设置 replication 为 sync(默认),这使得在写入操作时,在主分片和副本分片都完成后才会返回;如果设置replication 为 async 时,也可以通过设置搜索请求参数 _preference 为 primary 来查询主分片,确保文档是最新版本。

1.3 更新操作 通过版本号使用乐观锁并发控制

        每个文档都有一个_version 版本号,这个版本号在文档被改变时加一。Elasticsearch使用这个 _version 保证所有修改都被正确排序,当一个旧版本出现在新版本之后,它会被简单的忽略。

利用_version的这一优点确保数据不会因为修改冲突而丢失,比如指定文档的version来做更改,如果那个版本号不是现在的,我们的请求就失败了。

二、ES数据写入流程


2.1、ES写数据的整体流程:

ES集群配置

(1)客户端选择 ES 的某个 node 发送请求过去,这个 node 就是协调节点 coordinating node
(2)coordinating node 对 document 进行路由,将请求转发给对应的 node(有 primary shard)
(3)实际的 node 上的 primary shard 处理请求,然后将数据同步到 replica node 
(4)coordinating node 等到 primary node 和所有 replica node 都执行成功之后,最后返回响应结果给客户端。


2.2、ES主分片写数据的详细流程:

ES集群配置

(1)主分片先将数据写入ES的 memory buffer,然后定时(默认1s)将 memory buffer 中的数据写入一个新的 segment 文件中,并进入操作系统缓存 Filesystem cache(同时清空 memory buffer),这个过程就叫做 refresh;每个 segment 文件实际上是一些倒排索引的集合, 只有经历了 refresh 操作之后,这些数据才能变成可检索的。

每个 segment 是一个包含正排(空间占比90~95%)+ 倒排(空间占比5~10%)的完整索引文件,每次搜索请求会将所有 segment 中的倒排索引部分加载到内存,进行查询和打分,然后将命中的文档号拿到正排中召回完整数据记录。如果不对segment做配置,就会导致查询性能下降

ES 的近实时性:数据存在 memory buffer 时是搜索不到的,只有数据被 refresh 到  Filesystem cache 之后才能被搜索到,而 refresh 是每秒一次, 所以称 es 是近实时的;可以手动调用 es 的 api 触发一次 refresh 操作,让数据马上可以被搜索到;

commit point: 记录当前所有可用的 segment ,每个 commit point 都会维护一个 .del 文件( es 删除数据本质是不属于物理删除),当 es 做删改操作时首先会在 .del 文件中声明某个 document 已经被删除,文件内记录了在某个 segment 内某个文档已经被删除,当查询请求过来时在 segment 中被删除的文件是能够查出来的,但是当返回结果时会根据 commit point 维护的那个 .del 文件把已经删除的文档过滤掉; 

(2)由于 memory Buffer 和 Filesystem Cache 都是基于内存,假设服务器宕机,那么数据就会丢失,所以 ES 通过 translog 日志文件来保证数据的可靠性,在数据写入 memory buffer 的同时,将数据也写入 translog 日志文件中,当机器宕机重启时,es 会自动读取 translog 日志文件中的数据,恢复到 memory buffer 和 Filesystem cache 中去。

ES 数据丢失的问题:translog 也是先写入 Filesystem cache,然后默认每隔 5 秒刷一次到磁盘中,所以默认情况下,可能有 5 秒的数据会仅仅停留在 memory buffer 或者 translog 文件的 Filesystem cache中,而不在磁盘上,如果此时机器宕机,会丢失 5 秒钟的数据。也可以将 translog 设置成每次写操作必须是直接 fsync 到磁盘,但是性能会差很多。

(3)flush 操作:不断重复上面的步骤,translog 会变得越来越大,不过 translog 文件默认每30分钟或者 阈值超过 512M 时,就会触发 commit 操作,即 flush操作,将 memory buffer 中所有的数据写入新的 segment 文件中, 并将内存中所有的 segment 文件全部落盘,最后清空 translog 事务日志。

① 将 memory buffer 中的数据 refresh 到 Filesystem Cache 中去,清空 buffer;
② 创建一个新的 commit point(提交点),同时强行将 Filesystem Cache 中目前所有的数据都 fsync 到磁盘文件中;
③ 删除旧的 translog 日志文件并创建一个新的 translog 日志文件,此时 commit 操作完成

三、ES的搜索流程

搜索被执行成一个两阶段过程,即 Query Then Fetch:

3.1、Query阶段:

        客户端发送请求到 coordinate node,协调节点将搜索请求广播到所有的 primary shard 或 replica,每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。接着每个分片返回各自优先队列中 所有 docId 和 打分值 给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。

3.2、Fetch阶段:

        协调节点根据 Query阶段产生的结果,去各个节点上查询 docId 实际的 document 内容,最后由协调节点返回结果给客户端。

coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin 随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。
接收请求的 node 返回 document 给 coordinate node 。
coordinate node 返回 document 给客户端。

        Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分片的数据,这样在文档数量较少的时候可能不够准确,DFS Query Then Fetch 增加了一个预查询的处理,询问 Term 和 Document frequency,这个评分更准确,但是性能会变差。 

四、ES查询原理

4.1 lucene查询过程

 每个 document 的 name value 经过分词形成多个 term,多个 term 组成 term dictionary,如下显示基于 name 创建倒排链如下:

ES集群配置

在这里,Alice、Alan 都是 term。所以倒排本质上就是基于 term 的反向列表,方便通过属性反向查找 doc_id。
  到这里我们有个很自然的问题,如何快速拿到这个倒排表呢?在 lucene 里面就引入了 term dictonary 的概念,也就是 term 的字典。term 字典里我们可以按照 term 进行排序,那么用一个二分查找就可以找到这个 term 所对应的倒排表信息,这样的复杂度是 logN。
  但在 term 很多,内存放不下的时候,效率还是需要进一步提升。 为解决这个问题,lucene 引用 term dict index 来存放 term 的共享前缀,后缀则放在 term dictonary 中。

term dict index:是采用 FST 数据结构,存放在内存中。term dict index 查到对应的 term dict 的 block 位置之后,再去磁盘上找 term,大大减少了磁盘的 random access 次数
Term dict:在磁盘上是以分 block 的方式保存的,一个 block 内部利用公共前缀压缩,比如都是 Ab 开头的单词就可以把 Ab 省去
SkipList: 是以 docId 建立的数据结构
  如果所有的 term 都是英文字符的话,可能这个 term index 就真的是 26 个英文字符表构成的了。但是实际的情况是,term 未必都是英文字符,term 可以是任意的 byte 数组。

ES集群配置

在 term dict index 中需要保存的是 Term 的前面部分字段,以及与 Term Dictionary 之间的映射关系,这使得存储的信息量减少。再结合 FST(Finite State Transducer)压缩技术,term dict index 可以被压缩到足够小,以至于可以被缓存进服务器内存中,而 Term 后缀则存放在 trem dict。
  

4.2 整个检索过程如下:

内存加载 term dict index(tip文件),通过 FST 匹配前缀找到后缀词块位置。
根据词块位置,读取磁盘中 Term dict(tim 文件),匹配后缀,读取倒排表信息。
根据倒排表位置去 doc文件 中加载文档数据。
  找到了倒排表,怎么通过 docId 找到我们需要的文档呢?

ES集群配置

 在图 1 中,为了便于介绍,我们处理的是文档号 0~3455 的 3456 篇文档,我们另skipInterval 为 128,即每处理 128 篇文档生成一个 PackedBlock,对应一个 datum;另 skipMultiplier 为 3(源码中默认值为 8),即每生成 3 个 datum 就在上一层生成一个新的索引,新的索引也是一个 datum,它是 3 个 datum 中的最后一个,并且增加了一个索引值 SkipChildLevelPointer 来实现映射关系(见索引文件的生成(三)),每一层的数值为 PackedBlock 中的最后一篇文档的文档号,例如 level=2 的三个数值 1151、2303、3455。 

 4.3倒排合并(水平分桶和bitmap)

  到这里还有另一个问题,那就是当我们查询中出现了 name=‘Alan’ and name=‘Alice’ limit 0,20 该如何处理?

  它会拆分为 term = ‘Alan’ 和 term = 'Alice’的查询。分别得到每个term的倒排链(docId列表),再对多个倒排表做交集。那么倒排表怎么做交集呢?

水平分桶,多线程并行

有序集合1{1,3,5,7,8,9, 10,30,50,70,80,90}和有序集合2{2,3,4,5,6,7, 20,30,40,50,60,70},先进行分桶拆分【桶1的范围为[1, 9]、桶2的范围为[10, 100]、桶3的范围为[101, max_int]】,于是拆分成集合1【a={1,3,5,7,8,9}、b={10,30,50,70,80,90}、c={}】和集合2【d={2,3,4,5,6,7}、e={20,30,40,50,60,70}、e={}】,利用多线程对桶1(a和d)、桶2(b和e)、桶3(c和e)分别求交集,最后求并集。

bitmap,大大提高运算并行度,时间复杂度O(n)

假设set1{1,3,5,7,8,9}和set2{2,3,4,5,6,7}的所有元素都在桶值[1, 16]的范围之内,可以用16个bit来描述这两个集合,原集合中的元素x,在这个16bitmap中的第x个bit为1,此时两个bitmap求交集,只需要将两个bitmap进行“与”操作,结果集bitmap的3,5,7位是1,表明原集合的交集为{3,5,7}

水平分桶(每个桶内的数据一定处于一个范围之内),使用bitmap来表示集合,能极大提高求交集的效率,但时间复杂度仍旧是O(n),但bitmap需要大量连续空间,占用内存较大。文章来源地址https://www.toymoban.com/news/detail-425725.html

到了这里,关于ES集群配置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从kafka如何保证数据一致性看通常数据一致性设计

    在数据库系统中有个概念叫事务,事务的作用是为了保证数据的一致性,意思是要么数据成功,要么数据失败,不存在数据操作了一半的情况,这就是数据的一致性。在很多系统或者组件中,很多场景都需要保证数据的一致性,有的是高度的一致性。特别是在交易系统等这样

    2024年02月19日
    浏览(37)
  • MySQL是如何保证数据一致性的?

    通过上文《MySQL是如何保证数据不丢失的?》可以了解DML的操作流程以及数据的持久化机制。对于一个数据库而言,除了数据的持久性、不丢失之外,一致性也是非常重要的,不然这个数据是没有任何意义的。在使用MySQL时,数据不一致的情况也可能出现,所以,本文就来看看

    2024年02月03日
    浏览(45)
  • 使用双异步后,如何保证数据一致性?

    大家好,我是哪吒。 在上一篇文章中,我们 通过双异步的方式导入了10万行的Excel ,有个小伙伴在评论区问我, 如何保证插入后数据的一致性呢? 很简单,通过对比Excel文件行数和入库数量是否相等即可。 那么,如何获取异步线程的返回值呢? 我们可以通过给异步方法添加

    2024年01月23日
    浏览(49)
  • ZooKeeper是如何保证数据一致性的?

             目录 一、分布式一致性原理 二、ZooKeeper架构         2.1 ZAB 协议操作顺序性         2.2 领导者选举         成员身份         成员状态         领导者选举 三、总结         在分布式系统里的多台服务器要对数据状态达成一致,其实是一件很有难度和挑

    2024年04月11日
    浏览(36)
  • 聊聊 Kafka:Kafka 如何保证一致性

    在如今的分布式环境时代,任何一款中间件产品,大多都有一套机制去保证一致性的,Kafka 作为一个商业级消息中间件,消息一致性的重要性可想而知,那 Kafka 如何保证一致性的呢?本文从高水位更新机制、副本同步机制以及 Leader Epoch 几个方面去介绍 Kafka 是如何保证一致性

    2024年02月02日
    浏览(26)
  • 如何保证缓存和 MySQL 的双写一致 ?

            什么叫做如何保证缓存和 MySQL 双写一致,这个问题就是指当应用程序执行写(增删改)操作时,如何保证 Redis 和 MySQL 的数据一致性。 当用户发送请求时,程序的执行流程如下: 要保证 Redis 和 MySQL 的数据一致性,从大的角度来说,无非就两种思路: 1.修改 先修

    2024年02月11日
    浏览(31)
  • 106、Redis和Mysql如何保证数据一致

    先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不一致 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中,这种方案能解决1方案的问题,但是在高并发下性能较低,而且仍然会出现数据不一致的问题,比如线程1删除了Redis缓存数据,正在更新

    2024年02月15日
    浏览(28)
  • 如何保证数据库、缓存的双写一致?

    在我们日常研发过程中,由于数据库的一些限制,我们经常使用缓存(如:Redis)来提升访问速率。此时,数据库和缓存双写数据就存在一致性问题,这个问题跟开发语言无关,在高并发场景下,问题更加严重。 另外,在面试、工作中也会经常遇到这个问题。所以这里跟大家

    2024年04月12日
    浏览(33)
  • MySQL和Redis如何保证数据一致性

    MySQL与Redis都是常用的数据存储和缓存系统。为了提高应用程序的性能和可伸缩性,很多应用程序将MySQL和Redis一起使用,其中MySQL作为主要的持久存储,而Redis作为主要的缓存。在这种情况下,应用程序需要确保MySQL和Redis中的数据是同步的,以确保数据的一致性。 “数据一致

    2024年02月12日
    浏览(45)
  • MySQL和Redis如何保证数据一致性?

    由于缓存的高并发和高性能已经在各种项目中被广泛使用,在读取缓存这方面基本都是一致的,大概都是按照下图的流程进行操作: 但是在更新缓存方面,是更新完数据库再更新缓存还是直接删除缓存呢?又或者是先删除缓存再更新数据库?在这一点上就值得探讨了。 在实

    2024年02月01日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包