1 文章概述
1.1 ES基本概念
(1) 索引(Index)
类比关系型数据库概念:数据库(database)
(2) 类型(Type)
类比关系型数据库概念:表(table),类型这个概念已经逐步被官方弱化,7.X不再支持自定义类型,默认类型是_doc,在类型弱化之后也可以把索引(Index)类比为表
(3) 文档(Document)
类比关系型数据库概念:行(row)
(4) 分片(Shard)
类比于关系型数据库分库后数据分片,当一个索引数据量过大时,可以将一个索引拆分为多个数据集合,每一个数据集合只有一部分数据,这种数据集合称为分片
(5) 副本(Replica)
主分片可以有一个或多个副分片,副本有两个作用:第一可以承担读流量,提高系统吞吐量。第二可以提高可用性,如果主分片出现问题,副分片可以晋升为主分片
(6) 集群(Cluster)
一个节点资源是有限的,当数据量和流量达到超过单节点负载时,可以将多个节点组成一个集群,共同承担流量
1.2 两个问题
根据上述概念提出两个问题:
- 一个集群有三个节点,订单索引有三个分片,每个分片有两个副本,这些分片如何分布在集群
- 当请求访问ES集群,怎么确定数据在哪一个节点,哪一个分片
2 环境搭建
为了回答上述问题我们首先搭建实验环境,本次实验使用windows环境,ES 7.11版本。
2.1 集群搭建
ES官网下载64位版本并分别解压到文件夹:
- es-node-1
- es-node-2
- es-node-3
编辑文件
es-node1/config/elasticsearch.yml
# 集群信息
cluster.name: java-front-cluster
# 节点信息
node.name: es-node-1
node.master: true
node.data: true
network.host: localhost
http.port: 8001
# 通信端口
transport.tcp.port: 9001
discovery.zen.ping.unicast.hosts: ["localhost:9001", "localhost:9002", "localhost:9003"]
# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"
编辑文件
es-node2/config/elasticsearch.yml
# 集群信息
cluster.name: java-front-cluster
# 节点信息
node.name: es-node-2
node.master: true
node.data: true
network.host: localhost
http.port: 8002
# 通信端口
transport.tcp.port: 9002
discovery.zen.ping.unicast.hosts: ["localhost:9001", "localhost:9002", "localhost:9003"]
# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"
编辑文件
es-node3/config/elasticsearch.yml
# 集群信息
cluster.name: java-front-cluster
# 节点信息
node.name: es-node-3
node.master: true
node.data: true
network.host: localhost
http.port: 8003
# 通信端口
transport.tcp.port: 9003
discovery.zen.ping.unicast.hosts: ["localhost:9001", "localhost:9002", "localhost:9003"]
# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"
2.2 启动集群
连续双击下列脚本启动三个节点:
es-node-1/bin/elasticsearch.bat
es-node-2/bin/elasticsearch.bat
es-node-3/bin/elasticsearch.bat
如果只启动一个节点会出现错误:master节点无法发现或者选举,选举需要至少两个节点
[es-node-1] master not discovered or elected yet, an election requires at least 2 nodes
此时依次启动节点二和三就可以解决这个问题。
2.3 查看集群
节点一选举为主节点
GET http://localhost:8001/_cat/nodes
127.0.0.1 34 84 30 dilmrt * es-node-1
127.0.0.1 25 84 31 dilmrt - es-node-2
127.0.0.1 26 84 19 dilmrt - es-node-3
2.4 创建索引
创建订单索引,包含三个分片和两个副本
PUT http://localhost:8001/order
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
// 响应结果
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "order"
}
关注公众号【编程程序V】,分享更多Java技术前沿文章,Java学习面试资源。
3 解析问题一
一个集群有三个节点,订单索引有三个分片,每个分片有两个副本,这些分片如何分布在集群?
3.1 安装运行插件
可以通过扩展程序商店安装Chrome浏览器插件ElasticSearch Head,运行插件并访问节点一:
3.2 详细分析
3.2.1 主节点是哪一个
es-node-1
3.2.2 主分片如何分配
order索引有三个主分片
三个主分片分别对应加粗0、1、2
P0、P1在节点一,P2在节点二
3.2.3 副分片如何分配
P0有两个副分片R0,分配在节点二和节点三
P1有两个副分片R1,分配在节点二和节点三
P2有两个副分片R1,分配在节点一和节点三
3.2.4 集群健康值
集群健康值有三种颜色:绿色、黄色、红色
- 绿色:所有主分片和副分片都运行正常
- 黄色:所有主分片运行正常,存在副分片运行异常
- 红色:有主分片运行异常
3.2.5 关闭一个节点
关闭节点es-node-3并通过插件查看:
集群信息发生变化:
- 集群健康值变成黄色,表示所有主分片运行正常,存在副分片运行异常
- 节点三R0、R1、R2不能正常工作
3.2.6 关闭两个节点
再关闭节点es-node-2并通过插件查看:
集群信息发生变化:
- 集群健康值变成未连接
- 集群处于不可用状态,无法查询集群信息
- 查看es-node-1控制面板发现报错信息:[es-node-1] master not discovered or elected yet, an election requires at least 2 nodes
- 报错表示当前配置下master无法发现或者选举,选举至少需要两个节点
4 解析问题二
当请求访问ES集群,怎么确定访问数据在哪一个节点,哪一个分片?
4.1 路由规则
order索引有三个主分片,如果我们现在新增orderId=100订单数据,这条数据应该保存在哪个分片?
路由规则公式:
shard_number = hash(routing) % number_of_primary_shards
本实例路由公式:
shard_num = hash(100) % 3
路由公式参数说明:
- shard_num:最终选择分片序号
- routing:路由ID,不指定则为文档ID
- number_of_primary_shards:主分片数量
4.2 协调节点
本实例集群中有三个节点,当客户端发送请求至集群,应该发送请求到哪一个节点呢?
客户端也不知道应该发送给哪一个节点,所以会发送至任意一个节点,由这个节点决定处理还是转发,这个节点称为协调节点。
4.3 处理写请求
本章节沿用第二章节集群信息:
orderId=100写请求流程:
- 客户端发送写请求到任意节点,假设node-3
- node-3作为协调节点,根据路由公式发现应该写入1号主分片
- node-3将写请求转发给node-1
- node-1将orderId=100写入1号主分片成功
- 主分片将数据同步给node-2、node-3节点的1号副分片
- 发送响应给客户端
4.4 处理读请求
orderId=100读请求流程:
- 客户端发送写请求到任意节点,假设node-3
- node-3作为协调节点,根据路由公式发现应该读1号分片
- node-3查询1号所有主副分片以及所在节点
- 根据负载均衡策略决定路由哪一个分片,假设为node-2的1号副分片
- 转发请求到node-2读取1号副分片
- 发送响应给客户端
4.5 不指定routing怎么路由
这个问题可以类比关系型数据库分库分表,读取是不指定shardingKey会怎么样?答案是会扫描全库全表。ES整体搜索过程可以分为Query和Fetch两个阶段:
(1) Query
- 查询请求发送到每个分片(主分片或者副分片均可)
- 每个分片在执行查询,结果存放在大小为from + size的优先队列
- 每个分片返回优先队列中所有文档的ID和排序值给协调节点
- 协调节点合并所有文档到其优先队列,整体进行排序
(2) Fetch
- 协调节点决定哪些文档需要取回,并向对应分片查询文档信息
- 返回结果给客户端
5 文章总结
第一本文介绍了ES基本概念并提出了两个问题,第二本文为了回答这两个问题搭建了ES集群,第三本文从六个角度回答了第一个问题,第四本文从五个角度回答了第二个问题,希望本文对大家有所帮助。