elasticsearch-原理篇

分布式特性及分布式搜索的机制

谈谈Elasticsearch集群的分布式架构

首先说说什么是分布式架构:分布式架构的特点是集群的能力是容易水平扩张的,这个能力包括了数据存储能力,和请求的处理能力,以及保障了整个服务的高可用性。而es集群就具备这样的特点:
* 易扩展:为集群加入新的节点可以提升集群的数据存储能力,和请求处理能力
* 高可用:集群中的某个几点宕机,其他的节点可以替代他的角色。比如说,master节点宕机,master eligible节点会通过选举机制,重新选出一个master节点。一个data节点宕机,因为其他节点存放了宕机节点的数据副本,所以数据的增删改是不受影响的。
其实,需要了解集群架构中不同节点的角色类型以及作用:
节点的本质:java进程,一台机器上可以运行多个es进程,但是生产上建议一台机器运行一个es节点

节点名称作用
master 节点处理创建,删除索引等请求,决定分片被分配到哪个节点上 ,修改mapping,setting相关配置
master eligible 节点master节点宕机时可被选举成为主节点,每个es节点默认都是eligible master,集群中的第一个master eligible启动时,它会被选举成为master
data 节点负责数据存储;执行查询语句并将查询结果返回给coordinating节点,查询过程非常消耗硬件资源,通过扩展数据节点可以水平扩展数据,解决数据单点(性能,故障)问题
coordinating 节点提供路由的能力,例如创建所用的请求需要路由到master节点,查询请求需要路由到data节点 ,所有节点默认都是coordinating节点,不可更改
Ingest NodeIngest节点处理时机——在数据被索引之前,通过预定义好的处理管道对数据进行预处理。默认情况下,所有节点都启用Ingest,因此任何节点都可以处理Ingest任务

当然我也会很好奇节点之间是如和找到对方进行沟通的?
解决这个问题的方式就是维护集群信息
每个节点都保存了集群信息,但是只有master节点才能修改集群信息,摒弃修改后负责将信息同步给其他节点
这些信息包括:
* 所有的节点信息
* 所有的索引和相关的setting,mapping信息
* 分片路由信息

master eligible节点的选主过程

  • 互相 Ping 对⽅方,Node Id 低的会成为被选举的节点
  • 其他节点会加⼊入集群,但是不不承担 Master 节点的⻆角⾊色。⼀一旦发现被选中的主节点丢失, 就会选举出新的 Master 节点

es集群的脑裂问题

什么是脑裂问题:集群发生了网络分区后,无master节点的分区选举出了一个新的master节点。当网络分区恢复后,集群中存在两个master节点的现象。
在es7.0版本前,可以通过设置discovery.zen.minimum_master_nodes参数解决,只有集群中的节点数大于这个参数,才能执行选举。比如,当 3 个 master eligible 时,设置 discovery.zen.minimum_master_nodes 为 2,即可避免脑裂。
在es7.0后,不需自己去设置这个参数了,集群可以通过zen2 自动调节所需的最小节点数。

一个数据data Node宕机后,其他节点上的数据副本会重新生成primary分片吗?

master节点单点问题,如果master节点宕机了,集群会怎样?

分⽚片与集群的故障转移

故障转移的大致过程

  • 某个节点宕机,节点上的主分片数据P0和副本分片R1数据丢失
  • 其他节点上的副本分片升级为主分片
  • 重新生成缺失的副本分片,并宠幸分配到节点上
    在这里插入图片描述

默认的主分片和副本分片数

7.0版本后,默认的主分片数是1,副本分片数是0.
副本分片一定需要和主分片在不同的节点上

⽂文档分布式存储

简单的理解可以是一份索引,它含有很多文档,这些文档分散在不同的分片上,每个分片又分布在不同的机器上。
文档到分片的映射算法

  • 轮询,这样的算法使得分片上节点的数据量十分均匀,但有可能导致查询时访问的分片数过多
  • 文档到分片的路由,可以指定路由值,路由值相同的数据路由到不相同的分片上,查询同一路由值的数据时,查询一个分片就可以了。算法:shard = hash(_routing) % number_of_primary_shards
  • 创建索引后,primary的数量是不可以随意改动的,因为如果使用的映射算法是路由的话,primary_shard的数量变化,导致路由算法变化,新增时算得的分片值和查询时算得的路由值不一样,最终导致查询不到数据。如果要改primary的数据,需要reindex才行。

