Elasticsearch 存算分离架构实战:基于 OpenStore 实现弹性伸缩与成本优化

Elasticsearch 存算分离架构实战:基于 OpenStore 实现弹性伸缩与成本优化

1. 项目概述:为什么我们需要“更快、更稳、更省”的 Elasticsearch?

如果你负责过线上业务的日志分析、商品搜索或者实时监控,那你对 Elasticsearch 一定不陌生。这个基于 Lucene 的分布式搜索引擎,以其强大的全文检索和聚合分析能力,几乎成了大数据实时处理的标配。但用久了,痛点也来了:数据量一上来,集群规模就得跟着涨,存储和计算资源像一对连体婴儿,必须同步扩容。想单独加几个节点提升查询性能?对不起,你得连带着把存储也扩了,成本一下就上去了。集群升级或者节点故障恢复,动辄数小时甚至数天的数据重平衡时间,运维窗口期和业务风险都让人头疼。

这正是“存算分离”架构要解决的核心问题。最近深度体验了阿里云 Elasticsearch 的存算分离方案,特别是其基于 OpenStore 的弹性能力,感触颇深。它把传统一体架构的“铁板一块”拆解开来,让计算资源和存储资源可以独立伸缩、按需付费。简单来说,你可以像用水用电一样,在业务高峰时快速拉起计算节点应对海量查询,在低谷时释放掉以节省成本,而底层的数据则安全、持久地存放在一个高可靠、低成本的对象存储池里,不受计算节点生命周期的影响。

这不仅仅是技术架构的演进,更是成本模型和运维模式的革新。对于追求“更快、更稳、更省”的团队来说,这意味着更敏捷的响应能力、更低的总体拥有成本(TCO)以及更轻松的运维体验。接下来,我就结合自己的实测和踩过的坑,把这套方案的里里外外拆解清楚。

2. 核心架构拆解:存算分离与 OpenStore 是如何工作的?

要理解阿里云的方案,得先抛开我们熟悉的本地磁盘存储模式。传统 Elasticsearch 集群中,每个数据节点(Data Node)都同时承担计算(执行查询、聚合)和存储(承载分片数据)的职责。数据分片(Shard)及其副本(Replica)就固定存储在对应节点的本地磁盘上。

2.1 从“存算一体”到“存算分离”的范式转变

在存算一体架构下,资源管理是刚性的。假设你的业务有很强的周期性,比如电商大促期间查询 QPS 是平日的 10 倍。为了应对峰值,你不得不按照峰值需求来配置数据节点的数量和规格(CPU/内存)。但大促过后,这些昂贵的计算资源大部分时间处于闲置状态,可因为数据绑死在本地磁盘上,你无法安全地缩容,造成了巨大的资源浪费。反之,如果数据增长过快,你需要扩容存储,也必须连带扩容计算资源,即使当前计算能力已经过剩。

存算分离架构将这种耦合解开:

  • 计算层:由专有的弹性计算节点组成,负责接收查询请求、执行搜索与聚合逻辑。它们是无状态的,可以随时创建、销毁或调整规格。
  • 存储层:由高可靠、高扩展、低成本的对象存储(如阿里云 OSS)及配套的缓存加速层构成,持久化保存所有索引数据。计算节点通过高速网络访问存储层的数据。

阿里云 Elasticsearch 的存算分离方案,其核心存储引擎就是OpenStore。你可以把它理解为一个智能的、为搜索场景深度优化的“数据湖”。它底层基于对象存储,但在此之上构建了多层缓存、索引优化和数据管理能力,使得远程访问数据的性能可以接近甚至在某些场景下超越本地 SSD 磁盘。

2.2 OpenStore 的智能分层与缓存加速机制

这是实现“更快”的关键。如果每次查询都要穿透到远端的对象存储去读取数据,那延迟将是无法接受的。OpenStore 设计了一套精巧的分层存储与缓存体系:

  1. 热数据层(内存缓存):最常被访问的索引数据(如最近几天的日志、热门商品信息)会被自动识别并缓存在计算节点的本地内存或高性能 SSD 上。查询命中这部分缓存时,速度与本地磁盘无异。
  2. 温数据层(共享 SSD 缓存池):这是一个由多个计算节点共享的、基于分布式块存储构建的高速缓存层。它容量比单节点内存大得多,用于存放访问频率中等的数据。计算节点可以通过低延迟网络访问这个共享池。
  3. 冷数据层(对象存储):全量的索引数据最终持久化在阿里云 OSS 中。OSS 本身具有 11 个 9 的数据持久性,成本极低。对于偶尔需要查询的历史数据,系统会按需从 OSS 加载到缓存层。

