ElasticSearch7

倒排索引

数据写入时,建立关键字和主键的映射,查询时–>关键字–>主键–>对应文章

分片

因为ES是以检索为主的产物,为了便于查询,会将数据进行分片,例如:根据性别分片,当查询女的时候就只需要去女性这个分片中查询,速度更快。
在创建index的时候可以指定分片数进行设置,一旦设定,无法修改

副本

为防止数据节点宕机或者挂掉,影响服务的使用,可以在创建inde的时候指定副本数目,如果设置为1时,则相当于在集群中,会有两份相同数据存在,当原始数据丢失时,可以通过副本进行数据恢复或者响应
可以通过setting方法修改副本数量

多分片数据路由

当有写数据进来时,会根据数据主键hash(id)来计算,当前数据存储在哪个节点
当用户读取数据时,因为在每个分片中都会存在一份数据,所以集群会轮询到指定节点,但是并不是一定在当前节点做数据返回,如果当前节点的负载比较高时,会协调一个负载较低的节点处理当前请求。

多分片多副本数据写入流程
  • 客户端写入数据,随意访问集群中的节点(协调节点)
  • 协调节点创建该数据的id信息,进行hash(id),查询到对应主数据节点
  • 主数据节点进行数据保存,然后将数据发送至副本节点
  • 副本节点保存数据,反馈结果给主数据节点
  • 主数据节点反馈到客户端
  • 客户端收到写入数据反馈,写入成功

在写入时,可以通过设置consistency属性设置,是否需要副本节点反馈,其参数选项有:

  • one,只需要主节点写入成功即视为写入成功
  • all,需要所有副本节点写入成功才视为写入成功
  • quorum,大多数节点写入成功即视为写入成功,计算公式:
多分片多副本查询数据流程
  • 客户端请求数据,随意访问集群中的节点(协调节点)
  • 协调节点进行计算所在分片,并获取到所有的副本节点
  • 为了负载均衡,回轮询所有节点
  • 将请求转发到指定节点
  • 该节点进行数据返回
关键字
  • 词条:索引中最小存储和查询单元
  • 词典:字典,词条的集合,使用B+、hashMap存储
  • 倒排表:关键词出现在什么位置,和出现的频率,每条数据叫做倒排项
全文检索的大致流程

倒排查询的搜索过程:

  1. 词典中查询关键字是否存在,不存在直接返回
  2. 查询倒排表,关键词在倒排表中的指针,找到文档id的列表
  3. 找到对应的数据
  4. 进行返回
倒排索引早期的问题及好处
  1. 早期阶段,ES会为整个文档建立一个很大的倒排索引,并将其写入到磁盘,该倒排索引不会被修改,然后将其加载到内存中,因为不可边,所以不存在线程安全问题;一个大的倒排索引是允许被压缩的,这样在读到内存中,可以大量减少磁盘IO
  2. 问题:倒排索引是不允许被修改的,当更新频率较高时,就需要创建新的索引文件,重新建立倒排表,效率会降低,性能也会急剧下降
动态更新索引

如何在不变性的前提下,实现倒排索引的更新?

  • 引入段的概念,通过新增段,来减少修改情况下建立整个索引表的问题
删除

在我们删除的时候,由于索引段不会被修改,所以我们在查询的时候还是会查询到被删除的文档。删除的过程是将要删除的文档使用.del标识,查询到结果后发现该文档被.del所标识,则将该文档从查询结果中剔除(逻辑删除)

合并倒排索引

当索引段数量过多时,会将索引段进行合并,在合并的过程中,会将删除的文档从磁盘中彻底删除(物理删除),可以通过refresh_interval来设置段合并的频率,单位是秒

真正的写入流程
  1. 客户端执行写入请求
  2. 协调节点找到主分片节点,和其他副本节点
  3. 将文件写入主分片节点,并在主分片的内存中建立索引生成index数据
  4. 将index数据封装成一个segment数据对象,并将操作写入translog中
  5. 根据设置的refresh_interval(默认1s)属性所指定的频率,将segment数据对象、translog刷新至OSCache中
  6. 根据flush(默认30m)属性所设定的值,将OSCache中的segment数据对象和translog文件flush到磁盘中
  7. 当磁盘中的segment文件越来越多时,会将segment文件进行合并
文本分析器
  1. 分词器
  2. 字符过滤器,在建立索引文件时,将文本进行转换
  3. token过滤器,按照特定的要求、特定的格式进行转化,比如转换大小写、删除指定字符
ES性能优化

由于elasticSearch是重度使用磁盘的

  • 硬件方面
    • 使用SSD(固态硬盘)
    • 使用RID0,其本质就是,将数据存储到多快磁盘中,当有请求进来时,就可以多快磁盘并行处理
    • 使用多快硬盘,可以通过配置path.data进行配置
    • 尽可能的避免使用远程挂载
  • 合理的设置分片策略
    • 每一个分片可以视为一个搜索引擎,意味着内存、文件句柄消耗严重
    • 如果每一个分片都分配到不同节点还好,如果一个节点中包含多个分片,则面临资源竞争
    • 计算词条相关度是根据每个分片来的,如果分片多的话,会导致相关度计算存在误差
    • 总的分片数一般不要超过节点数的3倍,例如3个分片+2个副本为3+(3*2)=9
    • 节点数<=主分片数*(副本数-1)
  • 推迟分片分配
    • 默认情况下当节点宕机后,集群会重新分配分片,就需要大量的资源消耗,可以设置节点重新上线的时间,比如节点宕机后五分钟未上线才会重新分配分片
  • 使用路由参数
    • 不带路由(routing)参数,协调节点无法计算数据所属分片,只能将请求分发至所有节点,返回经过后进行聚合
    • 带路由参数(routing),协调节点计算出所属分片,将查询结果返回
  • 写入优化
    • 加大translog flush,目的是为了降低Iops、write block
    • 增加index Refresh,目的是减少segment merge 频率
    • 调整bulk线程池和队列
    • 优化节点间的任务分配
    • 尽量批量数据提交
      • 数据尽量不要超过100m
  • 段合并
    • 在后台定期进行段合并
  • 减少副本的数量
    • 可以在写入阶段,将副本数量设置为0,在数据写入完成后,再修改副本数量写入副本
  • 调整ES的JVM
