目录

ElasticSearch原理与实践

什么是ElasticSearch

ElasticSearch是一款非常强大的、基于Lucene的开源搜索及分析引擎;它是一个实时的分布式搜索分析引擎,它能让你以前所未有的速度和规模,去探索你的数据

它被用作全文检索、结构化搜索、分析以及这三个功能的组合

除了搜索,结合Kibana、Logstash、Beats开源产品,Elastic Stack(简称ELK)还被广泛运用在大数据近实时分析领域,包括:日志分析、指标监控、信息安全等。它可以帮助你探索海量结构化、非结构化数据,按需创建可视化报表,对监控数据设置报警阈值,通过使用机器学习,自动识别异常状况。

ElasticSearch是基于Restful WebApi,使用Java语言开发的搜索引擎库类,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。其客户端在Java、C#、PHP、Python等许多语言中都是可用的。

ElasticSearch的主要功能及应用场景

  • 主要功能: 1)海量数据的分布式存储以及集群管理,达到了服务与数据的高可用以及水平扩展; 2)近实时搜索,性能卓越。对结构化、全文、地理位置等类型数据的处理; 3)海量数据的近实时分析(聚合功能)
  • 应用场景: 1)网站搜索、垂直搜索、代码搜索; 2)日志管理与分析、安全指标监控、应用性能监控、Web抓取舆情分析

ElasticSearch的基础概念

  • Near Realtime(NRT) 近实时。数据提交索引后,立马就可以搜索到。
  • Cluster 集群,一个集群由一个唯一的名字标识,默认为“elasticsearch”。集群名称非常重要,具有相同集群名的节点才会组成一个集群。集群名称可以在配置文件中指定。
  • Node 节点:存储集群的数据,参与集群的索引和搜索功能。像集群有名字,节点也有自己的名称,默认在启动时会以一个随机的UUID的前七个字符作为节点的名字,你可以为其指定任意的名字。通过集群名在网络中发现同伴组成集群。一个节点也可是集群。
  • Index 索引: 一个索引是一个文档的集合(等同于solr中的集合)。每个索引有唯一的名字,通过这个名字来操作它。一个集群中可以有任意多个索引。
  • Type 类型:指在一个索引中,可以索引不同类型的文档,如用户数据、博客数据。从6.0.0 版本起已废弃,一个索引中只存放一类数据。
  • Document 文档:被索引的一条数据,索引的基本信息单元,以JSON格式来表示。
  • Shard 分片:在创建一个索引时可以指定分成多少个分片来存储。每个分片本身也是一个功能完善且独立的“索引”,可以被放置在集群的任意节点上。
  • Replication 备份: 一个分片可以有多个备份(副本)

ElasticSearch 原理

ElasticSearch 架构说明

https://tc.ctq6.cn/tc/20220607112545.png

  • 一个 ES Index 在集群模式下,有多个 Node (节点)组成。每个节点就是 ES 的Instance (实例)。
  • 每个节点上会有多个 shard (分片), P1 P2 是主分片, R1 R2 是副本分片
  • 每个分片上对应着就是一个 Lucene Index(底层索引文件)
  • Lucene Index 是一个统称
    • 由多个 Segment (段文件,就是倒排索引)组成。每个段文件存储着就是 Doc 文档。
    • commit point记录了所有 segments 的信息

Lucene索引结构

https://tc.ctq6.cn/tc/20220610124029.png

https://tc.ctq6.cn/tc/20220610124423.png

文件的关系如下:

https://tc.ctq6.cn/tc/20220610130948.png

Lucene处理流程

https://tc.ctq6.cn/tc/20220610133906.png

创建索引的过程:

  • 准备待索引的原文档,数据来源可能是文件、数据库或网络
  • 对文档的内容进行分词组件处理,形成一系列的Term
  • 索引组件对文档和Term处理,形成字典和倒排表

搜索索引的过程:

  • 对查询语句进行分词处理,形成一系列Term
  • 根据倒排索引表查找出包含Term的文档,并进行合并形成符合结果的文档集
  • 比对查询语句与各个文档相关性得分,并按照得分高低返回

ElasticSearch分析器

分析 包含下面的过程:

  • 首先,将一块文本分成适合于倒排索引的独立的词条
  • 之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall 分析器执行上面的工作。

分析器 实际上是将三个功能封装到了一个包里:

  • 字符过滤器 首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将 & 转化成 and。
  • 分词器 其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
  • Token 过滤器 最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 a, and, the 等无用词),或者增加词条(例如,像 jump 和 leap 这种同义词)。

Elasticsearch提供了开箱即用的字符过滤器、分词器和token 过滤器。 这些可以组合起来形成自定义的分析器以用于不同的目的

内置分析器

