以下我们将基于 elasticsearch-6.6.0 版本,在单机上部署 3 个节点组成的集群。3个节点都用作候选主节点,且同时作为数据节点。
集群搭建
下载 elasticsearch-6.6.0 二进制包,解压,复制 3 份,分别命名为 es1, es2, es3。
分别修改 config/elasticsearch.yml 的配置,
es1 如下:
# 集群名称,相同集群的节点名称一致
cluster.name: my-application
# 节点名称
node.name: es1
# 数据存储路径
path.data: /path/to/es1/data
# 日志存储路径
path.logs: /path/to/es1/logs
# 是否用作候选主节点,默认为 true
node.master: true
# 是否用作数据节点,默认为 true
node.data: true
# HTTP 端口,提供 RESTful 服务交互
http.port: 5201
# TCP 端口,集群节点之间通信
transport.tcp.port: 5301
# 集群中相互通信的节点
discovery.zen.ping.unicast.hosts: ["localhost:5301","locahost:5302","locahost:5303"]
# 集群最小主节点个数
discovery.zen.minimum_master_nodes: 2
es2 如下:
# 集群名称,相同集群的节点名称一致
cluster.name: my-application
# 节点名称
node.name: es2
# 数据存储路径
path.data: /path/to/es2/data
# 日志存储路径
path.logs: /path/to/es2/logs
# 是否用作候选主节点,默认为 true
node.master: true
# 是否用作数据节点,默认为 true
node.data: true
# HTTP 端口,提供 RESTful 服务交互
http.port: 5202
# TCP 端口,集群节点之间通信
transport.tcp.port: 5302
# 集群中相互通信的节点
discovery.zen.ping.unicast.hosts: ["localhost:5301","locahost:5302","locahost:5303"]
# 集群最小主节点个数
discovery.zen.minimum_master_nodes: 2
es3 如下:
# 集群名称,相同集群的节点名称一致
cluster.name: my-application
# 节点名称
node.name: es3
# 数据存储路径
path.data: /path/to/es3/data
# 日志存储路径
path.logs: /path/to/es3/logs
# 是否用作候选主节点,默认为 true
node.master: true
# 是否用作数据节点,默认为 true
node.data: true
# HTTP 端口,提供 RESTful 服务交互
http.port: 5203
# TCP 端口,集群节点之间通信
transport.tcp.port: 5303
# 集群中相互通信的节点
discovery.zen.ping.unicast.hosts: ["localhost:5301","locahost:5302","locahost:5303"]
# 集群最小主节点个数,为了防止脑裂,最小主节点个数应该为(候选主节点个数 / 2 + 1)
discovery.zen.minimum_master_nodes: 2
- 分别启动 3 个节点
cd /path/to/es1
bin/elasticsearch -d
- 在浏览器中查看集群状态
可视化管理
通过 elasticsearch-head 可以可视化的管理 es 集群。
elasticsearch-head 项目地址 http://mobz.github.io/elasticsearch-head。
如果本地有 nodejs 环境,通过以下步骤安装 elasticsearch-head。
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
安装完成,在浏览器中访问 http://localhost:9100/
elasticsearch-head 在访问 es 实例 RESTful API 时会存在跨域问题,es 实例启动时,配置文件需要添加一下参数
http.cors.enabled: true
http.cors.allow-origin: "*"
基础操作
创建索引
PUT /my_index
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 0
}
}
number_of_shards: 主分片数量,默认为 5
number_of_replicas: 分片副本数量,默认为 1
动态更新副本数量
PUT /my_index/settings
{
"number_of_replicas": 1
}
高可用性验证
这里以另外一个真实在用的集群来演示集群的高可用性。
步骤一
- 索引
app_jgus_yn
与app_jgus
都是在单节点集群情况下创建的,默认主分片数量为 5,副本数量为 0。 - 后来,集群扩展到 3 个节点,我为
app_jgus
动态更新了副本数量为 1。 - 该集群处于 green 状态:
步骤二
- 集群中 es3 节点失败了,集群处于 red 状态,有主分片缺失,此时集群不可用。
- 对
app_jgus
索引的查询依然可以正常进行,因为app_jgus
的每个主分片都有 1 个副本,剩余 2 个节点中保存有所有的索引数据。 - 索引
app_jgus_yn
由于没有为主分片生成副本,随 es3 节点失败,缺少了 2 个主分片,缺失的分片数据将无法被操作。
步骤三
- 重启 es3 节点,刷新查看集群状态
- 最终,集群状态恢复为步骤一中的正常状态
步骤四
- 为索引
app_jgus_yn
动态更新副本数量,将number_of_replicas
设为 1,即每个主分片都有 1 份副本。 - 每个分片都拥有了 1 份副本,集群处于 green 状态
步骤五
- 原主节点宕机,es3 被选为新的主节点。
- 由于原来每个主分片,都有副本,虽然一个节点宕机了,但其他 2 个节点有所有的数据,依赖可以完成所有的数据操作。此时,集群状态为 yellow。
- 一段时间以后,新的集群将达到 green 状态
步骤六
- 恢复原节点,相当于在已经稳定的集群中再新增节点。
- 集群将在新节点上分配数据,并最终达到新的 green 状态。
问题排查记录
问题一
在集群搭建完成以后,创建索引过程中,遇到了数据分片 unassigned
的异常。大致情况如下:
查看分片 unassigned
原因
GET /_cluster/allocation/explain?pretty
这里是因为空间不够引起的。
解决方案是调整集群磁盘水印的参数。
PUT /_cluster/settings
{
"persistent": {
"cluster.routing.allocation.disk.watermark.high": "95%",
"cluster.routing.allocation.disk.watermark.low": "93%"
}
}
问题二
集群搭建过程中,配置文件显式指定 transport.tcp.port
,但未显式设置 discovery.zen.ping.unicast.hosts
时,几个节点之间无法组成集群,各自独立。
我在配置时,3 个 es 节点的 transport.tcp.port
分别为 5301、5302、5303。当没有显式设置 discovery.zen.ping.unicast.hosts
时,会自动按照 9300、9301、9302 的端口顺序设置这个广播地址,因此无法与真实的实例端口通信。以上是我通过查看进程占用的端口得出的结论。
参考
如何在Elasticsearch中解析未分配的分片(unassigned shards)
Elasticsearch 学习笔记 索引创建、插入、查询、修改、删除
如果你看完本文有收获,欢迎关注我的公众号:精进Java (craft4j)。这是一个专注 于Java 后端与架构内容学习分享的公众号。