elasticsearch集群的master是如何选举的?
  • ES中选举主要模块是ZenDiscovery模块负责的,主要包括Ping和Unicast
    • ping 节点直接通过这个RPC来进行彼此通信
    • unicast单播模块维护一个主机列表,来判断哪些主机需要ping通
  • 对所有可成为master(配置文件中node.master=true)的节点进行排序(通过nodeId),每次选举的时候都把当前节点所知道的master进行排序,选出排为第一个的节点,当该节点收到的票数为一半以上,并且该节点的投票是自己,则当前节点为master,若未达到一半以上,则重复以上步骤
  • master的指责是集群、节点、索引的管理,不负责文档级别的管理,数据是有data节点进行管理的
有哪些情况可能出现脑裂问题
  • 由于网络问题,集群之间的网络延迟,从节点无法访问到master,导致从节点重新选举出新的master
  • 节点负载,当节点既是数据节点又是主节点时,访问量较大时,可能出现响应延迟,从节点无法及时访问到master,并认为master节点挂点了,选举出新的master
  • 内存回收,当主节点也是数据几点时,进程占用较大,发生GC时,会出现响应延迟,从节点无法及时访问,从新选举出新的主几点
如何避免脑裂问题
  • 减少误判,discovery.zen.ping_timeout的默认超时时间是3s,可以将该时间设置的大一点,减少误判的概率
  • 增加触发选举节点的数量,官方推荐(n/2)+1,当有一半以上的节点都认为主节点挂了,才会进行选举
  • 角色分离,将主节点和数据节点分离,避免出现负载或者GC所导致的响应延迟
ElasticSearch 是如何保证读写一致的
  • 可以使用版本号,使用乐观锁,确保新版本的数据不会被旧版本的数据覆盖掉
  • 在写操作的过程中,一致性级别包括quorume/one/all,可以使用高级别的写入策略来保证数据的一致性
    • quorume 为默认配置,表示当大多数的节点写入成功即认为成功
    • one 当有一个节点写入成功则认为写入成功
    • all 表示需要所有的节点都需要写入成功
  • 对于读操作时,可以使用replication为sync,表示主副分片都返回,来保证数据为最新的

ElasticSearch8

  • 新版本采用JDK17 ,并默认包含,也提供了兼容jdk8的版本
  • ES8中废除了type的概念
  • ES8中默认开启安全认证的
  • 提供了同步和异步API
  • 提供了EQL(事件查询语句 )
  • 在ES6.3以后就支持了SQL操作,Kibana中我们使用的是DSL
  • ES提供了实用lambda的相关API
cursor(游标)

当我们使用sql进行查询时,假如总共有3天数据,但是我们的查询语句只需要返回2条数据,则剩下的这条数据就会进入cursor中,在后续查询中,可以直接使用cursor进行查询,只可以取用一次,多次使用时,结果是返回空,游标是消耗性能的,可以使用close进行关闭
![image.png](https://img-blog.csdnimg.cn/img_convert/5a01ca4ebad05c8ff2d3221dc27205d5.png#clientId=u24d706fe-2394-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=470&id=u7de01b5c&margin=[object Object]&name=image.png&originHeight=940&originWidth=2862&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1307933&status=done&style=none&taskId=u62092005-a052-4450-afb1-93b0b874c3a&title=&width=1431)

权重
  • ES中查询到的结果是按照score进行排序的,可进行设置权重查询自己想要的那条数据
  • 可以使用explan查询权重计算详情
NLP自然语言处理
  • 下载openNLP
  • 下载NLP预处理模型包,输入对应的语句,可进行预处理的分析
性能优化
  • 页缓存
    • 操作系统级别的缓存
    • ES是实用java语言编写的,java无法直接操作OS的文件,所以OS将文件缓存到内存中
    • 一般情况下我们在设置ES程序时,ES的内存要小于操作系统的一半,这样就有更大的内存进行缓存文件
  • 分片集请求缓存(节点请求缓存)
    • 在查询的时候指定request_cache=true ,会将我们的查询结果缓存至该节点的 内存中
    • 默认是不开启缓存
  • 查询缓存
    • 将某一些功能进行缓存,缓存的管理更为精细,相比较于分片集请求缓存,该缓存可以在不同的查询中重复使用
  • 减少内存堆
    • 如果将ES的内存堆设置的特别大时,我们的内存中会存储大量的索引数据
    • 由于ES会将一些查询缓存存入系统内存中,则当ES的内存越大,系统可用内存就会变小
    • 官方推荐堆内存不要超过系统内存的一半,并且不要超过30G
  • 数据分层
    • 热数据,将热点数据存储至性能较好的节点中
    • 温数据,有些数据访问频率没有那么高时,将其放至容量较大的节点,速度一般的节点
    • 冷数据快照,部分历史数据如果访问频率特别低时,可以将数据迁移至外部存储系统,并做快照处理
      • 在7.1.2后续版本,ES可以直接查询对快照数据进行查询,不用拉取过来再查询了
Logo

华为云1024程序员节送福利,参与活动赢单人4000元礼包,更有热门技术干货免费学习

更多推荐