ES查询和监控

引言

Elasticsearch(ES)作为一个开源的分布式搜索引擎,以其高性能、可扩展性和实时分析能力赢得了广泛的应用。本文将深入探讨ES的分布式架构,帮助读者理解其背后的工作原理和实际应用。

ES基础架构概览

在这里插入图片描述

ES的分布式架构由多个核心组件构成,包括集群(Cluster),节点(Node)、索引(Index)、分片(Shard)、副本(Replica)、段(Segment)等。
集群(Cluster):一个es集群是由多个节点组成的。
节点(Node):ES集群中的一个单独服务器,可以承载多个索引。节点之间通过互相通信进行数据交换和协调工作,共同维持集群的稳定性和高可用性。
索引表(Index):类似于关系数据库中的表,是ES中存储数据的基本单位。每个索引可以包含多个分片,用于实现数据的分布式存储和查询。
分片(Shard):为了实现横向扩展和高可用性,ES将每个索引表划分成多个分片。每个分片是一个独立的Lucene索引,可以存储和处理特定量的数据。分片是数据分布和并行处理的基础。
副本(Replica):ES支持为每个分片创建多个副本,以提高数据冗余和故障恢复能力。副本可以分布在不同节点上,提升查询性能和系统可用性。
段(segment):Lucene索引中最小的独立存储单元。一个Lucene索引文件由一个或者多个段组成。在Luence中的段有不变性,也就是说段一旦生成,在其上只能有读操作,不能有写操作。频繁写入,会产生大量的小段,就像内存碎片一样,会影响长尾查询性能。因此在写入频繁时,必要时需要合并segment。

ES工作原理

ES的分布式架构使得其能够高效地处理大规模数据。以下是ES处理数据的基本流程:

写入数据:

客户端选择一个节点作为协调节点(Coordinating Node),发送写入请求。
协调节点将请求转发到包含主分片(Primary Shard)的节点。
主分片处理请求,并将数据同步到相应的副本分片(Replica Shard)。
协调节点确认所有分片写入成功后,向客户端返回响应。

查询数据:

客户端发送查询请求到任意一个节点,该节点成为协调节点。
协调节点将查询请求转发到包含相关分片的节点。
分片处理查询请求,并将结果返回给协调节点。
协调节点合并来自各分片的查询结果,并返回给客户端。

ES节点角色与扩展性

ES集群中的节点可以根据需要配置为不同的角色,以适应不同的使用场景。主要节点角色包括:
主节点(Master Node):负责管理集群的元数据,如节点信息、索引分片映射等。一个集群只能有一个活动主节点,否则会混乱,产生脑裂现象。
数据节点(Data Node):用于存储和管理数据,可进一步细分为冷、温、热等多种类型,以优化存储效率和查询性能。
协调节点:集群中的任何节点都可以充当协调节点的角色。用户的请求可以发往任何一个节点,并由该节点负责分发请求、收集结果等操作,而不需要主节点转发。这种节点可称之为协调节点,协调节点是不需要指定和配置的。

主节点和其他节点之间通过 Ping 的方式互检查,主节点负责 Ping 所有其他节点,判断是否有节点已经挂掉。其他节点也通过 Ping 的方式判断主节点是否处于可用状态。

ES的扩展性是其一大亮点。通过增加节点数量,可以轻松实现集群的横向扩展,以应对不断增长的数据量和查询需求。

ES主节点选举

主节点负责管理和协调整个集群的状态。它处理集群范围的操作,如创建或删除索引、跟踪哪些节点是集群的一部分,并决定分片的分配。当一个集群启动时,或者当前的主节点不可用时,会触发主节点选举过程。以下是Elasticsearch主节点选举的工作机制:

选举触发条件

集群启动:当一个新的集群启动时,需要选出第一个主节点。
主节点故障:如果当前的主节点由于某种原因变得不可用(例如网络分区或硬件故障),则集群中的其他节点将开始新的选举过程。

选举过程

发现阶段:
每个节点都会广播一条消息到所有已知的节点,通知它们自己认为的集群状态。
这条消息包含了该节点认为的最新集群状态信息,包括最近一次看到的主节点ID和任期(term)。
投票阶段:
如果一个节点发现当前没有活动的主节点,或者收到的消息表明有更新的集群状态,则它会发起一个新的选举。
发起选举的节点会给自己投一票,并且广播这个投票给集群中的其他节点。
其他节点接收到投票请求后,会根据自己的状态来决定是否支持这个候选节点。支持的标准通常基于节点的任期号和最新的集群状态。
获胜条件:
为了成为主节点,一个候选节点必须获得超过半数的选票。这意味着在一个N节点的集群中,至少需要floor(N/2) + 1个节点的支持。
如果一个节点获得了足够的选票,它就会被宣布为新的主节点,并向所有节点发送确认消息,告知它们新的主节点已经当选。
新的主节点还会更新其任期号,并确保所有节点都同步到了最新的集群状态。

脑裂

