• 作者:老汪软件技巧
  • 发表时间:2024-09-15 00:02
  • 浏览量:

1 介绍

Elasticsearch是一个基于Apache Lucene的开源分布式搜索和分析引擎,旨在实现云计算时代的实时搜索、稳定、可靠、快速、安装使用方便。它通常用于处理海量的文本数据,提供强大的全文搜索、结构化搜索、分析和组合功能。

2 架构

ES 基于 Lucene构建,每个索引(Index)的分片(Shard)对应一个 Lucene 实例。为了深入理解 ES 的底层原理,先了解一下 Lucene 的结构是很有帮助的。

Lucene 的数据存储由 段(Segment) 构成,段是 Lucene 中存储和管理数据的最小单位。每个段都有如下核心结构:

倒排索引

由 词典(Term Dictionary) 和 倒排列表(Posting List) 组成。倒排索引是搜索引擎的核心组件,通过将词条(Term)与包含该词的文档ID关联,实现快速搜索与查询匹配。文档存储(Document Store)

用于存储原始文档数据,采用行存储方式保存每个文档的完整内容。这样在执行需要获取原始数据的查询时,能够快速返回存储的文档。doc_values

是一种专门为某一列数据设计的存储结构,采用列式存储方式。这种列式存储加速了排序、聚合等需要对特定字段进行处理的查询操作。

Lucene 通过这种结构设计,使其在面对海量数据时,既能高效处理全文搜索,又能在聚合和排序操作中保持高性能。

虽然 Lucene 作为全文检索引擎库已经非常强大,但在面对大规模分布式场景和复杂的集群管理需求时,单靠 Lucene 仍然有一定局限性。因此,基于 Lucene 构建的分布式搜索引擎 Elasticsearch(简称 ES)应运而生。Elasticsearch 不仅继承了 Lucene 的强大搜索能力,还通过其分布式架构、实时搜索与分析的特性,成为处理大规模数据集和构建企业级搜索解决方案的首选工具。

3 ES基础概念

ES为我们屏蔽了Lucene底层的复杂结构,统一对资源进行统一抽象,让我们不用关心Lucene的细节,并提供了分布式扩展的功能。

Node 节点是Elasticsearch集群中的单个实例,通常运行在一台物理服务器或虚拟机上。每个节点都有一个唯一的名称,节点负责存储数据、处理查询请求以及参与集群的管理。

Index 很多人说Index对应数据库的表,虽然两者并不是同一类产品并不具有可比性,但是我还是坚持Index对应数据库的表,Index中存储特定的一类Document(数据),大部分情况数据库的表会同步至es的Index,和表的功能更为接近。

Document 文档是Elasticsearch中的基本信息单元,相当于关系型数据库中的行。每个文档由若干字段(键值对)组成,以JSON格式存储。

4 角色分化

参考:…

es的节点可以分为三类 master node 、 data node 、 Coordinating node可以通过node.roles配置来指定

master,指定了master角色并不代表他就是master节点,而是代表他有资格成为master节点,最终还是需要看集群选主来判定谁是master,建议设置三个及以上防止集群中没有master的候选节点的情况。

Coordinating 协调节点主要负责对接client端,分发、聚合 数据节点的数据(一个index的数据存在多个分片可能存在多个node中),所有节点默认都是协调节点,不能显示关闭,如果需要把一个节点单独列为协调节点,直接设置node.roles为空即可。

data 数据节点保存数据并执行与数据相关的操作,例如 CRUD、搜索和聚合。他也有很多子角色(data data_content data_hot data_warm data_cold data_frozen等)

5 写入流程集群写入客户端请求 协调节点协调节点 使用文档的ID经过hash算法计算出分片号主分片写入数据,并将写入操作分发给所有对应的副本分片副本分片确认,主分片确认,协调节点返回确认分片写入写入内存缓冲区(此时数据不可见,触发refresh操作才能读取到数据)如果index.translog.durability配置为async,则不等待事务日志写入,直接返回写入成功,如果为request,则需要确保事务日志的写入,防止数据丢失。写入内存缓冲区的后续操作通过refresh_interval配置的时间(默认1s),将内存缓冲区的数据生成一个独立的segment,加入到Lucene中段合并,随着时间的推移,es会自动合并段落盘,段数据一直存在内存中,虽然有translog确保数据的可靠性,但是一旦服务宕机,大量translog会导致恢复缓慢,大量translog也会增加存储压力写入优化client段

使用bulk,内部使用streaming_bulk,自动分片、批量发送给es服务端

from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
Elasticsearch(hosts, verify_certs=False, max_retries=5, retry_on_status=(502, 503, 504), 
                    request_timeout=30,basic_auth, PASSWORD))
success, failed = bulk(es, result, index="standard-hco", raise_on_error=True)

性能服务器演示视频__性能服务器

server端增加flush时间,每一次flush都会产生一个segment,虽然会定期segment合并,但是大量段会产生性能损耗。如果此时进行大批量的插入,甚至可以先关闭刷新(也可以设置一个较大值),但是这样会导致es数据不可见,且会占用大量内存,需要注意插入完之后要把配置复原(1s)index.translog.durability 暂时设置为 async,默认情况下,Elasticsearch 会在每次写入请求完成后将事务日志同步到磁盘(request 模式),允许事务日志异步写入,从而减少 fsync 的频率,提升写入速度,但是日志异步如果服务宕机会出现数据丢失的情况。暂时调整副本数量,在大规模写入期间,可以通过将副本(replica)数量设置为 0 来提高写入性能,因为副本分片的同步会增加写入开销。写入完成后,再将副本数量恢复到所需的冗余级别。

PUT /your_index/_settings
{
  "index": {
    "refresh_interval": "-1", // 禁用刷新
    "translog.durability": "async",
    "number_of_replicas": 0
  }
}

