Skip to content

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 es

ES 不能以 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/es
yaml
# /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

堆的两条硬规则:

  1. 不超过物理内存的 50%(另外 50% 留给 Lucene 的页缓存)。
  2. 不超过 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.target
bash
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/?pretty
json
{
  "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-3

master 列的 * 表示当前主节点。

八、常见故障 ​

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 memoryLimitMEMLOCK=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 配了但重启后报错该参数只在首次引导时用引导完成后可删除