Elasticsearch简介与环境搭建

Elasticsearch(简称ES)是一款Java语言开发的开源分布式全文检索引擎,底层基于Apache Lucene库构建。相比直接基于Lucene开发,ES更加开箱即用。ES通过Restful API对外提供服务,它天然支持分布式部署和水平扩展,能够支撑PB级的数据检索,目前广泛应用于日志分析、全文检索、商品搜索、数据可视化等领域。
ES官方网站:https://www.elastic.co/cn/elasticsearch/
ES的适用场景
在正式开始学习ES之前,我们得先搞清楚ES到底能解决什么问题,以及什么时候该使用它。
ES最主要的使用场景是全文检索。我们都知道MySQL的LIKE '%关键词%'查询,它的问题是无法使用索引,数据量较大时全表扫描性能极差。而ES的核心能力全文检索是依托倒排索引结构实现的,它可以对文本内容进行分词后建立索引,这能支持极为高效的关键词检索。举例来说,典型的使用场景可能类似如下几种:
- 商品搜索:例如用户输入“蓝牙降噪耳机”,系统需要在商品信息中快速找出结果并按相关性排序,ES支持分词检索、同义词检索、向量检索和自定义boost权重,即使不考虑效率单纯使用MySQL也很难做到同样检索效果
- 日志查询:系统每天产生海量运行日志,运维排查问题时需要根据特定错误信息迅速找到对应的日志条目,在这个场景下ELK(Elasticsearch + Logstash + Kibana)是业界的标准解决方案
- 文章(中文)检索:博客、新闻网站、知识库等大型内容平台可能存储了海量的文章,ES支持中文分词、同义词、拼音等高级检索能力,非常适合这类场景
除此之外,ES也支持对结构化数据做范围查询、精确匹配、聚合统计等操作,例如按价格区间筛选商品、按时间段统计订单量、按地理位置查找附近门店等。
当然,ES绝不是另一种万能的通用数据库,它也有其局限性。首先,ES不支持ACID事务,无法做跨文档的原子操作,涉及资金、库存等强一致性要求的核心业务数据不应基于ES作为主数据库。其次,ES不支持类似关系型数据库的JOIN操作,多表关联查询是它的弱项。此外,ES的底层存储结构(Segment,Lucene索引的最小物理单元,它是Immutable不可变的)决定了它不擅长高频率的数据更新,每次更新本质上是先标记删除再写入新文档,频繁更新会产生大量碎片。
主数据库+ES双存储架构
在实际开发中,ES几乎从不单独使用,它总是与一个主数据库(例如MySQL)配合构成双存储架构使用。主数据库负责业务数据的持久化存储、事务操作和精确的主键查询,ES只负责搜索、筛选、聚合统计等检索类需求。在这种架构下,数据同步策略常见的有两种:
- 应用层双写:业务代码在写入MySQL的同时也写入ES,实现较为简单
- 数据异步同步:例如基于Canal和MySQL的Binlog异步将数据同步到ES,这种方式解耦更彻底,系统吞吐量和一致性更好,但搭建起来较为复杂
flowchart TD
A[用户写入请求] --> B[MySQL(主存储)]
B -->|同步/异步写入| C[Elasticsearch(搜索索引)]
B --> D[核心业务查询(精确查找、事务操作)]
C --> E[搜索/聚合查询(全文检索、复杂筛选)]
ES版本选择
ES的版本迭代非常快,目前主流使用的版本有7.x和8.x两种,其中8.x引入了原生向量检索等新特性,如果你打算创建一个新项目,建议直接使用8.x。
另一个可能影响我们版本选择的是ES的Java客户端,ES的Java客户端非常混乱,我们可以简单了解下其发展历程:
Transport Client:最早的ES官方Java客户端,使用自定义Transport协议(非HTTP)通信,从ES7.x开始被废弃。
Low Level REST Client(LLRC):官方提供的基于HTTP的ES客户端,是ES的Restful API的直接封装,使用起来非常繁琐,一般用户不直接使用LLRC。
High Level REST Client(HLRC):是LLRC的高级封装,提供Java方法级的API,从ES 7.15开始被废弃。
Java API Client:最新官方推荐客户端,支持ES 8.x版本,同样基于LLRC,可以看作HLRC的重写和替代版本。
另一方面,ES的HLRC客户端与Java API Client客户端之间的割裂也导致SpringBoot 2.x版本对应的SpringData Elasticsearch基于的是HLRC,SpringBoot 3.x版本对应的SpringData Elasticsearch基于的是Java API Client,这又直接导致两个大版本的SpringBoot几乎绑定了ES 7.x和ES 8.x,相关生态也是围绕这两个版本分别建立的,如果你不使用SpringData Elasticsearch就得用较为繁琐的原生客户端,而且可能遇到一些兼容性问题,因此我们具体选择前一定要考虑清楚这些历史遗留因素。
本系列笔记将基于ES 8.x进行介绍。
使用Docker搭建单节点ES服务
对于学习环境,我们可以使用Docker搭建简易的单节点ES服务。搭建ES的同时通常还需要搭建Kibana图形界面,因此我们这里先创建一个自定义网络。
docker network create elastic-net
然后执行以下命令启动ES。
docker run -d --name elasticsearch --net elastic-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "xpack.security.enabled=false" -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" elasticsearch:8.13.4
其中,9200是Restful API的HTTP端口,Java客户端和Kibana都使用这个端口;9300是集群内部通信端口,不过我们搭建的是单节点服务,因此并不重要;discovery.type=single-node参数声明为ES采用单节点模式,否则ES会试图持续等待其他节点加入而无法正常启动;xpack.security.enabled=false表示关闭X-Pack Security安全配置,开启后默认会有用户名密码登录、TLS/HTTPS加密等一系列安全措施,在学习环境比较麻烦,因此我们这里将其关闭了,不过生产环境不要这样做;ES_JAVA_OPTS限制了JVM堆内存,防止ES默认占用我们电脑太多的内存,生产环境应根据实际配置调整。
容器启动后,我们可以直接访问http://localhost:9200,如果一切正常,可能看到类似如下的JSON信息。
{
"name" : "9c3abb4122b9",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "eNpW590aTg21pPl8UC8QhA",
"version" : {
"number" : "8.13.4",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "da95df118650b55a500dcc181889ac35c6d8da7c",
"build_date" : "2024-05-06T22:04:45.107454559Z",
"build_snapshot" : false,
"lucene_version" : "9.10.0",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}
ES默认的分词器对中文的处理非常粗糙,基本上只是按单个汉字切分,无法识别词语边界,实际项目中必须安装IK分词器。注意IK分词器的版本必须与ES版本严格对应,我们这里安装8.13.4版本。
docker exec -it elasticsearch bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.13.4
注意:关于infini.cloud这个域名,实际上IK分词器最初是由一位叫medcl的作者维护的,如果你更早接触ES可能还记得安装插件需要去作者的Github仓库里下载插件包,不过后期由于作者精力或其他原因,大约2021年底INFINI Labs接手了该项目的维护,因此安装插件的域名也是这个公司的。
IK分词器安装完成后,需要重启ES服务,重启完成后,可以使用以下命令测试IK分词器是否生效。如果返回结果中,文本被正确切分为多个词语而不是逐字拆分或是出现找不到分词器ik_max_word等错误,说明IK分词器安装成功。
curl -X POST "http://localhost:9200/_analyze" -H "Content-Type: application/json" -d '{"analyzer": "ik_max_word", "text": "Elasticsearch中文分词测试"}'
最后我们安装Kibana服务。Kibana是ES官方提供的可视化工具,也是学习和调试ES的必备工具,它提供了Dev Tools,方便我们直接在浏览器中编写和执行QueryDSL。执行以下命令部署和启动Kibana。
docker run -d --name kibana --net elastic-net -p 5601:5601 -e "ELASTICSEARCH_HOSTS=http://elasticsearch:9200" kibana:8.13.4
启动完成后即可使用浏览器访问Kibana界面。进入Kibana后,点击左侧菜单中的Dev Tools,即可在控制台中直接编写和执行QueryDSL,后续章节的示例大多会在这里演示。

ES集群搭建
单机环境足以满足学习和开发需求,但生产环境通常需要搭建集群以保证高可用和数据安全,这里我们通过具体实践对ES的集群模式搭建做一个概念性了解。一个ES集群由多个节点(Node)组成,每个节点可以承担不同的角色。
Master Node(主节点):负责集群级别的管理,例如创建或删除索引、追踪节点状态、分配分片等。一个集群同时只有一个活跃的Master节点,生产环境建议至少部署3个候选Master节点以保证高可用。
Data Node(数据节点):负责存储实际的数据分片并处理数据的读写请求,是集群中承担主要工作负载的节点。
Coordinating Node(协调节点):负责接收客户端请求,将请求分发到对应的Data Node,并将结果汇总返回给客户端。所有节点默认都具备协调功能。
我这里使用3台主机进行搭建,ES默认会使用4GB大小的堆内存,因此生产环境每个节点建议配置至少8GB内存。
192.168.1.164
192.168.1.165
192.168.1.166
ES的安装包在官网即可找到,我这里使用的是8.13.4版本,我们直接下载下来并解压。
tar xvf elasticsearch-8.13.4-linux-x86_64.tar.gz
生产环境很有可能是处于有网络限制的内网环境,因此可能需要手动安装插件,这种情况下可以将IK等插件拷贝到plugins目录。此外,ElasticSearch由于内置了JDK,因此我们其实并不需要额外安装Java运行环境。
做完上述操作后,我们分别按如下配置修改3个节点的config/elasticsearch.yml配置文件。
cluster.name: es-cluster
node.name: node1
network.host: 192.168.1.164
http.port: 9200
transport.port: 9300
cluster.name:集群名node.name:当前节点名,每个节点需要唯一network.host:节点主机名,这里我们直接设置为节点IPhttp.port:提供HTTP服务的端口,默认为9200transport.port:集群通信端口,默认为9300
然后我们先启动主节点(注意其它节点先不要动,ES8启动会自动修改追加安全配置,如果其它节点独自启动加入集群时就会报错)。
./bin/elasticsearch
我们这里在Shell前台启动了ES,如果添加-d参数则可以守护进程模式启动。这里我们可以先以前台方式启动便于查看启动日志等信息,没问题后再使用守护进程模式。ES主节点启动成功后会输出如下信息。

同时,查看配置文件config/elasticsearch.yml会发现里面自动追加了X-Pack Security相关配置。
从控制台输出信息可知,我们可以使用bin/elasticsearch --enrollment-token <token>命令启动其它节点并加入集群。
./bin/elasticsearch --enrollment-token eyJ2ZXIiOiI4LjIuMyIsImFkciI6WyIxOTIuMTY4LjEuMTY0OjkyMDAiXSwiZmdyIjoiNTJlODYzNDI5Yzc0YTgwYTEwYjcwMmM1MDBlYzgyMTI5YzkyNDk3NDc3MTE1NDk4MDk5YjM3ZWJiM2Y4NGMyNSIsImtleSI6InBMZVpLb0lCX093cVJTQ2VMaGhFOnJReFJ3RWdKUlNDSjR4NHJ3TlF5d1EifQ==
此时我们就可以访问ES集群了。之前控制台输出信息中,显示了默认用户名为elastic,密码为c+6jHy1yo9vjieQ4eqj_。如果使用Postman进行测试,我们在请求中加入HTTP Basic认证信息即可。这里注意开启安全配置后我们需要使用HTTPS协议访问,当然我们的证书是自签名的,Postman中可以设置忽略SSL证书问题,或者也可以手动安装config/certs目录下的自签名CA证书。此外如果希望自定义密码,可以执行./bin/elasticsearch-setup-passwords interactive命令,这里就不多介绍了。
我们可以执行以下查询查看集群状态。
GET https://192.168.1.164:9200/_cat/nodes?v=true
输出例子如下。
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.1.165 74 97 2 0.22 0.19 0.29 cdfhilmrstw - node2
192.168.1.166 48 93 2 0.13 0.18 0.25 cdfhilmrstw - node3
192.168.1.164 57 66 1 0.27 0.18 0.20 cdfhilmrstw * node1
对于Kibana,我们也是下载并解压对应版本的安装包。
tar xvf kibana-8.13.4-linux-x86_64.tar.gz
解压后我们首先需要修改配置文件config/kibana.yml,其中server.host默认为localhost,我们一般都需要配置为对应服务器的域名或IP地址。配置完成后即可启动Kibana。
./bin/kibana
Kibana初次启动需要填一个token用于配置ES服务端信息,我们可以在ES的目录中执行如下命令生成token。
./bin/elasticsearch-create-enrollment-token -s kibana
自动配置完成后,使用之前的elastic用户即可进入Kibana面板。
总结
至此,我们已经完成了ES的环境搭建,并初步使用ES的Restful API查询了一些信息。从下一章开始,我们将深入学习ES的核心概念,理解它背后的工作原理。