这个分层是动态、智能的。系统会根据数据的访问模式(频率、时序)自动调整数据在各级缓存中的位置,无需人工干预。例如,一个上周的日志索引,如果最近三天都没有查询,它可能会被逐渐从内存缓存降级到共享 SSD 缓存,甚至大部分数据块只保留在 OSS 中。当突然需要查询时,相关的数据块又会被快速“预热”到缓存中。

注意:OpenStore 的缓存策略是高度优化的,但初始查询冷数据时仍会有一定延迟。对于有严格 SLA 要求的追溯查询,建议通过定时任务或预加载 API 提前将相关索引或分片“pin”在缓存中。

2.3 弹性扩缩的底层支撑:无状态计算与共享存储

架构分离后,弹性扩缩才成为可能。

  • 弹性扩容(Scale-Out):当监控到查询延迟升高或 CPU 使用率持续高位时,你可以通过控制台或 API,在几分钟内增加指定数量或规格的计算节点。新节点启动后,会自动接入集群,并从共享存储(OpenStore)中获取集群元数据和缓存热点数据,迅速开始分担查询负载。无需进行任何数据分片的迁移和再平衡,这是与传统扩容天壤之别的地方。
  • 弹性缩容(Scale-In):在业务低峰期,你可以安全地移除部分计算节点。系统会先将这些节点上的查询请求引流到其他节点,然后优雅地将其下线。由于数据不在本地,下线节点不会触发任何数据恢复流程,缩容过程快速且平滑。
  • 存储自动扩容:存储容量由底层的 OSS 保障,几乎是无限的。你只需要为实际存储的数据量和请求次数付费,无需提前规划存储盘。索引创建、写入数据时,存储空间自动扩展。

这种模式使得资源利用率最大化。计算资源真正做到了“按需使用”,再也不用为未来的数据增长或不确定的业务峰值提前支付大量的硬件预留成本。

3. 实操指南:如何配置与启用存算分离集群?

理论讲完了,我们来看看具体怎么用。这里我以创建一个新的存算分离集群为例,并分享一些关键配置项的取舍经验。

3.1 集群创建与关键配置选择

在阿里云 Elasticsearch 控制台创建实例时,选择“存算分离”版本。

  1. 计算节点组配置

    • 节点规格:这里的选择逻辑和传统集群不同。由于计算节点不负责持久化数据,其本地磁盘主要用作系统盘和临时缓存,因此不需要配置大容量云盘。重点应放在vCPU 和内存上。对于重查询/聚合场景,内存尤为重要,因为更多的内存意味着更大的 Lucene 段文件缓存(Operating System Cache),能极大提升查询速度。我一般会从 8核16GB 或 16核32GB 的规格起步。
    • 节点数量:初始阶段可以保守一点,例如 2 个节点。因为后续扩缩容非常方便,你可以根据监控指标动态调整。存算分离集群至少需要 2 个计算节点来保证高可用。
  2. OpenStore 存储配置

    • 存储类型:通常选择“标准存储”即可,它平衡了性能和成本。如果对查询性能有极致要求,且预算充足,可以考虑“高性能存储”类型,它对应着更快的底层存储介质和更强的缓存能力。
    • 单节点存储容量:这个参数容易让人困惑。它不是指每个计算节点的本地磁盘大小,而是指每个计算节点可访问的共享缓存容量配额。例如,你设置单节点存储容量为 500GB,集群有 2 个节点,那么你这个集群在共享 SSD 缓存池中总共拥有 1TB 的缓存空间。这个缓存用于存放热数据和温数据。设置多大取决于你的热点数据集大小。一个实用的估算方法是:你希望常驻高速缓存的数据量(如最近7天的索引大小)除以计算节点数。
  3. 网络与安全

    • 专有网络 VPC:务必让 Elasticsearch 集群和你的应用服务器处于同一个 VPC 内,这是保证网络低延迟、高安全性的基础。
    • 公网访问:如非必要,不要开启。通过阿里云的私网连接(如 ECS 内网访问)或 PrivateLink 进行访问。

3.2 索引生命周期管理与数据分层策略

启用存算分离后,索引生命周期管理(ILM)变得更加重要和灵活。你可以制定策略,自动将数据在不同性能/成本的“层”间移动。在存算分离语境下,“层”的概念有了新的内涵:

  • 热阶段(Hot):索引刚创建,处于频繁写入和查询状态。ILM 策略可以将其索引的index.routing.allocation.include._tier_preference设置为data_hot。在存算分离集群中,这通常意味着系统会尽力将该索引的数据保留在计算节点的内存缓存或共享 SSD 缓存中,以获得最佳性能。
  • 温阶段(Warm):索引不再写入,但仍会被不定期查询。ILM 可以触发一个“收缩索引”(Shrink)或“强制合并”(Force Merge)操作,减少分片数量和段文件数,然后将其迁移到“温”层。在 OpenStore 中,这对应的可能是调整缓存策略,让数据更多地驻留在共享 SSD 缓存而非内存中。
  • 冷阶段(Cold):数据很少被查询,但对可用性有要求,需要在线可查。ILM 将其迁移到“冷”层。此时,索引的大部分数据块可能主要存放在 OSS 中,仅在查询时按需加载到缓存。这是成本节省的关键阶段,你只需要为 OSS 存储付费,而计算资源可以在无查询时降到最低。
  • 冻结阶段(Frozen):几乎从不查询的归档数据。Elasticsearch 提供了专门的“冻结索引”API,索引被冻结后,其数据完全存在于 OSS,不占用任何缓存,查询时需要显式解冻(速度较慢)。这适用于合规性存档数据。