Elasticsearch还附带了可以直接使用的预包装的分析器。接下来我们会列出最重要的分析器。为了证明它们的差异,我们看看每个分析器会从下面的字符串得到哪些词条:

1
"Set the shape to semi-transparent by calling set_trans(5)"

ElasticSearch内置分词器:

  • Standard Analyzer - 默认分词器,按词切分,小写处理
  • Simple Analyzer - 按照非字母切分(符号被过滤), 小写处理
  • Stop Analyzer - 小写处理,停用词过滤(the,a,is)
  • Whitespace Analyzer - 按照空格切分,不转小写
  • Keyword Analyzer - 不分词,直接将输入当作输出
  • Patter Analyzer - 正则表达式,默认\W+(非字符分割)
  • Language - 提供了30多种常见语言的分词器
  • Customer Analyzer 自定义分词器

1、标准分析器 标准分析器是Elasticsearch默认使用的分析器。它是分析各种语言文本最常用的选择。

1
2
3
4
5
POST _analyze
{
  "analyzer": "standard",
  "text":     "Set the shape to semi-transparent by calling set_trans(5)"
}

它根据 Unicode 联盟 定义的 单词边界 划分文本。删除绝大部分标点。最后,将词条小写。它会产生

1
set, the, shape, to, semi, transparent, by, calling, set_trans, 5

2、简单分析器

1
2
3
4
5
POST _analyze
{
  "analyzer": "simple",
  "text":     "Set the shape to semi-transparent by calling set_trans(5)"
}

简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生

1
set, the, shape, to, semi, transparent, by, calling, set, trans

3、空格分析器

1
2
3
4
5
POST _analyze
{
  "analyzer": "whitespace",
  "text":     "Set the shape to semi-transparent by calling set_trans(5)"
}

空格分析器在空格的地方划分文本。它会产生

1
Set, the, shape, to, semi-transparent, by, calling, set_trans(5)

