资讯详情

Elasticsearch Serverless无状态架构:计算存储分离解决集群扩缩容难题

📅 2026/9/30 3:00:05 | 华诺云谱 👁 阅读
Elasticsearch Serverless无状态架构:计算存储分离解决集群扩缩容难题
手头有个搜索和日志分析的场景数据量说大不大说小不小但业务波动特别明显——白天高峰和夜间低谷能差几十倍。用传统 Elasticsearch 集群扛这种流量要么常年空转浪费资源要么扩容速度跟不上突发流量。后来我把项目迁到了 Elasticsearch Serverless 架构上核心思路就是无状态化计算节点不保存任何持久数据所有数据都落到远程共享存储这才算彻底解决了我的痛点。这篇文章不聊PPT式的架构演进就从我实际迁移和运维的视角把 Elasticsearch Serverless 到底怎么做到无状态、数据怎么流动、部署时要注意什么、遇到问题怎么排查一条线讲清楚。无论你是刚开始接触 ES 的新手还是在为集群扩缩容发愁的老手这篇应该都能给你一些可以直接落地的参考。1. 传统集群的痛点以及无状态架构的解题思路1.1 传统 Elasticsearch 集群为什么难伺候先说结论传统 ES 集群的痛点几乎全来自状态这两个字。所谓状态就是节点本地保存了数据、分片、副本、集群元数据。每个数据节点都要维护自己的分片副本又要把分片状态和集群状态保持一致这让节点变得非常重。我举个例子一个 3 节点的集群每新增一个节点新节点要先把分片数据拷贝过去集群要做数据再平衡rebalance这个过程对磁盘 IO 和网络带宽的消耗都很大。而且节点挂了之后其它节点要重新分配副本稍有疏忽就容易出现 yellow 或 red 状态。另一个绕不开的问题是扩缩容。业务流量涨了你想把集群从 5 个节点扩到 20 个节点正常情况下必须等待分片迁移完成这个等待时间往往以小时计。反过来流量降下来想缩容还得小心翼翼地把某个节点上的分片先移走否则又会出现数据丢失风险。这种操作非常依赖运维经验不敢轻易自动化。还有单分片容量、副本数、磁盘空间、内存分配这些规划问题。我印象很深的一回集群里一个索引的分片计划定得太粗结果半年后单分片撑到了接近 40GB查询速度明显下降但那时候再改分片数就得重建索引相当痛苦。这些运维负担说到底是等价的你选择了有状态的数据持久化方式就要接受带状态的管理成本。1.2 无状态架构无掉的是数据节点里的持久数据Elasticsearch Serverless 的核心设计思路不是把 Elasticsearch 功能砍掉而是把数据存储从计算节点上彻底剥离出来。传统架构里一个数据节点的本地磁盘就承担着分片数据的持久化任务。无状态架构则完全不同数据节点本质上只是一台计算资源它本地不保存任何必须长期保留的数据所有分片数据都以 segment 文件的形式写入远程共享存储比如对象存储或者共享文件系统。节点本地的磁盘只用来放缓存和临时文件随时可以被清空、被替换。这就像把一间小卖部改成了中央仓库加临时摊位。摊位只负责把商品摆出来卖商品本身都锁在仓库里。摊位烧了、搬了换一个摊位继续卖就行不用一箱箱把货搬走。落到 Elasticsearch 的实现上数据节点启动时不需要从其它数据节点复制数据只需要从远程存储读取分片元数据和 segment 文件。所以新节点加入集群几乎秒级完成。节点异常退出也没有影响——它本身没有必须抢救的数据顶多是本地缓存丢失重新从远程存储拉一遍就好。1.3 什么场景适合无状态什么场景不建议我自己的判断标准很简单如果你的业务有明显的流量波峰波谷或者你想让一套搜索/日志系统能按需伸缩那 Serverless 无状态架构非常合适因为它把资源成本和数据副本解耦了。反过来说如果你的数据量很小、流量常年平稳、团队对传统 ES 运维已经很熟练那就没必要引入这套复杂度。加一个远程存储引入新的网络开销和配置项带来的收益并不明显。小集群上传统架构完全够用硬上一个无状态架构反而增加故障点。另外要注意无状态架构对网络带宽和远程存储的读写性能要求很高。如果你所在机房到对象存储的延迟超过几十毫秒查询和写入都会明显变慢。这一点在规划阶段就得想清楚。2. 核心设计拆解计算存储分离背后的三层角色2.1 三层角色分裂协调、数据与存储Elasticsearch Serverless 的逻辑架构我习惯分成三层来看。第一层是协调层Coordinator。它负责接收客户端请求解析查询做权限校验把请求路由到合适的数据节点然后汇总结果返回。协调层本身不存数据也不做数据持久化所以它可以非常轻量地做水平扩展。第二层是数据节点层Data Node。这是干活的角色负责执行写入、查询、聚合。每个数据节点在收到请求后会操作本地的缓存数据如果缓存未命中就去远程存储拉取相应的 segment。数据节点没有任何持久化存储的义务它可以随时销毁重建。第三层是存储层Storage。也就是远程共享存储保存了所有索引的 segment 文件、translog 以及分片元数据。这一层才是整个集群唯一的状态持有者。存储层通常由对象存储承担它天然具备高可用性、高持久性以及无限扩展能力。传统 ES 的分片有主备副本概念在无状态架构里发生了变化。副本不再是完整的数据拷贝而是同一份 segment 文件在远程共享存储上的不同引用方式。数据节点不需要各自持有一份完整副本避免了很多一致性问题。2.2 数据到底怎么进入仓库要理解数据写入流程我们先说 Elasticsearch 中的一个核心概念segment段。ES 中每个分片的数据实际是由若干不可变的 segment 文件组成的新写入的数据先进入内存 buffer等到满足刷新条件默认 1 秒后生成一个新 segment再经过合并merge把多个小 segment 合并成一个大 segment。在有状态的传统架构里这些 segment 直接写进节点本地磁盘。在无状态架构里segment 生成之后会被上传到远程共享存储节点本地只保留最近一小部分热数据的缓存。至于 translog事务日志为了保证写入不丢同样会同步到远程存储。所以数据写入的链路大概是这样客户端请求到达协调层协调层路由给某个数据节点数据节点写 translog 并写入内存 bufferperiodic flush 后生成 segment再把 segment 和 translog 上传远程存储最后返回客户端写入成功。这里实际上做了一个很重要的取舍用一次远程网络写入来换取数据节点的完全无状态。如果你的业务写入量特别大、对 p99 延迟要求又非常苛刻这种设计相对传统本地写入确实多了网络开销这也是为什么无状态架构更适合流量可弹性伸缩 对延迟不是极度敏感的场景。2.3 为什么必须要一个远程共享存储很多刚接触无状态架构的同事会问我能不能用数据节点之间的复制来替代远程存储答案是否定的。无状态的前提是节点随时可以被替换。如果数据还是放在某个节点的本地磁盘那节点挂了数据就持有状态的那部分就丢了。远程共享存储之所以必要是因为它是集群全体节点都能访问、且不依赖于某一个具体节点存活的公共底座。数据只要进了远程存储业务计算节点再怎么增减数据都在。从实现层面看远程共享存储可以理解为一个大得多的分布式文件系统但它和本地文件系统有一个明显的不同它不保证低延迟的随机写。所以 Elasticsearch 在无状态架构里会把写操作尽量合并成较大的 segment 文件再上传减少小文件频繁上传的开销。这也是为什么无状态 ES 通常会调整合并策略和刷新频率让 segment 足够大、数量足够少。3. 无状态架构与传统架构的对比与选型判断3.1 一张表看懂两者的关键差异对比项传统 ES 架构Serverless 无状态架构数据持久化位置节点本地磁盘远程共享存储对象存储等节点故障影响需要重新分配分片集群可能变红节点被替换数据从远程恢复扩容速度依赖分片迁移分钟到小时级秒级拉起新节点缩容复杂度需迁移分片并规避数据丢失风险直接销毁节点即可存储弹性受限于节点磁盘配额独立扩展几乎无限计算/存储耦合高度耦合规划困难完全解耦按需分配成本模型按节点固定成本付费按实际计算资源和存储用量付费运维深度需要专业 ES 运维经验平台托管为主运维成本低延迟敏感度适合对延迟极度苛刻的场景多一层网络开销延迟略高3.2 从几个核心指标看架构变化我最直观的感受在三个方面第一扩容时间从小时级变成分钟级。以前加节点分片迁移要等磁盘 IO 一点点搬现在新节点启动后直接从远程存储加载元数据只要计算资源到位基本上两三分钟就能接入集群服务查询。第二CPU 和磁盘不再绑定。传统架构里磁盘满了往往 CPU 还很闲想加计算能力就不得不扩大磁盘造成浪费。无状态架构下存储独立扩展计算资源按需增减成本模型更精确。第三故障恢复的心态变了。以前晚上收到节点宕机告警第一反应是分片有没有损坏、副本能不能顶上。现在节点宕机对我而言只是少了一台计算资源远程存储里的数据还在我完全不慌。这种心态上的转变实际上就是架构稳定性提升的体现。3.3 选型判断什么情况下可以迁移我建议你按这三步来做判断第一步评估流量特征。如果一天的流量波动超过 3 倍或者未来有比较明显的增长预期无状态架构的价值就很大。第二步评估延迟需求。你的业务查询响应要求是几百毫秒级别还是秒级如果要求极端的低延迟且数据量不大传统架构反而更稳。第三步评估团队能力。你们有没有专门的 ES 运维人力如果没有选择托管式的 Serverless 服务能节省很多精力如果有那也可以基于开源组件自建无状态集群但那个复杂度和运维成本就不低了。4. 实操记录本地启动与服务部署的完整过程4.1 Windows 本地启动 Elasticsearch 的注意点说实话网上说Windows 启动 Elasticsearch的教程很多但踩坑的细节没几个人讲清楚。第一步是准备 JDK。Elasticsearch 7.17 之后的版本内置了捆绑的 JDK但建议你还是单独安装一个 JDK 并配置好环境变量方便后续操作和排查。这里有个我踩过几次的坑如果你机器上装过其它软件环境变量里的 PATH 顺序可能导致 ES 用了错误版本的 Java建议在命令行里先执行java -version确认版本。第二步是下载对应版本的安装包。尽量在官方渠道下载不要用不明来源的整合包。下载 zip 包后解压注意路径不要包含中文和空格否则后续脚本执行容易出问题。第三步是修改配置。在config/elasticsearch.yml里本地单机测试至少要把discovery.type设置为single-node否则默认的zen发现机制会尝试找其它节点一直在 bootstrap 阶段卡住。内存设置方面在config/jvm.options里把-Xms和-Xmx设为一样大小避免运行时堆扩容的停顿建议设为本机物理内存的一半左右比如 8GB 内存的机器就设 4GB。第四步是启动。Windows 下直接运行bin/elasticsearch.bat然后访问http://localhost:9200能得到一个 JSON 响应就说明启动成功了。这里我可以给一段最小启动步骤清单下载 zip 包并解压配置JAVA_HOME环境变量修改config/elasticsearch.yml设置cluster.name和discovery.type: single-node设置jvm.options里的堆内存执行bin\elasticsearch.bat启动访问http://localhost:9200验证4.2 Serverless 部署的配置与验证流程当你准备部署到 Serverless 环境事情就从装一个单机进程变成了管理一套自动伸缩的计算集群。我用过的 Serverless 部署方式主要面向云厂商托管服务或者基于容器平台自建。先说托管方式。通常你只需要创建一个 Serverless 项目填入要支持的地域、数据归属和网络配置剩下的数据节点数量、分片分配都由平台自动搞定。部署完可以直接拿到一个专用的接入地址体验非常清爽。如果是自建我会建议把数据节点做成容器化工作负载让它跑在支持横向扩容的容器平台上。部署的关键点有三处第一处节点配置里要指定远程存储的地址和认证信息。比如在elasticsearch.yml里配置对象存储的 endpoint、bucket 和密钥这些是数据节点连接远程存储的桥梁。第二处必须保证所有配置的不变性。节点镜像一旦构建好运行参数不再修改要变就重新构建镜像。这样节点挂了被替换时新起的节点就和旧的完全一样这是无状态部署的基础。第三处要配置数据节点的存活探针。平台应该能够定期检查节点健康状态一旦发现节点异常立刻拉一个新的节点替换而不需要人工介入。部署完成后的验证我建议做三步检查第一步确认所有节点都能从远程存储读取分片元数据可以在数据节点的启动日志里看到recovered相关记录。第二步随机杀掉一个节点确认平台自动恢复后查询服务没有出现长时间中断。第三步人为打入少量索引数据然后删除一个节点再看数据是否能正常检索以确认数据确实持久化在远程存储上。4.3 与 Spring Boot 集成时需要注意的几个参数服务端部署好之后实际业务应用接入时最常见的就是 Spring Boot 项目。我通常用spring-data-elasticsearch配合 REST High Level Client 或者新版的ElasticsearchClient。集成时我最推荐直接使用官方的 transport 客户端或 REST 客户端因为它对 Spring Boot 生态兼容性好参数调整也方便。比较重要的配置项有这么几个spring.elasticsearch.uris接入地址使用 Serverless 接入点时直接填为返回的 HTTPS URL。spring.elasticsearch.username/spring.elasticsearch.password认证信息。spring.elasticsearch.connection-timeout和socket-timeout如果集群处在不同的地域网络延迟偏高务必调大超时时间否则业务端很容易报ConnectionTimeOutException。集成时还要注意一个细节Serverless 环境通常会限制索引的自定义 mapping 不能随意变更推荐把 mapping 和 setting 的模板提前定义好。如果直接在业务代码里通过IndexRequest动态建索引可能会出现字段类型和模板不一致的报错。我一般会在项目里放一份索引映射的初始化脚本部署新环境时先执行一次避免奇奇怪怪的字段类型问题。5. 无状态架构下的读写流程与故障恢复逻辑5.1 写入流程从协调层到远程存储无状态架构下一次典型的写入请求经过的链路如下客户端把写入请求发到协调节点。协调节点对请求做解析、鉴权和路由找到合适的索引主分片所在的数据节点。数据节点接收请求后先写 translog再写入内存 buffer。当 buffer 达到一定大小或时间达到刷新阈值触发 flush生成一个新的 segment。这个 segment 紧接着被上传到远程共享存储。等远程存储确认接收成功写入请求才会返回成功。这段链路里我最在意的是 translog 和 segment 的安全。translog 如果丢了内存 buffer 里的数据就丢了segment 如果没传到远程存储这个分片就等于没有持久化成功。因此无状态架构对这两个操作的同步要求比较严格通常会等远程存储返回 ACK 之后再给客户端发成功响应。5.2 查询流程缓存与远程存储的取舍查询请求的路径和写入略有不同。客户端请求到协调节点后协调节点把查询广播到所有相关分片的数据节点。每个数据节点先在本地缓存里查找相关 segment本地没有的再去远程存储拉取。这里有一个取舍要注意如果本地缓存总是未命中几次查询之后缓存会逐渐暖起来后续延迟会下降但如果查询范围跨越大量 segment远程存储的随机读会被放大。所以我在配置无状态集群时会优先保证频繁查询的索引足够小并且设置合理的 segment 合并策略减少落到远程读的次数。5.3 故障恢复演示从节点消失到业务无感这是我觉得无状态架构最优秀的地方。假设某个数据节点因为硬件故障突然宕机传统架构此时要经历主分片重选举、副本重分配、数据重新复制无状态架构里协调层会把这个节点标记为异常平台自动启动一台新数据节点。新节点启动时不需要从其它节点复制数据而是先从远程存储获取这个分片的元信息再用远程读取的方式直接对外提供服务。整个过程客户端感知到的可能就是个别请求的响应时间略微变长但不会出现整个索引不可查询的情况。我开始做迁移实验时做过一次破坏性测试在一个正常运行的无状态集群里直接杀掉所有数据节点结果因为消费端有连接重试机制节点恢复后数据依旧可查。这正是计算无状态、存储有状态的价值所在。6. 常见问题与排查技巧实录6.1 启动失败heap 设置和端口占用我碰到最多的启动失败场景本地调试时八成是 heap 设置得不合理或者端口被占用。如果你看到native thread creation failed之类的错误通常是线程数或内存超了。换个测试环境时先把jvm.options里的堆内存调小一点比如 512MB等启动成功再慢慢往上加。端口占用也很常见9200 和 9300 被占用时启动日志会直接报Address already in use。Windows 下用netstat -ano | findstr 9200找出占用进程手动处理掉就行。还有一点容易忽略ES 默认不允许以 root 身份在 Linux 下运行如果你正在容器里跑记得用非 root 用户运行。Windows 下没有这个限制但配置文件的权限要开放否则可能启动时报access denied。6.2 数据节点无法连接远程存储无状态架构里的一个高发问题数据节点配置了远程存储但启动后大量刷报错检查发现节点根本无法访问对象存储的 endpoint。排查思路我总结成一个顺序确认远程存储 endpoint 可以被数据节点的网络解析并且可以连通。在容器环境里做ping或curl测试。确认访问凭证配置正确。密钥信息如果放在环境变量里要检查数据节点的环境变量是否真的注入进去了。确认访问策略允许数据节点所在网络的读写操作。很多云环境要通过 VPC 或安全组规则放行相应端口和 IP。如果以上都没问题但节点还是报错检查一下本地时钟和远程服务器时钟的偏差时间偏差超过 5 分钟往往会导致请求签名校验失败。6.3 查询结果不全segment 与缓存机制有同事遇到过一个困惑数据写入几秒后查询偶尔会漏掉一部分新数据。我第一反应是查询默认的_refresh间隔。ES 默认 1 秒刷新刚写入的数据不会立刻对查询可见这是正常现象。如果你需要更强的实时性可以在写入后强制refreshtrue但代价是频繁刷新会生成大量小 segment影响后续查询性能不建议在批量写入场景使用。另一个点比较容易忽略无状态架构的本地缓存替换机制。当本地缓存打满节点会按策略淘汰部分 segment。如果查询落在被淘汰的 segment 上节点需要重新从远程存储加载这会表现为偶发的慢查询。所以查询耗时的曲线不应该只看平均值一定要观察 p99 分位值出现明显抖动时优先排查缓存命中率。6.4 我的排查工具与日常体检清单很多刚入行的朋友喜欢遇到问题就上论坛搜索我的习惯是先自己盯一套指标集群健康状态GET _cluster/health看status是不是 green。节点热点GET _nodes/hot_threads看数据节点的 CPU 热点。分片分配GET _cat/shards看有没有分片长时间处于 UNASSIGNED。缓存命中GET _nodes/stats重点看query_cache和request_cache的命中率。存储写入延迟针对远程存储做一次读写压测确认延迟是否在合理范围内。日常我是按周做一次体检查一遍集群健康、看看数据增长和分片数量、检查有没有频繁刷新的索引。这套习惯看起来简单但能帮我提前拦住不少问题。最后说点个人体会从传统集群迁到无状态架构我最大的收获不是省了多少运维时间而是想清楚了一个问题在分布式系统里状态放对位置比什么都重要。把数据状态集中到远程共享存储计算节点才能真正变成可丢弃的廉价资源。这个思路不只适用于 Elasticsearch很多大数据组件都在往这个方向走。如果你正准备上手我个人建议先从一个小规模的非核心业务开始。先在本地按单节点模式跑通再部署到 Serverless 环境然后逐步加数据量、加查询压力。不要一上来就把核心业务迁过去无状态架构虽然稳定但多了一层网络依赖你得先摸清自己业务对延迟和成本的边界在哪里。Windows 上启动 Elasticsearch 的坑、Serverless 部署的配置、Spring Boot 集成的注意点这些具体操作我在前面已经写得很细了。你照着走一遍大概率能顺利跑通。真碰到奇怪的问题再回头看看第 6 部分的排查清单基本能定位个八九不离十。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