上篇我们介绍了kafka。这篇我们到介绍elastic search(以下简称es),也是按照原理到集群搭建的顺序。
es是什么
es是一个分布式的、开源的搜索分析引擎。输入关键字,获取到想要的关键字相关的信息,这就是搜索。还有非结构化数据的分析处理。ok,两句话说明白了,es就是用来干搜索干分析这些事的,就像我们的百度,Google这些搜索引擎,我们输入关键字,他就出来一堆含有我们输入关键字并且相关度较高的结果,这就是搜索。那比如我们的系统日志收集,然后分析业务流量呀,这是分析。那接下来我们看一下它是怎么干的,为什么它适合这些事。
当然现在ChatGPT出来了是不是意味着我们传统的搜索引擎就要被毕业了呢,毕竟ai能直接回答我的问题,又不需要我自己在结果里面找答案是吧。但是,好像也不一定哈,毕竟ai也不一定对嘛,ai的判断力也不一定有我们人类高嘛。还有一些非结构化数据处理比如日志收集呀,大数据等业务也是需要一个中间件处理的嘛。那这些就不扯了,我们继续看我们的es。
es原理
上面提到es是干搜索的,那它为什么适合做搜索呢?那就必须提到一个词,叫全文检索。
- 什么是全文检索?从非结构化数据中提取出分词,然后重新组织分词信息,这个重新组织的信息叫索引。先建立索引,再对索引进行搜索的过程,就叫全文检索。
- 那什么是分词?“i love you”这句话,将这句话根据一定规则提取出来一个一个词,就是分词。“i”、“love”、“you”这三个词就是提取出来的词。
从全文检索的概念中,提到了非结构化数据,那相对肯定是有结构化数据的是吧。那什么是非结构化数据呢。那就从我们数据库中的表说起比较容易理解,因为表,字段,这种有行有列而且数据格式、数据长度都是固定的,是结构化数据。
那相反,非结构化数据就是没有固定行列,字段不统一,数据结构不规则不完整,没有预定义的数据模型。就是非结构化数据。
不像结构化,我要搜索某某字段,那我就光搜索那个字段的值就好了。那遇到非结构化数据,数据库表这种方式肯定是不合适的,所以我们的es就上场了。
提到了es的原理,就要提到Lucene这个东西了,Lucene是apache的一个子项目,是一个开放源代码的全文检索引擎工具包,但是它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,还有部分的文本分析引擎。es就是基于Lucene弄出来的一个封装了许多Lucene底层功能,提供了分布式的服务的搜索与数据分析引擎。
在Lucene中,对文档的检索是基于倒排索引实现的。
倒排索引
什么是倒排索引,我们举个例子:
document -> to -> words
通过一篇篇文章,找到文章中的单词,这叫「正向索引」,
word -> to -> document
输入一个单词,找到含有这个单词或者和这个单词有关系的文章,这叫「反向索引」,也称之为倒排索引。
那实际使用,是怎么用的呢,再举一个例子。
id | 句子 |
---|---|
1 | i am the king of the world |
2 | I am not an emotional type |
3 | king kong |
那如果用单词作为索引,而句子的id作为被索引的元素,那么索引就反过来了
id | 单词索引 |
---|---|
i | {1,2} |
am | {1,2} |
the | {1} |
king | {1,3} |
of | {1} |
world | {1} |
not | {2} |
an | {2} |
emotional | {2} |
type | {2} |
kong | {3} |
ok,那如果这个时候,我们的搜索关键字是i am king,那根据上面的表格,那即是取出{1,2}、{1,2}、{1,3}这三个单词索引出来,然后取个交集,就得到了id是1的句子。
那这个时候可能就会有疑问了,那这样,不是会耗费很大量的空间吗?那答案是,是的。当然在空间方面也会有压缩之类的处理。这里就先不展开说了。
为什么要使用倒排索引
那假设我们在搜索栏上搜索,apple,那假设用正向索引,那就需要扫描所有文档,然后每一个文档都找一下有没有apple这个单词,然后经过一定机制排序返回。可是文档的数目简直是天文数字,这样的做法是不可能短时间返回给用户的。所以搜索引擎会将正向索引重新构建为倒排索引,通过关键字得到文档id,再把文档返回给用户。
以上是es的原理的一个简单的介绍,那如果想在业务上使用,集群那肯定是必不可少的了,我们先介绍一下es的集群是怎样的一个东西,主备之间是怎么做信息交互的。
es集群原理
在说集群原理前先把相关的概念名词介绍一下
- cluster 代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是通过选举产生的,主从节点是对于内部来说的。es是无中心节点的,从外部来看es集群,在逻辑上是一个整体。意思就是对于外部来说,你与任何一个节点的通讯,都相当于与整个es集群通讯。
- shards 代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建之前指定,并且索引创建之后不允许修改。
- replicas 代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
- recovery 代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。
集群原理
每个索引会被分成多个shards储存,默认创建索引是分配5个主分片进行储存。每个分片会分在多个不同的节点上进行部署。并且分别为其创建1个副本分片。也就是说,每个索引都由5个主分片组成,而每个主分片都会有对应的一个copy。主分片和副分片都能处理查询请求,它们唯一的却别在于只有主分片才能处理索引请求。
用户可以在任何时候添加或删除副本。这句话有什么作用呢。意思就是,主分片的数目,决定着索引能保存的最大数据量,副分片是主分片的拷贝。那么,当插入大量数据的时候,那么对es集群造成了一定的压力,所以在插入大量数据之前,也就是建立索引的时候,我们最好把副分片数设置为0,等建立完索引后,再手动将副本数加大,这样可以提高数据的索引效率。
下图是2个节点的集群对于1个索引默认创建了5个分片的情况
当客户端发起创建document的时候,es需要确定这一个document放在这一个index的哪一个shard上,这个过程叫数据路由。
路由算法:shard=hash(rounting)%number_of_primary_shards
假设文档id是1,主分片是5,那就是1%5
另外,每一个节点不会拥有全部的主分片数据,但是节点的主分片+副分片=完整的索引数据。图中节点1是1、2、3主4、5副;节点2是1、2、3副,4、5主。这样的一个分配情况。
es集群搭建
接下来我们进行集群的搭建,我们依然是用server02、server03、server04这三台机器。
然后第一步先去dns服务器配置好我们的es域名解析,
es01.com.cn、es02.com.cn、es03.com.cn
然后去配置系统设置,分别是
/etc/security/limits.conf
/etc/sysctl.conf
这两个文件
limits.conf:
#<type> can have the two values:
# - "soft" for enforcing the soft limits
# - "hard" for enforcing hard limits
#
* soft nofile 65535
* hard nofile 65535
sysctl.conf:
vm.max_map_count=655360
两个文件都是追加些代码,原本是没有的。
然后依然是先创建好我们的文件夹elastic-search-cluster
创建我们的docker-compose.yaml
server02:
version: '3'
services:
es-cluster-node:
image: elasticsearch:7.17.5
container_name: es-cluster-node
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- network.bind_host=0.0.0.0
- network.host=es01.com.cn
- network.publish_host=es01.com.cn
- http.port=9200
- transport.tcp.port=9300
- transport.host=es01.com.cn
- transport.bind_host=0.0.0.0
- transport.publish_host=es01.com.cn
- http.cors.enabled=true
- http.cors.allow-origin=*
- node.master=true
- node.data=true
- discovery.seed_hosts=es02.com.cn,es03.com.cn
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.security.transport.ssl.keystore.path=certs/elastic-stack-ca.p12
- xpack.security.transport.ssl.truststore.path=certs/elastic-stack-ca.p12
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/data:/usr/share/elasticsearch/data
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/certs:/usr/share/elasticsearch/config/certs
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/elasticsearch.keystore:/usr/share/elasticsearch/config/elasticsearch.keystore
ports:
- 9200:9200
- 9300:9300
server03:
version: '3'
services:
es-cluster-node:
image: elasticsearch:7.17.5
container_name: es-cluster-node
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- network.bind_host=0.0.0.0
- network.host=es02.com.cn
- network.publish_host=es02.com.cn
- http.port=9200
- transport.tcp.port=9300
- transport.host=es02.com.cn
- transport.bind_host=0.0.0.0
- transport.publish_host=es02.com.cn
- http.cors.enabled=true
- http.cors.allow-origin=*
- node.master=true
- node.data=true
- discovery.seed_hosts=es01.com.cn,es03.com.cn
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.security.transport.ssl.keystore.path=certs/elastic-stack-ca.p12
- xpack.security.transport.ssl.truststore.path=certs/elastic-stack-ca.p12
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/data:/usr/share/elasticsearch/data
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/certs:/usr/share/elasticsearch/config/certs
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/elasticsearch.keystore:/usr/share/elasticsearch/config/elasticsearch.keystore
ports:
- 9200:9200
- 9300:9300
server04:
version: '3'
services:
es-cluster-node:
image: elasticsearch:7.17.5
container_name: es-cluster-node
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- network.bind_host=0.0.0.0
- network.host=es03.com.cn
- network.publish_host=es03.com.cn
- http.port=9200
- transport.tcp.port=9300
- transport.host=es03.com.cn
- transport.bind_host=0.0.0.0
- transport.publish_host=es03.com.cn
- http.cors.enabled=true
- http.cors.allow-origin=*
- node.master=true
- node.data=true
- discovery.seed_hosts=es01.com.cn,es02.com.cn
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.security.transport.ssl.keystore.path=certs/elastic-stack-ca.p12
- xpack.security.transport.ssl.truststore.path=certs/elastic-stack-ca.p12
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/data:/usr/share/elasticsearch/data
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/certs:/usr/share/elasticsearch/config/certs
- /data/deploy/xdeas-docker/elastic-search-cluster/volumes/elasticsearch.keystore:/usr/share/elasticsearch/config/elasticsearch.keystore
ports:
- 9200:9200
- 9300:9300
这里有个点要注意,细心的朋友会看见我这边的ssl.verification_mode=certificate这个设置,我这边开启了ssl的还有一个账号密码的校验,因此对应下面的cert和elasticsearch.keystore的挂载我也写上了。如果不想开ssl校验,只需要把ssl那几个配置注释掉,就可以了。
下一个问题来了,我目前这个文件夹里面,根本没有这个文件的呀,那这里启动不会报错吗?答案是,会报错的,所以我们在启动集群之前,要先生成这一个账号密码的key文件。这里教一下大家怎么生成这个东西,需要借助单例elasticsearch生成。也就是说,我们需要先随便找一个服务器,启动一个单例的elasticsearch,不用什么特别配置,因为我们只是借助它去生成我们的keystore而已。
那我们直接跑一个docker命令去启动一个单例就行。我们选server02来启一个单例的,用完就删掉。建一个单例的文件夹
把启动单例需要的文件和文件夹都放在里面
data和plugins文件夹都给777权限,775启动好像会报错,各位也可以试一试。然后 elasticsearch.yml也没什么写的
elasticsearch.yml:
cluster.name: "docker-cluster"
network.host: 0.0.0.0
##添加配置
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization
http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE
discovery.zen.minimum_master_nodes: 1
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
# #配置单节点模式
discovery.type: single-node
注意运行指令挂载文件的路径,大家需要改成自己的文件夹路径
最后运行
docker run -p 9200:9200 -p 9300:9300 --name elasticsearch -e "discovery.type=single-node" -e "xpack.security.audit.enabled=true" -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" -v /data/deploy/xdeas-docker/elastic_single_mode/plugins:/usr/share/elasticsearch/plugins -v /data/deploy/xdeas-docker/elastic_single_mode/data:/usr/share/elasticsearch/data -v /data/deploy/xdeas-docker/elastic_single_mode/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -d elasticsearch:7.17.5
就启动了一个单例的elasticsearch了。
这边还能看到我们之前搭的kafka和zookeeper。接下来我们进入这个es,去生成我们的密钥文件。
docker exec -ti elasticsearch /bin/bash
然后运行 elasticsearch-setup-passwords interactive
然后经过漫长的输入了不知道多少次密码之后
最后会告诉你成功。 这会就成功生成了elasticsearch.keystore文件了。
然后运行以下代码生成ca证书(如果不开启ssl的可以跳过这一步)
./bin/elasticsearch-certutil ca #一直回车,默认文件名,没有密码
./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12 #因上一个步骤没有设置密码。一直回车就行,回车(文件使用默认名),密码(无密码)
然后在容器里面的 /usr/share/elasticsearch/config 文件夹里面会看见 elasticsearch.keystore 文件。/usr/shar/elasticsearch/文件夹下看见elastic-stack-ca.p12和elastic-certificates.p12文件.
我们需要把这三个文件复制到宿主机。那我们先从容器里面退出来,然后复制这三个文件到宿主机,.p12文件放到volumes/certs文件夹里面,keystore放到volumes文件夹里,那启动集群的准备工作,就算完成了。如果没有开启ssl的.p12文件的生成可以跳过。
然后就可以停掉我们这个单例的elasticsearch了 。
接下来回去我们的集群文件夹。docker-compose up -d 大功告成。