国产ARM64服务器银河麒麟V10 SP1部署Elasticsearch实战
1. 为什么要在国产 ARM64 服务器上折腾 Elasticsearch先把场景说清楚。我手头有一批基于国产处理器的服务器跑的是银河麒麟高级服务器操作系统 V10 SP1架构是 ARM64。业务侧需要一个全文检索和日志聚合的能力选型上绕不开 Elasticsearch。很多人第一反应是这玩意儿不是 x86 上跑跑就行了吗但真到了国产化环境里从 JDK 到系统参数再到安装包处处都是坑。这篇东西就是把我从零到一把 Elasticsearch 跑起来、跑稳的整个过程摊开讲。核心关键词就三个银河麒麟 V10 SP1、ARM64 架构、Elasticsearch。适合谁看一是正在做国产化替代、需要在 ARM 服务器上部署搜索/日志组件的运维和开发二是对 ARM 生态感兴趣、想了解 x86 与 ARM 在中间件部署上差异的技术人三是被官方文档只讲 x86坑过、想找一份能直接抄作业的实战记录的人。先说结论性的判断Elasticsearch 在 ARM64 上跑本身没有原理性障碍因为 ES 是 Java 写的JVM 早就支持 ARM64 了。真正的难点不在 ES 本身而在操作系统层面的适配——麒麟的系统源、依赖库版本、内核参数、以及那个让人又爱又恨的 systemd 服务管理。把这些理顺了剩下的就是常规的调优。我踩过的最大一个坑是直接拿 x86 的安装包往 ARM 机器上怼结果自然是跑不起来。ARM64 和 x86_64 的二进制完全不兼容必须用对应架构的发行包。这个道理很简单但急起来真的会忘。所以第一步永远是确认架构别嫌麻烦。2. 部署前的环境确认与依赖梳理2.1 先摸清家底系统与架构核对动手之前先把机器的底细摸清楚。我习惯用几条命令一次性确认避免后面反复回来查。# 确认系统版本 cat /etc/kylin-release # 确认内核版本 uname -r # 确认 CPU 架构这一步最关键 uname -m # 确认内存和磁盘 free -h df -huname -m的输出必须是aarch64。如果显示x86_64那说明你登错机器了或者这台根本不是 ARM 服务器。银河麒麟 V10 SP1 在 ARM 上对应的就是 aarch64这个别搞混。内存这块我要多嘴一句。Elasticsearch 是吃内存的大户官方建议单节点至少 4GB但那是能跑起来的底线。实际生产环境我建议堆内存给到物理内存的一半但绝对不要超过 31GB。为什么是 31GB因为 JVM 在堆内存超过约 32GB 时会关闭指针压缩Compressed OOPs反而导致性能下降和内存浪费。这是个经典陷阱很多人以为堆越大越好结果适得其反。磁盘方面ES 的索引数据增长很快尤其是日志场景。我一般会单独挂一块数据盘给 ES 用避免和系统盘抢 IO。麒麟系统默认的磁盘调度策略对 SSD 不一定最优后面调优章节会讲。2.2 JDK 的选择别用系统自带的这是 ARM64 环境里第一个大坑。银河麒麟 V10 SP1 系统源里自带的 OpenJDK 版本往往偏旧而且有些是给系统组件用的定制版直接拿来跑 ES 可能遇到各种诡异问题。我的做法是自己装一个干净的 OpenJDK和 ES 绑定使用。ES 从 7.x 开始自带 JDK 捆绑包在jdk目录下理论上可以不用管系统 JDK。但如果你用的是某些精简发行版或者自己编译的包就得手动指定。# 查看系统现有 java java -version # 查看 java 安装路径 which java readlink -f $(which java)我实测下来ES 7.17 和 8.x 系列在 ARM64 上配合其自带的 JDK 是最省心的。如果你非要指定外部 JDK记住两个原则一是版本要匹配ES 7.x 用 JDK 11ES 8.x 用 JDK 17二是必须是 ARM64 版本的 JDKx86 的 JDK 在 aarch64 上根本装不上。提示不要试图用apt install openjdk-11-jdk这种方式装 JDK 然后指望 ES 自动识别。ES 对 JDK 的查找路径有自己的逻辑最稳妥的是用ES_JAVA_HOME环境变量显式指定。2.3 系统依赖与内核参数预调Elasticsearch 对系统资源有硬性要求不满足直接启动失败。这些要求在 x86 和 ARM64 上是一样的但麒麟系统的默认值往往偏保守需要手动改。第一个是文件描述符限制。ES 会打开大量文件句柄默认的 1024 远远不够。# 临时生效 ulimit -n 65536 # 永久生效编辑 /etc/security/limits.conf * soft nofile 65536 * hard nofile 65536第二个是虚拟内存映射数。ES 使用 mmap 方式读取索引文件需要足够的max_map_count。# 查看当前值 sysctl vm.max_map_count # 临时修改 sysctl -w vm.max_map_count262144 # 永久修改写入 /etc/sysctl.conf echo vm.max_map_count262144 /etc/sysctl.conf第三个是线程数限制。ES 会创建大量线程需要放开nproc。# /etc/security/limits.conf 追加 * soft nproc 4096 * hard nproc 4096这里有个麒麟特有的注意点麒麟系统的 PAM 配置和某些通用发行版略有差异改完limits.conf后必须重新登录或者重启相关服务才生效。我有一次改完直接systemctl restart发现没生效折腾半天才发现是会话没刷新。用ulimit -a确认一下当前会话的实际值别只看配置文件。3. Elasticsearch 安装包获取与 ARM64 适配3.1 安装包从哪来架构必须对号入座Elasticsearch 官方提供多种架构的 tar.gz 和 rpm 包。ARM64 对应的是aarch64后缀的包。下载页面里通常会让你选平台选 Linux aarch64 就对了。如果你在内网环境没法直接下载那就得提前在能上网的机器上下好再传进去。传输过程中注意校验文件完整性我一般用 sha512 校验# 下载校验文件 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.9-linux-aarch64.tar.gz.sha512 # 校验 shasum -a 512 -c elasticsearch-7.17.9-linux-aarch64.tar.gz.sha512校验这一步别省。内网传输、U盘拷贝都可能出问题一个字节的损坏就能让你排查半天。3.2 解压与目录规划别放系统盘我习惯把 ES 装在独立的数据盘上比如/data/elasticsearch。这样做的好处是索引数据增长不会撑爆系统盘而且备份、迁移都方便。# 创建目录 mkdir -p /data/elasticsearch # 解压 tar -zxvf elasticsearch-7.17.9-linux-aarch64.tar.gz -C /data/elasticsearch --strip-components1 # 创建专用用户ES 不允许 root 运行 useradd esuser chown -R esuser:esuser /data/elasticsearchES 不允许以 root 身份运行这是硬性安全策略。所以必须建一个普通用户。这个用户不需要登录权限useradd默认就行。目录结构上重点关注几个目录用途注意事项bin启动脚本包含elasticsearch主程序config配置文件elasticsearch.yml和jvm.options在这data索引数据建议软链到独立数据盘logs日志增长快注意清理策略jdk捆绑 JDKARM64 版本别乱动3.3 配置文件的核心改动config/elasticsearch.yml是主配置。单节点场景下我一般改这几项# 集群名单节点也建议起个有意义的名字 cluster.name: kylin-es-cluster # 节点名 node.name: node-1 # 数据目录指向独立盘 path.data: /data/es-data # 日志目录 path.logs: /data/es-logs # 绑定地址0.0.0.0 表示监听所有网卡 network.host: 0.0.0.0 # 对外端口 http.port: 9200 # 集群发现单节点就写自己 discovery.seed_hosts: [127.0.0.1] cluster.initial_master_nodes: [node-1]network.host设成0.0.0.0后ES 会进入生产模式会触发一系列更严格的检查比如必须配置发现机制。如果你只是本地测试可以设成127.0.0.1进入开发模式检查会宽松很多。但生产环境必须用生产模式别图省事。jvm.options里改堆内存-Xms16g -Xmx16g这两个值必须相等避免运行期动态调整带来的性能抖动。16g 是我根据 32g 物理内存给的你们按自己机器来。4. 启动、验证与常见启动失败排查4.1 首次启动用前台模式看日志第一次启动我强烈建议不要直接后台跑而是前台启动把日志直接打在屏幕上。这样任何报错都能第一时间看到。su - esuser cd /data/elasticsearch ./bin/elasticsearch如果一切正常你会看到一堆日志滚动最后出现started字样。这时候另开一个终端验证curl -X GET http://localhost:9200/?pretty返回类似这样的 JSON 就说明成功了{ name : node-1, cluster_name : kylin-es-cluster, version : { number : 7.17.9, build_flavor : default, build_type : tar } }4.2 启动失败速查表ARM64 麒麟环境里启动失败的原因就那么几类。我整理成表方便对照排查。报错关键词根本原因解决方法max file descriptors文件描述符不足改 limits.conf重登录max virtual memory areasmax_map_count 太小sysctl 调大can not run elasticsearch as root用 root 启动了切普通用户unable to lock JVM Memory内存锁定失败关闭 bootstrap.memory_lock 或调大 memlockNo such file or directory架构不匹配或路径错确认 aarch64 包BindException端口被占用查 9200/9300 端口failed to obtain node locks数据目录被锁确认没有残留进程我遇到最多的是内存锁定失败。ES 默认会尝试锁定堆内存防止被交换到磁盘。但麒麟系统默认的memlock限制可能是 unlimited 也可能是很小的值。如果你不想折腾直接在elasticsearch.yml里关掉bootstrap.memory_lock: false关掉的代价是极端情况下堆内存可能被换出影响性能。生产环境建议还是把 memlock 调大# /etc/security/limits.conf esuser soft memlock unlimited esuser hard memlock unlimited4.3 配置 systemd 服务让它开机自启前台跑通之后就该配成系统服务了。麒麟用的是 systemd写一个 unit 文件即可。# /etc/systemd/system/elasticsearch.service [Unit] DescriptionElasticsearch Afternetwork.target [Service] Typesimple Useresuser Groupesuser EnvironmentES_JAVA_HOME/data/elasticsearch/jdk ExecStart/data/elasticsearch/bin/elasticsearch Restarton-failure LimitNOFILE65536 LimitNPROC4096 LimitMEMLOCKinfinity [Install] WantedBymulti-user.target几个关键点LimitNOFILE这些限制必须写在 unit 文件里因为 systemd 启动的服务不读limits.conf。这是很多人配完服务发现限制没生效的原因。ES_JAVA_HOME显式指向捆绑 JDK避免系统 JDK 干扰。systemctl daemon-reload systemctl enable elasticsearch systemctl start elasticsearch systemctl status elasticsearch5. 性能调优与 ARM64 特有经验5.1 内存与 GC 调优ES 的性能很大程度上取决于 JVM 的 GC 表现。ES 7.x 默认用 G1 GC这个在 ARM64 上表现也不错。但有几个参数值得关注。在jvm.options.d目录下建一个自定义文件比如custom.options-XX:UseG1GC -XX:MaxGCPauseMillis200 -XX:G1ReservePercent25 -XX:InitiatingHeapOccupancyPercent30MaxGCPauseMillis是目标停顿时间G1 会尽量达成但不是硬保证。设太小会导致 GC 更频繁反而降低吞吐。200ms 是个比较平衡的值。ARM64 的 CPU 核数往往比同价位 x86 多这对 GC 的并行阶段是好事。但要注意GC 线程数默认是根据 CPU 核数自动算的核太多反而可能造成线程争抢。如果发现 GC 日志里并行阶段耗时异常可以手动限制-XX:ParallelGCThreads8 -XX:ConcGCThreads45.2 磁盘与文件系统麒麟系统默认的文件系统可能是 ext4 或 xfs。对 ES 来说xfs 通常表现更好尤其是在大文件读写场景。如果条件允许数据盘格式化成 xfs。挂载参数上我一般加noatime减少不必要的元数据写入/dev/sdb1 /data xfs defaults,noatime 0 0另外ES 的索引写入是顺序写为主但段合并merge会产生大量随机 IO。SSD 上这个问题不明显机械盘上就要注意了。如果用的是机械盘建议把index.merge.scheduler.max_thread_count调低减少并发合并对 IO 的冲击。5.3 ARM64 上的实测感受说点主观的。同样的 ES 版本、同样的配置在 ARM64 和 x86_64 上跑单次查询的延迟差异不大因为 ES 的瓶颈通常在 IO 和内存而不是 CPU 指令集。但在高并发写入场景下ARM64 的多核优势能体现出来吞吐量反而可能更高。不过有个细节要注意某些第三方插件尤其是带 native 代码的可能没有 ARM64 版本。装插件前一定确认架构支持别装完了启动报UnsatisfiedLinkError。这是 ARM 生态目前的普遍问题不是麒麟特有的。6. 运维实操日常巡检与故障处理6.1 集群健康度巡检日常运维我每天必看几个指标。用_cluster/health看整体状态curl -X GET http://localhost:9200/_cluster/health?pretty重点看status字段green正常yellow表示有副本分片未分配单节点正常现象red表示有主分片丢失必须处理。再看_cat/indices看索引状态curl -X GET http://localhost:9200/_cat/indices?vsstore.size:desc按存储大小排序快速定位大索引。日志类索引如果无限增长迟早撑爆磁盘必须配 ILM索引生命周期管理或者定期清理。6.2 常见故障处理实录故障一磁盘写满导致 ES 只读。这是最经典的故障。ES 检测到磁盘使用率超过 95%默认cluster.routing.allocation.disk.watermark.flood_stage会把索引设为只读。处理方法是先清磁盘再解除只读# 解除只读 curl -X PUT http://localhost:9200/_all/_settings -H Content-Type: application/json -d { index.blocks.read_only_allow_delete: null }预防措施是提前配好水位线告警别等写满了才发现。故障二节点频繁掉线。如果 ES 进程莫名其妙消失先看系统日志dmesg很可能是被 OOM Killer 杀了。堆内存设太大、物理内存不够系统就会杀进程。解决办法是给堆内存留足余量物理内存至少是堆的 2 倍。故障三查询变慢。先看是不是段太多。段数量过多会导致查询要扫描大量小文件。可以强制合并curl -X POST http://localhost:9200/your-index/_forcemerge?max_num_segments1但 forcemerge 很吃 IO别在业务高峰期做而且对正在写入的索引不要做。6.3 备份与恢复ES 的备份用快照snapshot。先注册一个快照仓库curl -X PUT http://localhost:9200/_snapshot/my_backup -H Content-Type: application/json -d { type: fs, settings: { location: /data/es-backup, compress: true } }然后创建快照curl -X PUT http://localhost:9200/_snapshot/my_backup/snapshot_1?wait_for_completiontrue恢复的时候注意目标索引必须不存在否则会冲突。这个机制是为了防止误覆盖但第一次用的人容易懵。7. 我踩过的坑和给你的建议最后聊点实在的。这套环境我前后搭了不下五次每次都有新发现。第一个坑是别信一键脚本。网上有些针对 x86 的自动化部署脚本直接拿到 ARM64 上跑轻则报错重则把系统配置改乱。国产化环境里手动一步步来反而最快。第二个坑是麒麟的系统源更新要谨慎。有次我为了装个依赖apt upgrade了一把结果把系统自带的某个库升级了导致另一个业务组件挂了。ES 本身不依赖系统库太多但如果你在同一台机器上跑别的服务升级前一定想清楚影响面。第三个坑是时间同步。ES 集群对时间敏感节点间时间差太大会导致各种诡异问题。麒麟默认可能没开 NTP记得配上timedatectl set-ntp true timedatectl status第四个坑是别忽略日志。ES 的日志分好几类elasticsearch.log是主日志gc.log是 GC 日志deprecation.log是废弃 API 警告。我习惯每天扫一眼 gc.logGC 频繁或者停顿时间长都是性能问题的前兆。关于版本选择我的建议是生产环境用 7.17.x 的最后一个稳定版别追新。8.x 改动大很多 API 和配置不兼容国产化环境里第三方工具链的适配也未必跟得上。等生态成熟了再迁。这套东西跑起来之后其实挺稳的。ARM64 的算力和麒麟的稳定性应付中等规模的检索和日志场景完全够用。关键是把前面那些系统层面的细节抠到位剩下的就是常规运维了。