概述
集群角色
集群由多个Node组成,Node可以有不同的类型,通过下面配置文件设置:
../elasticsearch.yml:
node.master: [true|false]
node.data: [true|false]
- node.master=true :作为
master
的候选节点,标志着此节点可以产于选举。 - node.data=true :此节点作为数据节点,存储
shard
数据以及处理数据的写入、查询等。 - 两者都为false的时候,说明此节点只担任请求转发、结果聚合工作,在处理大量请求的时候,可以达到负载均衡效果。
核心概念
Cluster 集群
ES集群由多个节点组成,“集群名称”作为一个集群的标识。
Node 节点
一个ES实例代表一个Node。
Node具有多种类型,一般这样组合节点的类型:
类型/说明 | 主节点+数据节点 | 数据节点 | 客户端节点 |
---|---|---|---|
node.master | true | false | false |
node.data | true | true | false |
有成为主节点资格,也存储数据 | 不参与竞选,只存储数据 | 不存储、不竞选,主要是针对海量请求进行负载均衡 |
shard 分片
在ES中,索引数据被分为多个分片进行存储。
分片分为主分片和副分片,分别处理写操作和读操作,副分片是复制主分片的数据。
这些分片(即主、副分片)分布在各个节点上。比如分布在1节点上的主分片,其副分片可能在2节点上。
搭建集群
集群配置(基于Docker搭建)
环境说明
elasticsearch:7.14.0。
我将开启三个虚拟机,搭建ES集群,共三个节点。
Node1 | Node2 | Node3 | |
---|---|---|---|
IP | 192.168.204.181 | 192.168.204.182 | 192.168.204.183 |
域名 | es01 | es02 | es03 |
系统 | Ubuntu 18 | Ubuntu 18 | Ubuntu 18 |
host文件配置C:\Windows\System32\drivers\etc\hosts
:
192.168.204.181 es01
192.168.204.182 es02
192.168.204.183 es03
架构如下:
准备
下面操作分别在三台主机上进行:
- 创建存放数据、日志的目录:
mkdir /home/liangshijie/es_home/data
、mkdir /home/liangshijie/es_home/logs
- 授予数据、日志目录的权限给管理员用户:
sudo chown -R 1000:1000 /home/liangshijie/es_home
1000:1000
的意思是:<用户ID>:<用户组ID>
查看用户ID:id -u <用户名>
查看用户组ID:getent group <用户组名>
- 放开防火墙端口:
9200
、9300
我使用ufw管理防火墙,开放端口的命令:ufw allow 9200、ufw allow 9300
使用docker-compose启动ES实例
现在,需要在三台主机上配置docker-compose.yml
文件,然后使用docker-compose up -d
命令创建、运行容器(用户需要具备root权限)。
Node1
version: '3'
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0 # es镜像版本
container_name: es
network_mode: host
environment:
- node.name=node1 # 节点名称
- cluster.name=my-es-cluster # 集群名称
- discovery.seed_hosts=es02,es03 # 其他节点的地址
- cluster.initial_master_nodes=node1 # 初始主节点
- bootstrap.memory_lock=true # 内存锁定以避免交换
- network.publish_host=es01 # 握手之后,响应的地址(写主机地址)
- http.publish_host=es01 # 写主机地址
- transport.publish_host=es01 # 写主机地址
- node.master=true # 节点参与主节点的竞选
- node.data=true # 节点存储数据
- http.port=9200
- transport.tcp.port=9300 # 节点内部数据传输端口
# - http.cors.enabled=true
# - http.cors.allow-origin="*"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # JVM堆内存设置
ulimits: # 资源限制设置
memlock: # 内存锁定限制
soft: -1 # 软限制为无限制
hard: -1 # 硬限制为无限制
nofile:
soft: 65536
hard: 65536
volumes:
- /home/liangshijie/es_home/data:/usr/share/elasticsearch/data # <主机目录>:<容器内目录>。此外,也可以使用docker默认的。注意,要保证目录权限足够
- /home/liangshijie/es_home/logs:/usr/share/elasticsearch/logs
ports:
- 9200:9200 # 对外暴露端口
- 9300:9300 # 对外暴露端口
kibana: # 不需要kibana的可以移除
image: kibana:7.14.0
container_name: kibana
restart: always
environment:
- TZ="Asia/Shanghai"
ports:
- 5601:5601
volumes:
- /home/liangshijie/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml:ro # 根据实际情况修改kibana.yml文件路径
depends_on:
- es
补充 kibana.yml
server.name: kibana
server.host: "0.0.0.0"
#此处为es的master地址
elasticsearch.hosts: "http://es01:9200"
xpack.monitoring.ui.container.elasticsearch.enabled: true
i18n.locale: "zh-CN"
Node2
version: '3'
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0 # es镜像版本
container_name: es
network_mode: host
environment:
- node.name=node2 # 节点名称
- cluster.name=my-es-cluster # 集群名称
- discovery.seed_hosts=es01,es03 # 其他节点的地址
- cluster.initial_master_nodes=node1 # 初始主节点
- bootstrap.memory_lock=true # 内存锁定以避免交换
- network.publish_host=es02 # 握手之后,响应的地址(写主机地址)
- http.publish_host=es02 # 写主机地址
- transport.publish_host=es02 # 写主机地址
- node.master=false # 节点参与主节点的竞选
- node.data=true # 节点存储数据
- http.port=9200
- transport.tcp.port=9300 # 节点内部数据传输端口
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # JVM堆内存设置
ulimits: # 资源限制设置
memlock: # 内存锁定限制
soft: -1 # 软限制为无限制
hard: -1 # 硬限制为无限制
nofile:
soft: 65536
hard: 65536
volumes:
- /home/liangshijie/es_home/data:/usr/share/elasticsearch/data # <主机目录>:<容器内目录>。此外,也可以使用docker默认的。注意,要保证目录权限足够
- /home/liangshijie/es_home/logs:/usr/share/elasticsearch/logs
ports:
- 9200:9200 # 对外暴露端口
- 9300:9300 # 对外暴露端口
Node3
version: '3'
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0 # es镜像版本
container_name: es
network_mode: host
environment:
- node.name=node3 # 节点名称
- cluster.name=my-es-cluster # 集群名称
- discovery.seed_hosts=es01,es02 # 其他节点的地址
- cluster.initial_master_nodes=node1 # 初始主节点
- bootstrap.memory_lock=true # 内存锁定以避免交换
- network.publish_host=es03 # 握手之后,响应的地址(写主机地址)
- http.publish_host=es03 # 写主机地址
- transport.publish_host=es03 # 写主机地址
- node.master=false # 节点参与主节点的竞选
- node.data=true # 节点存储数据
- http.port=9200
- transport.tcp.port=9300 # 节点内部数据传输端口
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # JVM堆内存设置
ulimits: # 资源限制设置
memlock: # 内存锁定限制
soft: -1 # 软限制为无限制
hard: -1 # 硬限制为无限制
nofile:
soft: 65536
hard: 65536
volumes:
- /home/liangshijie/es_home/data:/usr/share/elasticsearch/data # <主机目录>:<容器内目录>。此外,也可以使用docker默认的。注意,要保证目录权限足够
- /home/liangshijie/es_home/logs:/usr/share/elasticsearch/logs
ports:
- 9200:9200 # 对外暴露端口
- 9300:9300 # 对外暴露端口
验证
任意访问一个地址:http://es01:9200/_cat/health?v
、http://es02:9200/_cat/health?v
、http://es03:9200/_cat/health?v
epoch | timestamp | cluster | status | node.total | node.data | shards | pri | relo | init | unassign | pending_tasks | max_task_wait_time | active_shards_percent |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1692606535 | 08:28:55 | my-es-cluster | green | 3 | 3 | 14 | 7 | 0 | 0 | 0 | 0 | 0 | 100.0% |
- cluster 集群名称
- status集群状态 green代表健康;yellow代表分配了所有主分片,但至少缺少一个副本,此时集群数据仍旧完整;red代表部分主分片不可用,可能已经丢失数据。
- node.total代表在线的节点总数量
- node.data代表在线的数据节点的数量
- shards 存活的分片数量
- pri 存活的主分片数量 正常情况下 shards的数量是pri的两倍。
- relo迁移中的分片数量,正常情况为 0
- init 初始化中的分片数量 正常情况为 0
- unassign未分配的分片 正常情况为 0
- pending_tasks准备中的任务,任务指迁移分片等 正常情况为 0
- max_task_wait_time任务最长等待时间
- active_shards_percent正常分片百分比 正常情况为 100%
挂载配置文件(可选)
如果你要挂载配置文件(上述例子中,配置内容我全写在environment
中了),
你可以在volumes
中添加:- /xxxx/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
,将配置文件挂载到主机。
下面是一个yml的例子:
cluster.name: my-es-cluster
node.name: node1
node.master: true
node.data: true
#network.host: 0.0.0.0
network.bind_host: 0.0.0.0
network.publish_host: 10.0.0.1
http.port: 9200
transport.tcp.port: 9300
http.cors.enabled: true
http.cors.allow-origin: "*"
discovery.zen.ping.unicast.hosts: ["es-master:9300", "es-node1:9300", "es-node2:9300"]
discovery.zen.minimum_master_nodes: 2
discovery.zen.ping_timeout: 5s
bootstrap.memory_lock: true
action.destructive_requires_name: true
cluster.initial_master_nodes: ["es-master"]
ingest.geoip.downloader.enabled: false
重要系统配置(可选)
参考来源官网:https://www.elastic.co/guide/en/elasticsearch/reference/7.5/system-config.html
禁用交换
防止部分JVM堆数据被交换到磁盘,降低性能。
方式一:禁用交换分区
- 临时禁用
sudo swapoff -a
- 永久禁用
# 备份
sudo cp /etc/fstab /etc/fstab.bak
# 编辑
sudo nano /etc/fstab
# 注释下面
# /dev/mapper/swap none swap sw 0 0
# 重启系统(建议)
sudo reboot
# 验证:无输出表示成功
cat /proc/swaps
方式二:配置 swappiness
sysctl 值 vm.swappiness 设置为1。
设置为1表示尽量减少对分页交换的使用,优先使用物理内存。
- 临时设置
- 永久设置
sudo vim /etc/sysctl.conf
# 末尾添加
vm.swappiness=1
# 更改生效
sudo sysctl -p
方式三:启用 bootstrap.memory_lock
在启动时将JVM的堆内存锁定在物理内存中,从而避免将堆内存交换到磁盘上的分页交换空间。这可以提高Elasticsearch的性能和稳定性,尤其在处理大量数据时非常有用。
# 1.打开配置文件,通常位于config目录下
vim elasticsearch.yml
# 2.添加配置
bootstrap.memory_lock: true
# 3.重启ES
# 4.验证:mlockall 值为 true,则表示内存已经成功锁定。
curl -X GET "localhost:9200/_nodes?filter_path=**.mlockall"
或
GET _nodes?filter_path=**.mlockall
注意,启用 bootstrap.memory_lock 需要足够的操作系统权限。可能需要使用超级用户(root)权限来执行这些操作。
文件描述符
Elasticsearch 使用许多文件描述符或文件句柄。用完文件描述符可能是灾难性的,并且最有可能导致数据丢失。确保将运行 Elasticsearch 的用户打开的文件描述符的数量限制增加到 65536 或更高。
- 在Docker上设置:
--ulimit nofile=65536:65536
- 验证
GET _nodes/stats/process?filter_path=**.max_file_descriptors
- 也在主机上设置
vim /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
虚拟内存
默认操作系统对 mmap 计数的限制可能太低,这可能导致内存不足异常。
在 Linux 上,可以通过以 root 身份运行以下命令来增加限制(临时):sysctl -w vm.max_map_count=262144
什么时候要调整?调整到什么数值?需要有待后续进一步探究。这里就不深入
线程数
Elasticsearch运行时涉及许多不同类型的线程,包括搜索线程、索引线程、后台线程等。适当的线程数设置可以确保不会出现过多的线程竞争和资源竞争,从而提高系统的性能。设置合理的线程数可以确保各个线程能够充分利用可用的CPU核心,提高并发处理能力。
确保 Elasticsearch 用户可以创建的线程数至少为4096。
- 使用root运行命令
- 或者将 nproc 设置为4096,添加到 /etc/security/limits.conf 配置文件中
sudo vim /etc/security/limits.conf
# 设置对应的es用户的nproc数值
es_user soft nproc 4096
es_user hard nproc 4096
# 重启系统
DNS缓存设置
Elasticsearch在运行时使用安全管理器(security manager)。在安全管理器下,Java虚拟机(JVM)默认会对主机名解析进行缓存,以提高性能。
Elasticsearch为了适应不同的环境和需求,对主机名解析的缓存行为进行了一些调整,并提供了修改缓存时间的选项。
默认将对正向主机名解析(从主机名到IP地址)的缓存时间设置为60秒,而对负向主机名解析(从IP地址到主机名)的缓存时间设置为10秒。
自定义缓存:
- JVM选项中编辑
es.networkaddress.cache.ttl
和es.networkaddress.cache.negative.ttl
的值,以自定义缓存时间。这些选项分别控制正向和负向主机名解析的缓存时间,单位为秒。
在Elasticsearch中,Java安全策略中的 networkaddress.cache.ttl 和 networkaddress.cache.negative.ttl 参数(用于修改缓存时间)是被忽略的。