产生原因
(1)主节点访问故障(负载过大,资源耗尽,ping不通)
(2)网络故障,导致不可用。
集群中的一些节点访问不到master,认为master挂掉了,从而选举出新的master。导致会出现集群中存在多个活动主节点,这可能导致短暂的脑裂(split-brain)现象。
冲突解决
如果出现了脑裂,有多个主节点,怎么办?Elasticsearch通过比较候选主节点的任期号和其他因素(如节点ID)来解决这种冲突,确保只有一个节点能够成功当选为主节点。
如果两个节点具有相同的任期号,那么具有较高节点ID的节点将赢得选举。
避免脑裂
(1)一个集群部署不要跨机房
主节点和备选主节点尽量部署在同一个局域网(同一个机房内),这样网络环境更下安全可靠,信息传输效率也高;
(2)角色分离(单一职责原则,一个节点只做一件事)
master节点与data节点分离,限制角色;数据节点时需要承担存储和搜索的工作的,压力会很大。所以如果该节点同时作为候选主节点和数据节点,那么一旦选上它作为主节点了,这时主节点的工作压力将会非常大,出现脑裂现象的概率就增加了。
(3)延长ping超时设置
置主节点的响应时间,在默认情况下,主节点3秒没有响应,其他节点就认为主节点宕机了,那我们可以把该时间设置得长一点,该配置是:discovery.zen.ping_timeout:5
(4)提高主节点选举票数,这是es默认的配置。

ES实际应用场景

ES因其强大的搜索和分析能力,被广泛应用于多个领域,如:
日志分析:在ELK(Elasticsearch、Logstash、Kibana)日志分析系统中,ES负责存储和查询日志数据。
电商搜索:电商平台利用ES实现商品搜索功能,提供快速、准确的搜索体验。
数据监控:在大数据监控系统中,ES用于存储和分析监控数据,帮助用户及时发现潜在问题。

es安装

参考https://blog.youkuaiyun.com/okiwilldoit/article/details/137107087
再安装kibana,在它的控制台里写es查询语句。
在这里插入图片描述

es指南

es权威指南-中文版
kibana用户手册-中文版
es中文社区
es参考手册API
es客户端API

es查询语句

# 查询es版本
GET /

# 查询集群下所有index
GET /_cat/indices?v

# 查询节点
GET _cat/nodes?format=json

# 查询某个index的结构
GET /index_name/_mapping?pretty

#查询doc_id=123的详细信息
GET /index_name/_doc/123

# 查询作者为"猫腻"的作品,取出4个字段,100条数据,按照star_num和like_num倒排
GET /index_name/_search
{
  "query" : { 
    "match" : { 
      "authorname" : "猫腻" 
    }
  },
  "_source": ["ID","title","authorname","desc"],
  "size": 100,
  "sort": [{"star_num": {"order": "desc"}}, {"like_num":{"order": "desc"}}]
}

在语句中加入"explain":true(与size对齐),会返回计算BM25的过程分。

es bool查询

Bool查询则可以实现查询的组合,并支持多字段查询和精确匹配、模糊匹配、范围匹配等多种查询方式。下面我们来看一下Bool查询的基本语法:

{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "Search" }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2019-01-01" }}} 
      ],
      "should": [
        { "match": { "author": "John" }},
        { "match": { "author": "Doe" }}
      ],
      "must_not": [
        { "match": { "category": "Marketing" }}
      ]
    }
  }
}

must:表示必须匹配的条件,相当于AND。
filter:表示过滤条件,可以提高查询效率,相当于WHERE。
should:表示应该匹配的条件,可以有多个,相当于OR。should里的所有条件bm25分数是相加关系。
must_not:表示必须不匹配的条件,相当于NOT。
dis_max:所有条件bm25分数的最高分。

在这个查询中,必须同时匹配 title 和 content 字段,同时 status 字段必须为 published,publish_date 字段必须大于等于 2019-01-01,并且 author 字段必须匹配 John 或者 Doe 中的至少一个,同时 category 字段不能匹配 Marketing

ES新增字段

在my_index索引表里新增new_feild字段
PUT my_index/_mapping
{
 "properties": {
   "new_feild" : {
      "type" : "boolean",
      "doc_values" : false
    }
 }
}

增加预定义脚本

PUT /_scripts/my_script_staticscore
 {
     "script": {
         "lang" : "painless",
          "source": """
      double staticscore = doc['staticscore'].empty ? 0.0: doc['staticscore'].value;
      double staticscore_norm = staticscore / 60000.0;
      return (1 + staticscore_norm) * _score;
"""
     }
 }

清空索引所有数据

POST /your_index/_delete_by_query
{
  "query": {
    "match_all": {}
  }
}

新增doc

PUT myindex/_doc/16515175900086404
{
  "articleid": 10,
  "allwords" : 5000,
  "authorname" : "一只简单的猪",
  "authorid" : 3860320803982101,
  "title" : "名字很长很长很长很长很长很长很",
  "enable_visible" : [
      "10_12_30",
      "10_10_1"
    ],
    "newchaptertime" : 1722672398
}

ES更新字段