6 查询流程集群查询

主要分为两个阶段,在scatter阶段,协调节点将请求转发给保存数据的数据节点。每个数据节点分片在本地执行请求并将其结果返回给协调节点。在gather阶段,协调节点将每个数据节点的结果缩减为单个全局结果集。

分片查询1. 接收查询请求

用户通过 REST API 或客户端向 ES 发送查询请求。查询可以是简单的关键词搜索,也可以是复杂的布尔查询、短语查询或聚合查询等。

2. 查询解析

ES 首先会解析用户的查询请求,并根据查询类型,确定要检索的索引和字段。查询语法被转换成内部的查询结构,ES 会根据用户的查询需求决定如何执行。

3. 分词和分析(Analyzer)

在执行查询之前,ES 会对查询中涉及的文本进行分词。具体步骤如下:

4. 倒排索引查找

在分词后,ES 使用倒排索引来查找与查询词匹配的文档。倒排索引是由词条到文档 ID 的映射,它能够快速定位包含某个词条的文档列表。每个文档根据其相关的字段被提前索引并存储在倒排索引中。

5. 文档匹配与评分6. 结果聚合与排序7. 返回查询结果

ES 将最终的查询结果(包括文档列表、相关性评分、聚合数据等)打包成 JSON 格式的响应并返回给客户端。用户可以根据需要处理和显示这些结果。

查询优化增加 refresh_interval,减少段的产生使用_source控制返回字段,只返回必要字段深度分页问题,使用Scroll Search、search_after等解决方案合理设计表结构,对于不需要模糊查询的字段优先使用keyword类型需要排序、分组、聚合的字段,可以添加doc_values(会添加一个列式存储结构,加速聚合、排序等操作)过滤数据使用 filter 代替 query 来跳过部分数据的评分计算,同时filter也会尽可能击中内存的查询缓存分词器

添加分词器(IK,pinyin等)扩展,提高中文和拼音的查询效果(默认分词器一个中文产生一个分词)

{
    "settings": {
        "analysis": {
            "analyzer": {
                "my_analyzer": { // 定义分词器名词
                    "tokenizer": "ik_max_word", // 使用ik的ik_max_word分词器
                    "filter": [ "number_to_chinese_synonym","py"] // 添加分词后置过滤器
                }
            },
            "filter": {
                "py": {
                    "type": "pinyin", 
                    "keep_full_pinyin": false,  // 不保留完整的拼音单词
                    "keep_first_letter": false,  // 不保留拼音的首字母
                    "keep_joined_full_pinyin": true, //保留拼接的完整拼音(如 "zhongguo" 表示 "中国")
                    "keep_original": true, // 保留原始中文文本。
                    "limit_first_letter_length": 16, // 限制拼音首字母的长度(如果保留的话)。
                    "remove_duplicated_term": true, // 移除重复的词项,避免重复数据干扰检索。
                    "none_chinese_pinyin_tokenize": false //非中文字符不进行拼音分词。
                },
                "number_to_chinese_synonym": {
                    "type": "synonym", // 同义词过滤器
                    "synonyms": [ "9,九","8,八","7,七","6,六","5,五","4,四","3,三","2,二","1,一","0,零"]
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "text_name": {
                "analyzer": "my_analyzer",  // 指定分词器
                "type": "text"
            }
        }
    }
}

7 运维相关单节点docker部署

docker network create elastic
sudo sysctl -w vm.max_map_count=262144
docker run --name elasticsearch  --net baize_network\
  -p 9200:9200 \
  -e "bootstrap.memory_lock=true" \
  -m 20GB \
  --log-driver=json-file --log-opt max-size=200m --log-opt max-file=5  \
  --ulimit memlock=-1:-1 \
  --restart unless-stopped \
  -v $(pwd)/plugins:/usr/share/elasticsearch/plugins \
  -v $(pwd)/data:/usr/share/elasticsearch/data \
  -v $(pwd)/logs:/usr/share/elasticsearch/logs \
 -it docker.elastic.co/elasticsearch/elasticsearch:8.13.4
#重置密码
docker exec -it elasticsearch /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic
#生成kibana token(也可使用elasticsearch容器启动时控制台输出的token)
docker exec -it elasticsearch  /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana
docker run --name kibana \
           --net baize_network \
          --log-driver=json-file --log-opt max-size=200m --log-opt max-file=5  \
           -p 5601:5601 \
           -m 2g \
           --restart unless-stopped \
           docker.elastic.co/kibana/kibana:8.13.4

机器推荐配置cpu 推荐4核以上,越多越好物理内存 推荐 32GB-64GB,非堆内存主要用于缓存文件句柄、缓存 Lucene 段、索引、系统缓存等。JVM内存最佳配置16GB - 31GB,堆内存设置为物理内存的 50% 左右,绝对不要超过32g(32g之后,JVM无法使用压缩指针,增大内存使用,降低性能)插件安装

由于网络问题,也可以手动下载插件到plugins目录下,解压后使用

RUN elasticsearch-plugin install  --batch https://get.infini.cloud/elasticsearch/analysis-ik/8.12.2
RUN elasticsearch-plugin install  --batch https://get.infini.cloud/elasticsearch/analysis-pinyin/8.12.2

8 问题ES是否会发生脑裂

不会,脑裂主要指出现多个master节点。es选主类似于raft算法选举master节点,只有当超过一半的投票节点(通常是拥有 master 角色的节点)同意后,才能选出一个新的主节点。这种严苛的选举规则,复杂的网络分区问题或配置不当才可能发生脑裂

未完待续。。。


上一条查看详情 +深入解析循环神经网络(RNN)
下一条 查看详情 +没有了