分⽚片及其⽣生命周期

es的中的分片和lucene中的index是什么关系

  • es中的shard就是lucene中的index
  • lucene中的index其实是由多个segment组成的
  • segment是什么,segment里面存放的是文档数据。当执行refresh操作时,index buffer中的idnex document会被写入到lucene的segment中。

es中的刷新操作指令汇总

  • refresh:将index buffer写入segment的过程。默认一秒执行一次,可以通过index.refresh_interval参数修改频率。refresh后,数据就可以被搜索到了。index buffer被占满时,也会触发refre操作,默认是JVM的10%;调用refresh后数据会被清空。
  • flush:这是个非常长的操作过程,包含这下面几个步骤:
    * 调用refresh:数据写入segment,index buffer清空
    * 调用fsync,将segment中的数据写入磁盘
    * 清空transaction Log
    * 默认30分钟调用一次
    * Transaction Log 满 (默认 512 MB),也会调用
  • merge:
    作用:将多个segment文件合并成一个,较少segment的数量;删除.del文件(删除已经删除的文档)
    触发:es和lucene会自动进行merge操作;也有支持手动merge的API
    POST my_index/_forcemerge

什么是commit point

  • commit point:记录了所有的segments信息
  • .del: 删除的文档信息保存在.del文件中

什么是transaction log?

transaction log 的作用就是为了防止,文档在未落盘前,es机器宕机导致数据丢失的情况。
数据在写入index buffer的同时,数据会被写入到transacion log。

在这里插入图片描述

剖析分布式查询及相关性算分

分布式搜索的运行机制
分成两个阶段:第一阶段query,第二阶段fetch
query阶段
用户发出query请求 -> 收到请求的节点以coordinating的身份将请求转发data Node -> 被选中的分片执行查询,进行排序。然后每个分片都会返回from+size个排序后的文档id和排序值给coordinating节点。
在这里插入图片描述
fetch阶段
coordinating node 节点会将query阶段从每个分片获取到的文档id进行重新排序,获取从from到from+size个文档id。以muiti get请求的方式,到相应的分片获取详细的文档数据。
潜在问题

  • 深度分页问题:深度分页时,协调节点需要处理的数据会比较多,影响查询性能。
  • 相关性算分问题:文档的打分在分片之间是相互独立的,不同的分片的数据量不一致打分就会不太准确,特别是数据量少的时候。解决方案:一是数据量少的时候,索引设置成一个分片即可。二是使⽤DFS Query Then Fetch(到每个分⽚片把各分⽚片的词频和⽂文档频率进⾏行行搜集,然后完整的进⾏行行⼀一次相关性算分, 耗费更更加多的 CPU 和内存,执⾏行行性能低下,⼀一般不不建议使⽤用)

谈谈es中的排序场景

实战

## sort关键字是和query一个层级的,没有指定_score排序,所以不会计算评分
POST kibana_sample_data_ecommerce/_search
{
  "size": 20,
  "sort": [
    {
      "order_date": {
        "order": "desc"
      }
    }
  ],
  "query": {
    "match_all": {}
  }
}
## 可以通过指定score,使得在评分相同的时候按照评分进行排序
POST kibana_sample_data_ecommerce/_search
{
  "size": 20,
  "sort": [
    {
      "order_date": {
        "order": "desc"
      }
    },
    {"_score":{"order": "desc"}}
  ],
  "query": {
    "match_all": {}
  }
}

## 如果对text类型的字段进行排序,会报错。因为排序会使用fielddata,而text类型的fielddata字段默认是disabled。需要手动改变索引的mapping, 将fielddata设置为true,才能正常使用。fielddata只是用于text类型的。
POST kibana_sample_data_ecommerce/_search
{
  "size": 20,
  "sort": [
    {
      "customer_full_name": {
        "order": "desc"
      }
    },
    {"_score":{"order": "desc"}}
  ],
  "query": {
    "match_all": {}
  }
}