#更新单个字段
//字段名为item_name的值更新为2322332
POST index_name/_update/$id/
{
  "doc": {
    "item_name": "2322332" 
  }
}
#更新数组字段,新增值
//字段名是tags,是个多值字段
//tags更新前是["1"],更新后是["1","blue"]
POST index_name/_update/$id/
{
  "script": {
    "source": "ctx._source.tags.add(params.tag)",
    "lang": "painless",
    "params": {
      "tag": "blue"
    }
  }
}
//判断是否存在,不存在再添加
POST index_name/_update/$id/
{
  "script": {
    "source": """
      def tags = ctx._source.tags;
      def value = "-1";
      if (!tags.contains(value)) {
        tags.add(value);
      }
    """,
    "lang": "painless"
  }
}
#更新数组字段,删除值
//字段名是tags,是个多值字段
//tags更新前是["1","blue"],删除值为"blue"后,变成["1"]
POST index_name/_update/$id/
{
  "script": {
    "source": """
      for(int i = 0; i < ctx._source.tags.size(); i++) {
        if(ctx._source.tags[i] == 'blue') {
          ctx._source.tags.remove(i);
          break; 
        }
      }
    """,
    "lang": "painless"
  }
}

ES SQL

6.3版本后支持SQL,但是不支持join等复杂操作。
https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-spec.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-search-api.html

POST _sql?format=txt
{
  "query": "SELECT author, title FROM index_name WHERE MATCH(title, '猎鬼') ORDER BY updateTime DESC LIMIT 100"
}

ES监控

通过kibana可以看到es的监控信息,包括每个索引的查询耗时等。
在这里插入图片描述

ES段的概念

在 Elasticsearch 中,段是倒排索引的物理存储单元。倒排索引是一种数据结构,它将文档中的每个词(term)映射到包含该词的文档列表。当文档被索引到 Elasticsearch 中时,它们会被分解成更小的单元,这些单元就是段。
例如,当有一个包含多个文档的索引,Elasticsearch 会把这些文档划分成多个段来存储和管理。每个段都是独立的,包含了倒排索引的一部分,并且是不可变的(immutable),这意味着一旦段被创建,就不能再修改。
查看某个索引的段

GET index_name/_segments

段的生命周期和操作

创建:
当新的文档被写入 Elasticsearch 时,会触发段的创建过程。在后台,Elasticsearch 会定期(由index.refresh_interval设置控制,默认是 1 秒)或者在达到一定的文档数量或大小阈值时,将内存中的索引数据刷新(flush)到磁盘上形成新的段。
例如,当向一个索引写入大量文档后,经过刷新间隔,这些文档就会被组织成新的段存储在磁盘上。
合并(Merge):
随着时间的推移,索引中会积累许多小的段。为了提高查询性能和磁盘利用率,Elasticsearch 会自动合并这些小的段。段合并操作会读取多个小的段,将它们合并成一个更大的段,并删除原来的小的段。
例如,有多个小的段,每个段包含部分文档的倒排索引,合并后可以减少段的数量,使得查询时需要搜索的段数量减少,从而提高查询效率。同时,合并后的段可以更好地利用磁盘空间,因为它可以更紧凑地存储倒排索引。
删除:
当文档从索引中删除时,Elasticsearch 不会立即从段中删除相应的信息。而是在段合并时,会标记要删除的文档,在合并过程中真正从新的段中去除这些已删除文档的信息。

段对查询性能的影响

积极影响:
合理的段结构可以提高查询性能。因为段是倒排索引的存储单元,查询操作实际上是在段上进行的。当段的大小适中且经过优化(如通过合并)时,查询可以更快地定位到包含查询词的文档。例如,经过段合并后,查询时需要扫描的段数量减少,I/O 操作的次数也会相应减少,从而加快查询速度。
消极影响:
过多的小的段可能会导致查询性能下降。因为每个段都需要被搜索,过多的段会增加查询时的 I/O 开销和内存占用。例如,如果索引中有大量未合并的小的段,查询可能需要在许多小的段之间频繁切换,导致查询速度变慢。

如何管理段

控制刷新频率:
可以通过调整index.refresh_interval参数来控制段的创建频率。如果对数据的实时性要求不是很高,可以适当延长刷新间隔,减少小的段的产生。但是要注意,延长刷新间隔可能会导致新写入的文档在一段时间内无法被查询到。
触发合并操作:
虽然 Elasticsearch 会自动进行段合并,但在某些情况下,也可以手动触发合并操作。可以使用 Elasticsearch 的 API 来控制合并策略和触发合并。例如,在索引负载较低的时段,可以手动触发合并操作,以优化索引的性能。不过,要注意合并操作可能会消耗大量的磁盘 I/O 和 CPU 资源,所以要谨慎操作。

手动触发合并代码

集群中的所有索引进行段合并,将每个索引的段合并到尽可能少的数量,以优化索引性能和减少磁盘空间占用。
POST /_forcemerge
将 your_index_name 替换为你实际要合并段的索引名称,只会对指定的索引进行段合并操作。
POST /your_index_name/_forcemerge

查看合并进度

将 your_index_name 替换为具体的索引名称,即可查看该索引的段信息和合并进度。
GET /your_index_name/_cat/segments?v
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值