你可以通过 Kibana 的 Index Lifecycle Policies 界面非常直观地配置这些策略。例如,为日志索引配置一个策略:在热阶段保留3天,然后自动滚动到温阶段保留7天,最后进入冷阶段保留30天。

3.3 监控与弹性扩缩容操作

监控是弹性伸缩的眼睛。你需要重点关注以下几个指标:

  • 计算节点 CPU 使用率与负载:如果持续高于70%(可根据业务敏感度调整),应考虑扩容。
  • 查询延迟(Search Latency):特别是 p99 延迟,是影响用户体验的直接指标。
  • JVM 堆内存压力:虽然存储分离了,但查询聚合仍需要内存,监控 GC 频率和时间。
  • OpenStore 缓存命中率:这个指标能告诉你当前的数据访问模式是否健康,缓存命中率低意味着大量查询穿透到OSS,会拉高延迟。

扩容操作实录

  1. 登录阿里云 Elasticsearch 控制台,进入目标集群的“配置与管理”页面。
  2. 在“弹性伸缩”或“节点管理”部分,找到计算节点组的“扩容”选项。
  3. 选择“增加节点数量”或“变更节点规格”。例如,从 2 个 8核16GB 节点,扩容到 3 个相同规格的节点,或者将现有节点全部升级为 16核32GB。
  4. 确认费用变化,提交任务。整个过程是平滑的,系统会先启动新节点,待其加入集群并同步元数据后,逐步将部分查询负载迁移过去,最后完成扩容。期间业务无感知。
  5. 扩容完成后,在 Kibana 的“Stack Monitoring”或通过_cat/nodes?v命令查看新节点状态。

缩容操作同样简单,选择需要移除的节点(通常建议先移除负载较低的节点),系统会自动将其上的分片(主要是主分片,存算分离下副本概念弱化)所有权转移给其他节点,然后安全下线该节点。全程无数据搬迁

实操心得:对于有明显波峰波谷的业务(如白天高峰、夜间低谷),可以结合阿里云的“定时弹性伸缩”功能,设置定时任务在每天固定时间进行扩缩容。例如,在早9点业务上升前自动扩容2个节点,在晚12点后自动缩容。这能实现最大程度的成本优化。

4. 性能与成本实测对比分析

说一千道一万,不如实际测一测。我设计了一个简单的对比实验:用相同的数据集和查询负载,分别测试传统本地SSD集群和存算分离集群在性能、成本弹性方面的表现。

测试环境

  • 数据集:约 1TB 的模拟商品日志和交易数据,索引约为 10 个,每个索引 5 个主分片 1 个副本。
  • 查询负载:混合了 term 查询、range 聚合、terms 聚合等典型 OLAP 查询。
  • 传统集群:3个数据节点,每个节点 16核64GB,配备 2TB 高效云盘。
  • 存算分离集群:2个计算节点(16核64GB),单节点存储容量(缓存)配置为 1TB,底层使用标准存储。

测试结果

测试项传统本地SSD集群存算分离集群 (OpenStore)分析与说明
数据写入速度约 45 MB/s约 40 MB/s存算分离集群写入需经过网络写入OSS,略有损耗,但在可接受范围。可通过调整refresh_interval和批量写入优化。
高频热数据查询延迟 (p50)15 ms12 ms由于OpenStore的热数据缓存机制,且计算节点无需承担数据恢复等后台任务,CPU更专注于查询,延迟反而略优。
低频冷数据首次查询延迟15 ms (数据在本地盘)800 ms关键差异点。冷数据需从OSS加载,首次查询延迟显著增高。但后续查询因数据已在缓存,延迟会降至与热数据相当。
集群扩容耗时 (2节点->3节点)约 45 分钟约 5 分钟传统集群需要在新旧节点间迁移大量分片数据,耗时极长。存算分离集群仅需启动新节点并加入集群,优势巨大。
月度静态成本估算较高 (计算+存储捆绑)基础成本较低传统集群需为存储和峰值计算能力持续付费。存算分离按实际存储量、请求量和弹性计算时长付费,在负载不均场景下优势明显。
应对突发查询洪峰能力弱,需提前预置资源强,可分钟级弹性扩容存算分离可快速扩容计算节点分担负载,洪峰过后立即缩容,只为使用的资源付费。