4、语言分析器 特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如, 英语 分析器附带了一组英语无用词(常用单词,例如 and 或者 the ,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干

1
2
3
4
5
POST _analyze
{
  "analyzer": "language",
  "text":     "Set the shape to semi-transparent by calling set_trans(5)"
}

英语 分词器会产生下面的词条:

1
set, shape, semi, transpar, call, set_tran, 5

什么时候使用分析器

当我们 索引 一个文档,它的全文域被分析成词条以用来创建倒排索引。 但是,当我们在全文域 搜索 的时候,我们需要将查询字符串通过 相同的分析过程 ,以保证我们搜索的词条格式与索引中的词条格式一致。

全文查询,理解每个域是如何定义的,因此它们可以做正确的事:

  • 当你查询一个 全文 域时, 会对查询字符串应用相同的分析器,以产生正确的搜索词条列表。
  • 当你查询一个 精确值 域时,不会分析查询字符串,而是搜索你指定的精确值

查询文档流程详解

单个文档

以下是从主分片或者副本分片检索文档的步骤顺序: https://tc.ctq6.cn/tc/20220610172744.png

  • 客户端向 Node 1 发送获取请求。
  • 节点使用文档的 _id 来确定文档属于分片 0 。分片 0 的副本分片存在于所有的三个节点上。 在这种情况下,它将请求转发到 Node 2 。
  • Node 2 将文档返回给 Node 1 ,然后将文档返回给客户端。 在处理读取请求时,协调结点在每次请求的时候都会通过轮询所有的副本分片来达到负载均衡。

在文档被检索时,已经被索引的文档可能已经存在于主分片上但是还没有复制到副本分片。

在这种情况下,副本分片可能会报告文档不存在,但是主分片可能成功返回文档。 一旦索引请求成功返回给用户,文档在主分片和副本分片都是可用的

多个文档

使用 mget 取回多个文档的步骤顺序:

https://tc.ctq6.cn/tc/20220610172952.png

以下是使用单个 mget 请求取回多个文档所需的步骤顺序:

  • 客户端向 Node 1 发送 mget 请求。
  • Node 1 为每个分片构建多文档获取请求,然后并行转发这些请求到托管在每个所需的主分片或者副本分片的节点上。一旦收到所有答复, Node 1 构建响应并将其返回给客户端。

文档读取过程详解

https://tc.ctq6.cn/tc/20220610173440.png

  • 在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。 ==在搜索的时候是会查询Filesystem Cache的,但是有部分数据还在Memory Buffer,所以搜索是近实时的。==
  • 每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。
  • 接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并丰富文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。

写入文档流程详解

ElasticSearch和Kibana 安装

安装ElasticSezrch

1、平台确认 这里我准备了一台Centos7虚拟机, 为方便选择后续安装的版本,所以需要看下系统版本信息。

1
2
[root@localhost ~]# uname -a
Linux localhost.localdomain 3.10.0-1127.el7.x86_64 #1 SMP Tue Mar 31 23:36:51 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

2、安装java环境 安装 Elasticsearch 之前,你需要先安装一个较新的版本的 Java,最好的选择是,你可以从 www.java.com (opens new window) 获得官方提供的最新版本的 Java。本次使用openjdk,安装以后,确认是否安装成功:

1
2
3
4
5
[root@localhost ~]# yum install -y java-1.8.0-openjdk.x86_64
[root@localhost ~]# java -version
openjdk version "1.8.0_332"
OpenJDK Runtime Environment (build 1.8.0_332-b09)
OpenJDK 64-Bit Server VM (build 25.332-b09, mixed mode)

3、下载ElasticSearch

1
curl -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.2.2-linux-x86_64.tar.gz

4、解压ElasticSearch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[root@localhost ~]# tar zxf elasticsearch-8.2.2-linux-x86_64.tar.gz -C /usr/local/
[root@localhost ~]# ll /usr/local/
总用量 0
drwxr-xr-x. 2 root root  28 5月   5 11:42 bin
drwxr-xr-x  9 root root 155 5月  25 23:53 elasticsearch-8.2.2
drwxr-xr-x. 2 root root   6 4月  11 2018 etc
drwxr-xr-x. 2 root root   6 4月  11 2018 games
drwxr-xr-x. 2 root root   6 4月  11 2018 include
drwxr-xr-x. 2 root root   6 4月  11 2018 lib
drwxr-xr-x. 2 root root   6 4月  11 2018 lib64
drwxr-xr-x. 2 root root   6 4月  11 2018 libexec
drwxr-xr-x. 2 root root   6 4月  11 2018 sbin
drwxr-xr-x. 5 root root  49 5月   5 11:05 share
drwxr-xr-x. 2 root root   6 4月  11 2018 src

5、增加ElasticSearch用户 必须创建一个非root用户来运行ElasticSearch(ElasticSearch5及以上版本,基于安全考虑,强制规定不能以root身份运行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 增加ElasticSearch用户
[root@localhost ~]# useradd elasticsearch
[root@localhost ~]# passwd elasticsearch
更改用户 elasticsearch 的密码 。
新的 密码:
无效的密码: 密码未通过字典检查 - 过于简单化/系统化
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
# 修改目录权限至新增的elasticsearch用户
[root@localhost ~]# chown -R elasticsearch /usr/local/elasticsearch-8.2.2
# 增加data和log存放区,并赋予elasticsearch用户权限
[root@localhost ~]# mkdir -p /data/es
[root@localhost ~]# chown -R elasticsearch /data/es
[root@localhost ~]# mkdir -p /var/log/es
[root@localhost ~]# chown -R elasticsearch /var/log/es

然后修改上述的data和log路径,关闭安全验证 vim /usr/local/elasticsearch-8.2.2/config/elasticsearch.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[root@localhost ~]# vim /usr/local/elasticsearch-8.2.2/config/elasticsearch.yml
# ----------------------------------- Paths ------------------------------------
#
# Path to directory where to store the data (separate multiple locations by comma):
#
path.data: /data/es
#
# Path to log files:
#
path.logs: /var/log/es

# Enable security features
xpack.security.enabled: false

6、修改Linux系统的限制配置

  • 修改系统中允许应用最多创建多少文件等的限制权限。Linux默认来说,一般限制应用最多创建的文件是65535个。但是ES至少需要65536的文件创建权限。
  • 修改系统中允许用户启动的进程开启多少个线程。默认的Linux限制root用户开启的进程可以开启任意数量的线程,其他用户开启的进程可以开启1024个线程。必须修改限制数为4096+。因为ES至少需要4096的线程池预备。ES在5.x版本之后,强制要求在linux中不能使用root用户启动ES进程。所以必须使用其他用户启动ES进程才可以。
  • Linux低版本内核为线程分配的内存是128K。4.x版本的内核分配的内存更大。如果虚拟机的内存是1G,最多只能开启3000+个线程数。至少为虚拟机分配1.5G以上的内存
1
2
3
4
5
6
7
[root@localhost ~]# cat >> /etc/security/limits.conf << EOF
# es limit
elasticsearch soft nofile 65536
elasticsearch hard nofile 65536
elasticsearch soft nproc 4096
elasticsearch hard nproc 4096
EOF

7、启动es

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 配置自动启动
[root@localhost ~]# cat > /usr/lib/systemd/system/elasticsearch.service << EOF
[Unit]
Description=elasticsearch
After=network.target

[Service]
Type=simple
User=elasticsearch
LimitNOFILE=100000
LimitNPROC=100000
Restart=no
ExecStart=/usr/local/elasticsearch-8.2.2/bin/elasticsearch
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF
[root@localhost ~]# systemctl enable elasticsearch
Created symlink from /etc/systemd/system/multi-user.target.wants/elasticsearch.service to /usr/lib/systemd/system/elasticsearch.service.
# 启动es
[root@localhost ~]# systemctl start elasticsearch

8、查看es是否启动成功

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@localhost ~]#  netstat -ntlp | grep 9200
tcp6       0      0 :::9200                 :::*                    LISTEN      22558/java
[root@localhost ~]# curl -v 127.0.0.1:9200
* About to connect() to 127.0.0.1 port 9200 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 9200 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:9200
> Accept: */*
> 
< HTTP/1.1 200 OK
< X-elastic-product: Elasticsearch
< content-type: application/json
< content-length: 544
< 
{
  "name" : "localhost.localdomain",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "34WvcK4CRaK-20R-xmdsHA",
  "version" : {
    "number" : "8.2.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "9876968ef3c745186b94fdabd4483e01499224ef",
    "build_date" : "2022-05-25T15:47:06.259735307Z",
    "build_snapshot" : false,
    "lucene_version" : "9.1.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}
* Connection #0 to host 127.0.0.1 left intact

安装Kibana

1、下载kibana

1
[root@localhost ~]# curl -O https://artifacts.elastic.co/downloads/kibana/kibana-8.2.2-linux-x86_64.tar.gz

2、解压kibana

1
[root@localhost ~]# tar zxf kibana-8.2.2-linux-x86_64.tar.gz -C /usr/local/

3、使用elasticsearch用户权限

1
2
3
4
[root@localhost ~]# chown -R elasticsearch /usr/local/kibana-8.2.2
# 配置kibana远程访问
[root@localhost ~]# vim /usr/local/kibana-8.2.2/config/kibana.yml
server.host: 0.0.0.0

4、启动kibana

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 配置自动启动
[root@localhost ~]# cat > /usr/lib/systemd/system/kibana.service << EOF
[Unit]
Description=kibana
After=network.target

[Service]
Type=simple
User=elasticsearch
Restart=no
ExecStart=/usr/local/kibana-8.2.2/bin/kibana
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF
[root@localhost ~]# systemctl enable kibana
Created symlink from /etc/systemd/system/multi-user.target.wants/kibana.service to /usr/lib/systemd/system/kibana.service.
# 启动es
[root@localhost ~]# systemctl start kibana

5、界面访问 https://tc.ctq6.cn/tc/20220609125916.png

https://tc.ctq6.cn/tc/20220608160840.png

配置密码访问

  • 停止kibana和elasticsearch服务
  • 将xpack.security.enabled设置添加到ES_PATH_CONF/elasticsearch.yml文件并将值设置为true
  • 启动elasticsearch (./bin/elasticsearch -d)
  • 执行如下密码设置器,./bin/elasticsearch-setup-passwords interactive来设置各个组件的密码
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    [root@localhost ~]# /usr/local/elasticsearch-8.2.2/bin/elasticsearch-setup-passwords interactive
    ******************************************************************************
    Note: The 'elasticsearch-setup-passwords' tool has been deprecated. This       command will be removed in a future release.
    ******************************************************************************
    
    Initiating the setup of passwords for reserved users elastic,apm_system,kibana,kibana_system,logstash_system,beats_system,remote_monitoring_user.
    You will be prompted to enter passwords as the process progresses.
    Please confirm that you would like to continue [y/N]y
    
    
    Enter password for [elastic]: 
    Reenter password for [elastic]: 
    Enter password for [apm_system]: 
    Reenter password for [apm_system]: 
    Enter password for [kibana_system]: 
    Reenter password for [kibana_system]: 
    Enter password for [logstash_system]: 
    Reenter password for [logstash_system]: 
    Enter password for [beats_system]: 
    Reenter password for [beats_system]: 
    Enter password for [remote_monitoring_user]: 
    Reenter password for [remote_monitoring_user]: 
    Changed password for user [apm_system]
    Changed password for user [kibana_system]
    Changed password for user [kibana]
    Changed password for user [logstash_system]
    Changed password for user [beats_system]
    Changed password for user [remote_monitoring_user]
    Changed password for user [elastic]
    
  • 将elasticsearch.username设置添加到KIB_PATH_CONF/kibana.yml 文件并将值设置给elastic用户: elasticsearch.username: “kibana_system”
  • 创建kibana keystore, ./bin/kibana-keystore create
  • 在kibana keystore 中添加密码 ./bin/kibana-keystore add elasticsearch.password
    1
    2
    
    [root@localhost ~]# /usr/local/kibana-8.2.2/bin/kibana-keystore add elasticsearch.password
    Enter value for elasticsearch.password: *******
    
  • 重启kibana 服务即可 nohup ./bin/kibana &

然后就可以使用密码登录了:

https://tc.ctq6.cn/tc/20220608171710.png