1. 为什么要在麒麟V10上折腾ElasticSearch
先把场景说清楚。麒麟V10(这里指的是银河麒麟桌面版/服务器版操作系统V10)是不少单位在推进信息化建设时选用的国产操作系统底座,而ElasticSearch(后面统一简称ES)是全文检索和日志分析领域用得最普遍的分布式搜索引擎。把这两个东西凑到一起,是很多做日志平台、做数据检索、做业务搜索的团队绕不开的一步。
我最近刚在一个基于麒麟V10服务器版的环境里完整部署了一套ES集群,从系统依赖、JDK选型、内核参数调优,到systemd托管、集群发现配置、安全加固,一路踩了不少坑。这篇文章就是把这套流程完整复盘一遍,包括每一步为什么这么做、参数怎么算、遇到问题怎么排查。适合两类人看:一类是第一次在国产化环境里部署ES、被各种依赖和权限问题卡住的运维或后端同学;另一类是想把ES从x86迁移到国产化平台、需要一份可复现清单的架构同学。
需要提前说明的是,麒麟V10底层是Linux内核,包管理用的是RPM系(yum/dnf),所以整体思路和CentOS/RHEL系是相通的,但差异点集中在软件源可用性、SELinux策略、systemd单元行为、以及部分依赖库版本上。这些差异恰恰是最容易让人翻车的地方,后面会逐个拆开讲。
2. 部署前的整体设计与选型思路
2.1 版本组合怎么定
ES的版本选择是第一道坎。ES 7.x和8.x在安全模型上有本质区别:7.x默认关闭安全认证,8.x默认开启TLS和账号密码。在国产化环境里,很多内网服务之间调用并不走HTTPS,如果直接上8.x,光是证书配置就能耗掉大半天。所以我的建议是:
- 如果是内网日志检索、对安全要求不高的场景,选ES 7.17.x(7.x最后一个大版本,长期维护),部署成本最低。
- 如果是对外提供服务、有合规要求的场景,选ES 8.x,但一定要提前规划证书和账号体系。
JDK方面,ES 7.17自带捆绑JDK(在jdk目录下),理论上不需要系统装JDK。但麒麟V10的glibc版本和自带JDK的兼容性需要验证,我实测下来7.17自带的JDK在麒麟V10 SP2上是能正常跑的,所以优先用ES自带的JDK,避免系统JDK版本冲突。
2.2 部署形态怎么选
单节点还是集群,取决于数据量和可用性要求。这里给一个粗略的判断:
| 场景 | 节点数 | 说明 |
|---|---|---|
| 个人测试/开发 | 1 | 单节点,关闭发现配置 |
| 小规模日志(日增<10GB) | 3 | 3节点起步,1主2数据或3角色合一 |
| 中等规模(日增10-100GB) | 5+ | 分离master和data角色 |
| 大规模 | 按需 | 独立coordinating节点 |
麒麟V10环境里我建议至少3节点,因为ES的集群脑裂防护依赖discovery.seed_hosts和cluster.initial_master_nodes,单节点虽然能跑,但一旦挂了数据就没了,而且很多分片分配策略在单节点下行为不一样,测试环境和生产环境差异太大。
2.3 目录规划
ES默认会把数据、日志、配置都放在安装目录下,这在生产环境是大忌——升级或重装时容易误删数据。我的规划是:
- 安装目录:
/usr/local/elasticsearch - 数据目录:
/data/es/data(单独挂盘,SSD优先) - 日志目录:
/data/es/logs - 配置目录:保留在安装目录的
config下,但通过path.data和path.logs指向独立目录
这样升级时只需要替换安装目录,数据和日志不受影响。
3. 系统层准备:麒麟V10的差异点处理
3.1 依赖检查与安装
麒麟V10服务器版默认软件源里有些包可能缺失,先做一轮依赖体检:
# 检查glibc版本,ES 7.17要求2.17以上 ldd --version # 检查是否有libcurl、openssl等基础库 rpm -qa | grep -E "libcurl|openssl|zlib"如果缺包,用系统自带的yum源安装:
yum install -y libcurl openssl zlib bzip2注意:麒麟V10的yum源里包名可能和CentOS略有差异,比如有些版本把
libcurl拆成了libcurl-minimal和libcurl-full,装之前先用yum search确认一下。
3.2 内核参数调优
ES对文件句柄数和内存映射区数量有硬性要求,这是最容易忽略又最容易导致启动失败的地方。
# 编辑 /etc/security/limits.conf,追加 * soft nofile 65536 * hard nofile 65536 * soft nproc 4096 * hard nproc 4096 # 编辑 /etc/sysctl.conf,追加 vm.max_map_count=262144 vm.swappiness=1vm.max_map_count这个参数必须调,ES的Lucene底层用mmap读索引文件,默认值65530在高负载下会直接报max virtual memory areas vm.max_map_count [65530] is too low。262144是官方推荐值,按每个分片占用一定映射区估算,节点上分片越多这个值要越大。
vm.swappiness=1是为了尽量不让内核把ES的内存换出去,ES自己会管理堆内存,被swap会导致GC停顿飙升。
改完执行sysctl -p生效,ulimit -n验证句柄数。
3.3 创建专用用户
ES不允许用root启动,这是硬性限制。创建一个专用用户:
useradd esuser passwd esuser # 把数据目录和安装目录的属主给esuser chown -R esuser:esuser /usr/local/elasticsearch chown -R esuser:esuser /data/es实操心得:麒麟V10的
useradd默认可能不创建家目录,如果后续要用到~/.bashrc里的环境变量,记得加-m参数。
3.4 关闭SELinux或调整策略
麒麟V10默认可能开启SELinux。ES需要绑定端口、读写数据目录,SELinux的默认策略会拦截。两种处理方式:
- 测试环境:直接
setenforce 0临时关闭,或改/etc/selinux/config永久关闭。 - 生产环境:不建议直接关,而是用
ausearch和audit2allow生成针对ES的放行策略。
我个人的做法是生产环境保留SELinux,但为ES单独写策略模块,这样既满足合规要求,又不影响ES运行。具体命令后面排查章节会讲。
4. ElasticSearch安装与核心配置
4.1 安装包获取与解压
从官方渠道下载对应架构的tar包(麒麟V10常见是aarch64或x86_64,用uname -m确认)。下载后解压:
tar -zxvf elasticsearch-7.17.9-linux-aarch64.tar.gz -C /usr/local/ mv /usr/local/elasticsearch-7.17.9 /usr/local/elasticsearch注意:不要用root解压后直接跑,解压完立刻改属主给esuser。
4.2 elasticsearch.yml核心配置
这是整个部署的灵魂文件,逐项说明:
cluster.name: kylin-es-cluster node.name: es-node-1 path.data: /data/es/data path.logs: /data/es/logs network.host: 0.0.0.0 http.port: 9200 transport.port: 9300 discovery.seed_hosts: ["10.0.0.1:9300", "10.0.0.2:9300", "10.0.0.3:9300"] cluster.initial_master_nodes: ["es-node-1", "es-node-2", "es-node-3"] bootstrap.memory_lock: true逐项解释:
cluster.name:集群名,同一网段如果有多个集群必须区分开,否则会误加入。node.name:节点唯一标识,建议用主机名或带序号的命名。network.host:绑0.0.0.0表示监听所有网卡,生产环境建议绑内网IP。discovery.seed_hosts:集群发现种子节点,写其他节点的transport地址。cluster.initial_master_nodes:只在集群首次启动时配置,列出有资格成为master的节点名。集群起来后这个配置可以删掉,否则重启时可能出问题。bootstrap.memory_lock: true:锁定内存,防止ES堆内存被换出。这个要配合systemd的LimitMEMLOCK=infinity使用,否则会报错。
4.3 JVM堆内存配置
编辑config/jvm.options,或者新建config/jvm.options.d/heap.options:
-Xms16g -Xmx16g堆内存怎么定?经验公式:
- 不超过物理内存的50%
- 不超过32GB(超过32GB后JVM的指针压缩失效,反而浪费内存)
- 留足够内存给Lucene的文件缓存(剩下的一半基本都给文件缓存)
比如64GB内存的机器,堆设31GB,剩33GB给文件缓存,这是比较理想的配比。如果机器只有16GB内存,堆设8GB,剩8GB给系统和其他进程。
踩过的坑:
-Xms和-Xmx必须设成一样大,否则JVM会动态调整堆大小,导致GC行为不稳定。
4.4 systemd托管配置
用systemd托管比nohup启动靠谱得多,能自动重启、能管资源限制。创建/etc/systemd/system/elasticsearch.service:
[Unit] Description=Elasticsearch After=network.target [Service] Type=simple User=esuser Group=esuser LimitNOFILE=65536 LimitNPROC=4096 LimitMEMLOCK=infinity Environment=ES_JAVA_HOME=/usr/local/elasticsearch/jdk ExecStart=/usr/local/elasticsearch/bin/elasticsearch Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target关键点:
LimitMEMLOCK=infinity:配合bootstrap.memory_lock,不加这个ES启动会直接失败。Environment=ES_JAVA_HOME:指定用ES自带的JDK,避免系统JDK干扰。Restart=on-failure:进程异常退出自动拉起。
配置完执行:
systemctl daemon-reload systemctl enable elasticsearch systemctl start elasticsearch5. 集群验证与安全加固
5.1 启动验证
启动后先看日志:
tail -f /data/es/logs/kylin-es-cluster.log看到started字样说明节点起来了。然后验证集群状态:
curl -XGET 'http://localhost:9200/_cluster/health?pretty'返回的status字段:
green:所有主分片和副本分片都正常yellow:主分片正常,副本分片未分配(单节点常见)red:有主分片未分配,需要立即排查
再看节点列表:
curl -XGET 'http://localhost:9200/_cat/nodes?v'三个节点都出现且角色正确,集群就算搭起来了。
5.2 安全加固
ES 7.x默认无认证,任何能访问9200端口的人都能读写数据。生产环境必须加固。最轻量的做法是开启X-Pack基础认证:
在elasticsearch.yml追加:
xpack.security.enabled: true然后执行密码初始化:
/usr/local/elasticsearch/bin/elasticsearch-setup-passwords interactive会依次让你设置elastic、kibana、logstash等内置账号的密码。设置完后所有请求都要带认证:
curl -u elastic:你的密码 -XGET 'http://localhost:9200/_cluster/health?pretty'注意:开启安全后,集群内部节点间通信也需要配置证书,否则节点无法加入。如果只是内网使用,可以只开HTTP层认证,transport层保持明文,配置
xpack.security.transport.ssl.enabled: false。
5.3 防火墙配置
麒麟V10默认可能开启firewalld。放行ES端口:
firewall-cmd --permanent --add-port=9200/tcp firewall-cmd --permanent --add-port=9300/tcp firewall-cmd --reload实操心得:9300是transport端口,集群节点间通信必须放行,很多人只放9200结果节点加不进来,排查半天。
6. 常见问题与排查技巧实录
6.1 启动失败类问题
问题一:max virtual memory areas vm.max_map_count [65530] is too low
原因:内核参数没调。解决:sysctl -w vm.max_map_count=262144,并写入/etc/sysctl.conf持久化。
问题二:memory locking requested for elasticsearch process but memory is not locked
原因:bootstrap.memory_lock: true但systemd没给LimitMEMLOCK。解决:在service文件加LimitMEMLOCK=infinity,daemon-reload后重启。
问题三:can not run elasticsearch as root
原因:用root启动了。解决:切到esuser用户,或改service文件的User=字段。
问题四:failed to obtain node locks
原因:数据目录被上一个进程占用,或者属主不对。解决:ps -ef | grep elasticsearch确认没有残留进程,chown -R esuser:esuser /data/es。
6.2 集群类问题
问题五:节点加不进集群
排查顺序:
discovery.seed_hosts里的IP和端口是否可达(telnet测试9300)cluster.name是否一致- 防火墙是否放行9300
- 节点名是否和
cluster.initial_master_nodes里的一致
问题六:集群状态yellow
单节点部署时副本分片无法分配是正常的,因为副本不能和主分片在同一节点。解决:要么加节点,要么把索引副本数设为0:
curl -XPUT 'http://localhost:9200/索引名/_settings' -H 'Content-Type: application/json' -d '{"index":{"number_of_replicas":0}}'问题七:脑裂
ES 7.x之后用cluster.initial_master_nodes和多数投票机制防脑裂,只要配置正确基本不会出现。如果出现,检查是否有节点被网络隔离后又恢复,导致出现两个master。
6.3 性能类问题
问题八:写入慢
排查方向:
- 是否开了
refresh_interval过短(默认1s,批量写入时可临时调大) - 是否
translog同步策略过于频繁(index.translog.durability设为async可提升写入) - 磁盘是否成为瓶颈(
iostat -x 1看%util)
问题九:查询慢
- 检查是否有大量
wildcard查询 - 检查分片数是否过多(单分片建议30-50GB)
- 检查是否有深分页(
from+size超过10000会报错,需要用search_after)
6.4 麒麟V10特有问题
问题十:SELinux拦截
如果日志里出现avc: denied,用:
ausearch -m avc -ts recent查看被拦截的操作,然后用audit2allow生成策略:
ausearch -m avc -ts recent | audit2allow -M es_policy semodule -i es_policy.pp问题十一:自带JDK不兼容
如果启动报GLIBC_2.xx not found,说明系统glibc版本低于JDK要求。解决:升级系统glibc(风险高),或换用系统JDK(需验证ES兼容性)。我实测麒麟V10 SP2的glibc版本是够的,SP1可能需要额外处理。
7. 我个人的部署体会
整套流程走下来,最耗时间的不是ES本身的配置,而是麒麟V10环境适配那部分——依赖包、SELinux、systemd资源限制,这三块占了排查时间的七成。ES的配置项其实很成熟,官方文档也全,照着填基本不会错,但系统层的坑是文档里不会写的。
如果让我给一个最省事的部署顺序,我会这样排:先调内核参数和limits,再建用户和目录,然后解压安装包改配置,最后systemd托管启动。这个顺序的好处是每一步都能独立验证,出问题容易定位。反过来,如果先启动再回头调系统参数,往往要反复重启,效率低很多。
另外提一个容易被忽略的点:ES的数据目录一定要放在独立磁盘上,而且最好是SSD。我见过把数据目录和系统盘放一起的,日志一多直接把根分区写满,整个系统都卡死。这个坑在测试环境不明显,一上生产就暴露。
最后分享一个小技巧:部署完成后,用curl -XGET 'http://localhost:9200/_nodes/stats?pretty'把节点状态导出来存一份,作为基线。以后性能出问题时对比这份基线,能快速看出是哪个指标异常。这个习惯帮我省了很多排查时间。