成本分析示例: 假设一个业务,日均只有4小时高峰查询期,需要强大的计算能力(4个32核节点),其余20小时负载很低(2个16核节点即可)。数据总量2TB。

  • 传统模式:你必须始终维持4个32核节点+2TB云盘,为全天24小时付费。
  • 存算分离模式:你可以配置2个16核节点作为基础算力,并为2TB数据支付存储费。在4小时高峰期内,通过弹性伸缩临时增加2个32核节点。这样,你只为额外的强大算力支付了4小时/天的费用,成本节省可能超过50%。

5. 常见问题与避坑指南

在实际迁移和使用过程中,我遇到了一些典型问题,这里汇总一下,希望能帮你少走弯路。

5.1 性能调优相关

问题1:冷数据查询慢怎么办?

  • 排查:首先通过监控查看 OpenStore 缓存命中率。如果针对某个历史索引的查询缓存命中率很低,说明它在被频繁地“冷启动”。
  • 解决
    1. 预加载(Warm):对于已知在特定时间(如每天凌晨生成报表)需要查询的历史索引,可以通过_plugins/_query_cache/warmAPI(具体API名称需参考阿里云文档)或定时任务,提前将索引数据加载到缓存中。
    2. 调整ILM策略:如果某个“冷”阶段的索引仍然被频繁访问,考虑延长其“温”阶段的时间,或者为其创建单独的、缓存策略更积极的ILM策略。
    3. 优化查询:尽量避免对冷索引进行全量扫描或高基数的聚合。使用更精确的时间范围过滤,或者考虑将汇总数据提前计算好存入另一个小型索引中。

问题2:写入吞吐量不如本地盘集群?

  • 排查:检查计算节点的网络带宽是否成为瓶颈,以及index.refresh_interval的设置。
  • 解决
    1. 批量写入:这是最重要的优化。确保使用 Elasticsearch 的 Bulk API,并调整每批次的文档数量和大小(例如 5-15MB 一批),找到最佳平衡点。
    2. 调整刷新间隔:适当调大refresh_interval(例如从默认的1s改为30s),可以减少 Lucene 段文件的生成频率,提升写入吞吐。代价是数据可见性有延迟。
    3. 使用专用客户端节点:如果写入量极大,可以考虑配置独立的、不承担数据角色的 Client Node 来专门处理写入请求,减轻数据节点的网络和CPU压力。

5.2 运维与兼容性

问题3:从传统集群迁移到存算分离集群,有什么好方法?

  • 方案一:快照与恢复(推荐):这是最安全、对源集群影响最小的方式。
    1. 在源集群创建共享存储库(Repository),指向一个 OSS Bucket。
    2. 为需要迁移的索引创建快照(Snapshot)。
    3. 在目标存算分离集群中,配置连接到同一个 OSS Bucket 的存储库。
    4. 从快照中恢复索引。由于目标集群的存储底层也是 OSS,恢复速度很快。
  • 方案二:跨集群复制(CCR):如果要求近乎实时的迁移,可以使用 CCR 功能,将源集群的索引持续同步到目标集群。适合长周期的灰度迁移。

问题4:所有的插件和功能都兼容吗?

  • 主要兼容:核心的搜索、聚合、IK分词器、SQL插件等都完全兼容。
  • 需要注意:某些严重依赖本地磁盘特性的插件或自定义功能可能需要评估。例如,一些社区插件如果直接操作本地分片文件路径,可能在存算分离环境下无法工作。在迁移前,最好在测试环境进行全面验证。
  • 专属功能:存算分离集群会提供一些特有的监控指标(如缓存命中率)和管理 API,这是传统集群没有的。

问题5:如何保障数据安全与高可用?

  • 数据持久性:数据最终存储在 OSS,提供 99.999999999%(11个9)的持久性,远高于本地盘。
  • 计算层高可用:至少部署2个计算节点,并分布在不同的可用区(如果支持)。当一个可用区故障时,剩余节点仍可提供服务。查询请求会自动重试。
  • 缓存层高可用:共享 SSD 缓存池本身也是多副本、高可用的设计,单点故障不会导致数据丢失或缓存失效。
  • 访问安全:结合 VPC 网络隔离、安全组、Elasticsearch 自身的用户名密码认证、以及阿里云的访问控制(RAM),可以构建多层次的安全防护。

迁移到存算分离架构,尤其是 OpenStore,初期需要一些观念上的转变和细致的测试。但一旦跑通,它在弹性、成本和运维复杂度上带来的收益是非常显著的。对于数据量持续增长、业务负载波动大、且对成本敏感的场景,这无疑是一个值得深入评估的架构升级方向。