PUT kibana_sample_data_ecommerce/_mapping
{
  "properties": {
    "customer_full_name" : {
          "type" : "text",
          "fielddata": true,
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
  }
}

排序过程
* 针对原始字段进行,倒排序无法发挥作用
* 需要使用正排索引,通过文档id和字段快速获取原始内容
* 实现方式有2种,fielddata -> text, doc values-> 列式存储,非text类型字段

doc value 对比 fielddata
在这里插入图片描述
fielddata应用介绍

  • 默认关闭,可以通过 Mapping 设置打开。修改 设置后,即时⽣生效,⽆无需重建索引
  • 其他字段类型不不⽀支持,只⽀支持对 Text 进⾏行行设定
  • 打开后,可以对 Text 字段进⾏行行排序。但是是对 分词后的 term 排序,所以,结果往往⽆无法满⾜足 预期,不不建议使⽤用
  • 部分情况下打开,满⾜足⼀一些聚合分析的特定需求
  • 参考文章:https://www.elastic.co/guide/cn/elasticsearch/guide/current/_limiting_memory_usage.html

Doc Values 应用介绍

  • 默认启⽤用,可以通过 Mapping 设置关闭
  • 关闭后,增加索引的速度 / 减少磁盘空间
  • 如果重新打开/关闭,需要重建索引
  • 什么时候需要关闭:明确不不需要做排序及聚合分析
  • 可以正常支持搜索和结果字段展示

使用docvalue_fields, 可以查询text字段分词后的结果

PUT test_keyword
PUT test_keyword/_mapping
{
  "properties": {
    "user_name":{
      "type": "text",
      "fielddata":true
    }
  }
}

PUT test_keyword/_doc/1
{
  "user_name":"郎思明"
}

POST test_keyword/_search
{
  "docvalue_fields": [
    "user_name"
    ]
    
  , "query": {
   "match": {
     "user_name": "林零"
   }
  }
}

es对于并发问题的处理是如何的

es是使用乐观锁进行并发控制的。
es中的文档是不可变更的。你更新一个文档,es会将原文档标记为删除,然后增加一个全新的文档,并且version字段增加1。
内部版本控制:if_seq_no + if_primary_term
外部版本:version + version_type(external)
什么是内部版本是是外部版本?这两种控制版本并发的方式有什么区别?
6.7版本以后,不允许使用内部版本的并发控制,就是指使用version的这种写法。
primary_term和seq_no的说明
对于if_primary_term记录的就是具体的哪个主分片,而if_seq_no这个参数起的作用和旧版本中的_version是一样的,之所以加上if_primary_term这个参数主要是提高并发的性能以及更自然,因为每个document都只会在某一个主分片中,所以由所在主分片分配序列号比由之前通过一个参数_version,相当于由整个ES集群分配版本号要来的更好。
https://www.elastic.co/guide/en/elasticsearch/reference/6.7/optimistic-concurrency-control.html

version_type的含义
通过自己设置一个外部值来判断当前记录的新旧状态,比如你想要version<=5的才进行更新,否则返回失败
?version=5&version_type=external
version_type=external代表你要用外部的值进行判断
version=你的判断值

segment merge的过程是怎样的呢?

考虑点:

  • 尽可能合并较小的segment,足够大的segment可以不参与合并 -》需要确定可以参与合并的segment的最大长度
  • 每次合并的segment的数量需要限制,不能一次合并太多的segment -> 需要确定一次合并最大可以处理的segment的数量
  • 大小相近的segment应该被分到一组进行合并,具体是出于什么原因考虑,目前还不知。
    参考文章:https://zhuanlan.zhihu.com/p/65075215

杂文

深入理解 Lucene 的 flush 过程
https://mp.weixin.qq.com/s/wI3E2ZLncHNCd_-T3tBFPw

扒一扒查询缓存的裤子
https://mp.weixin.qq.com/s/q5iN2rOwkb0Bw1MXowZ6LQ

Elasticsearch 中增加分片数量,聚合一定会变快吗?
https://mp.weixin.qq.com/s/MJlgoQFFlfvUFygwZyJuAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值