外观
Elasticsearch:内核参数、堆与分片
ES 装不起来,九成是以 root 运行或没设 vm.max_map_count。分片规划错了,则是几个月后集群变慢的主因。
一、系统前置
bash
# 1. 虚拟内存映射数(ES 必需,否则 bootstrap check 失败)
sysctl -w vm.max_map_count=262144
echo 'vm.max_map_count = 262144' > /etc/sysctl.d/99-elasticsearch.conf
sysctl -p /etc/sysctl.d/99-elasticsearch.conf
# 2. 文件句柄
cat > /etc/security/limits.d/99-elasticsearch.conf <<'EOF'
es soft nofile 65535
es hard nofile 65535
es soft memlock unlimited
es hard memlock unlimited
es soft nproc 4096
es hard nproc 4096
EOF
# 3. 专用用户(ES 拒绝以 root 启动)
useradd -r -s /sbin/nologin esES 不能以 root 运行
启动会直接报:
text
java.lang.RuntimeException: can not run elasticsearch as root这是硬限制,不是配置能绕过的。必须建普通用户并用它启动。
二、安装
bash
cd /opt
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.15.3-linux-x86_64.tar.gz
tar xf elasticsearch-8.15.3-linux-x86_64.tar.gz
mkdir -p /data/es/{data,logs}
chown -R es:es /opt/elasticsearch-8.15.3 /data/esyaml
# /opt/elasticsearch-8.15.3/config/elasticsearch.yml
cluster.name: es-prod
node.name: es-1
path.data: /data/es/data
path.logs: /data/es/logs
network.host: 10.0.0.51
http.port: 9200
transport.port: 9300
discovery.seed_hosts: ["10.0.0.51", "10.0.0.52", "10.0.0.53"]
cluster.initial_master_nodes: ["es-1", "es-2", "es-3"]
# 单节点测试时改成:
# discovery.type: single-node
xpack.security.enabled: true堆单独配:
bash
mkdir -p /opt/elasticsearch-8.15.3/config/jvm.options.d
cat > /opt/elasticsearch-8.15.3/config/jvm.options.d/heap.options <<'EOF'
-Xms8g
-Xmx8g
EOF堆的两条硬规则:
- 不超过物理内存的 50%(另外 50% 留给 Lucene 的页缓存)。
- 不超过 31GB(超过会失去压缩指针,反而更耗内存)。
Xms 必须等于 Xmx
不等时堆会动态扩缩,触发不必要的 GC。ES 启动时会检查,不相等只告警,但应该改。
三、systemd
ini
# /etc/systemd/system/elasticsearch.service
[Unit]
Description=Elasticsearch
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=es
Group=es
Environment=ES_HOME=/opt/elasticsearch-8.15.3
Environment=ES_PATH_CONF=/opt/elasticsearch-8.15.3/config
ExecStart=/opt/elasticsearch-8.15.3/bin/elasticsearch
Restart=on-failure
RestartSec=10
LimitNOFILE=65535
LimitNPROC=4096
LimitMEMLOCK=infinity
[Install]
WantedBy=multi-user.targetbash
systemctl daemon-reload
systemctl enable --now elasticsearch
journalctl -u elasticsearch -f首次启动会自动配置安全并打印密码:
text
------------------------------------------
✅ Elasticsearch security features have been automatically configured!
✅ Authentication is enabled and cluster connections are encrypted.
ℹ️ Password for the elastic user (reset with `bin/elasticsearch-reset-password -u elastic`):
kR8=2mQz1xLp
ℹ️ HTTP CA certificate SHA-256 fingerprint:
a1b2c3d4e5f6...
------------------------------------------密码只显示一次,立刻保存。忘了就重置:
bash
bin/elasticsearch-reset-password -u elastic四、验证
bash
curl -k -u elastic:'kR8=2mQz1xLp' https://10.0.0.51:9200/?prettyjson
{
"name" : "es-1",
"cluster_name" : "es-prod",
"version" : {
"number" : "8.15.3",
"build_flavor" : "default",
"build_type" : "tar"
},
"tagline" : "You Know, for Search"
}bash
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cluster/health?pretty'json
{
"cluster_name" : "es-prod",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 12,
"active_shards" : 24,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0
}status 三种颜色:
| 颜色 | 含义 |
|---|---|
green | 所有主副分片都分配了 |
yellow | 主分片全在,有副本未分配(单节点集群必然 yellow) |
red | 有主分片未分配,数据不可用 |
单节点 + 副本数 1 必然是 yellow,这是正常的。
五、分片规划
bash
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cat/indices?v&s=store.size:desc'text
health status index pri rep docs.count store.size pri.store.size
green open order-2026.10 3 1 1842033 2.4gb 1.2gb
green open log-2026.10.27 12 1 98421344 42.1gb 21.0gb规划原则:
| 规则 | 说明 |
|---|---|
| 单分片 30~50GB | 太小浪费资源,太大恢复慢 |
| 每 GB 堆 ≤ 20 个分片 | 8G 堆 → 最多 160 个分片 |
| 分片数不能改 | 只能 _reindex 或 rollover |
| 副本数建议 1 | 再多会放大写入压力 |
bash
# 算一下当前分片数是否超限
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cat/shards' | wc -l
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cat/nodes?v&h=name,heap.percent,heap.max'text
name heap.percent heap.max
es-1 42 7.8gb
es-2 41 7.8gb
es-3 40 7.8gb每个节点约 160 个分片的上限,三个节点合计 480。超过就要考虑 rollover 或拆分集群。
六、ILM:自动滚动与删除
日志类索引必须配 ILM,否则索引会无限增长。
json
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": { "max_primary_shard_size": "50gb", "max_age": "7d" }
}
},
"warm": {
"min_age": "7d",
"actions": {
"forcemerge": { "max_num_segments": 1 },
"shrink": { "number_of_shards": 1 }
}
},
"delete": {
"min_age": "30d",
"actions": { "delete": {} }
}
}
}
}配合索引模板:
json
PUT _index_template/logs-template
{
"index_patterns": ["log-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "logs-policy",
"index.lifecycle.rollover_alias": "log"
}
}
}写入走别名 log,rollover 后自动切到新索引。
rollover 需要写别名
直接写具体索引名(log-2026.10.27)不会触发 rollover。必须写别名(log),且索引名符合 -000001 这类结尾规则。
七、常用调试命令
bash
# 节点
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cat/nodes?v&h=ip,heap.percent,ram.percent,cpu,load_1m,node.role,master,name'
# 未分配分片及原因
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cat/shards?v' | grep UNASSIGNED
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cluster/allocation/explain?pretty'
# 线程池是否打满
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cat/thread_pool/write?v'
# 慢查询
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/order/_search?pretty' -H 'Content-Type: application/json' -d '{"profile":true,"query":{"match_all":{}}}'text
ip heap.percent ram.percent cpu load_1m node.role master name
10.0.0.51 42 68 8 0.42 cdfhmsrt * es-1
10.0.0.52 41 66 7 0.38 cdfhmsrt - es-2
10.0.0.53 40 65 7 0.40 cdfhmsrt - es-3master 列的 * 表示当前主节点。
八、常见故障
bootstrap checks failed
text
[ERROR] [o.e.b.BootstrapChecks] max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]按第一节设置 vm.max_map_count。
其他常见 bootstrap 失败:
| 报错 | 处置 |
|---|---|
max file descriptors [4096] ... too low | 设 nofile 65535 |
memory locking requested ... cannot lock JVM memory | LimitMEMLOCK=infinity |
max number of threads ... too low | 设 nproc 4096 |
system call filters failed | 容器里需 --security-opt seccomp=unconfined |
discovery ... failed | 节点间 9300 不通,或 initial_master_nodes 写错 |
集群 red / yellow
bash
curl -k -u elastic:'密码' 'https://10.0.0.51:9200/_cluster/allocation/explain?pretty'json
{
"index": "order-2026.10",
"shard": 2,
"primary": true,
"current_state": "unassigned",
"unassigned_info": {
"reason": "NODE_LEFT",
"at": "2026-10-27T15:31:02.114Z",
"details": "node_left [es-2]"
},
"can_allocate": "no_valid_shard_copy"
}NODE_LEFT + no_valid_shard_copy = 那个分片的唯一副本所在的节点没了,数据丢失风险。
九、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
| 启动即退出 | 用 root 运行 | 建普通用户 |
vm.max_map_count too low | 内核参数 | sysctl 设置 |
| 单节点集群一直 yellow | 副本无处分配 | 正常,或设 replicas: 0 |
| 写入变慢、CPU 高 | 分片太多 / merge 频繁 | 减少分片,用 ILM |
| heap 设了 40G | 超过压缩指针阈值 | 改成 ≤31g |
| 内存看着够但 OOM | 堆 + Lucene 缓存超限 | 堆降到 50% 以内 |
| 集群连不上 | 9300 未放通 | 开 transport 端口 |
| 索引无限增长 | 没配 ILM | 配 rollover + delete |
cluster.initial_master_nodes 配了但重启后报错 | 该参数只在首次引导时用 | 引导完成后可删除 |