一、大型集群里Jaeger索引为啥容易占爆ES空间

刚接触分布式系统的同学可能没感觉,但当你的集群从10个微服务涨到50个,每天产生几万条调用链路数据,还没做任何存储规划时,就会碰到ES空间不够的问题。比如我们公司去年就踩过这个坑:运维同学发现ES使用率到了95%,再查的话直接报错,Jaeger新产生的调用链数据存不进去,排查线上BUG的时候,只能看到3天前的旧数据,没法定位刚出的问题,折腾了大半天。 这里说的Jaeger不用记太复杂,就把它当成“分布式调用链的日志管理器”,每个微服务的每次请求,都会生成一条调用链路数据存在ES里,而ES是专门存这种结构化数据的工具,平时我们查某个服务的调用情况、排查慢请求,全靠ES里的这些数据。但问题是这些数据不是永久有用的,比如一周前的测试调用、昨天的非核心业务请求,过了时间就没人查了,全存在ES里自然会占爆空间。

1.1 先搞懂Jaeger索引和ES的关系

ES里的每个Jaeger调用链数据,都会存在一个“索引”里,你可以把这个索引当成带日期的文件夹,比如名字是“jaeger-span-2024.05.20”,这个文件夹里全是5月20日那天的调用链数据。每个索引有一定大小上限,当集群的数据多了,索引也会不停创建新的,ES的空间就一点点被占满了。

1.2 为啥会突然爆空间?

大型集群里还有个隐形的坑:很多人不知道Jaeger的索引默认是永久存储的,ES的存储要么按容量付费、要么物理机磁盘空间有限,当调用量突然涨了(比如做活动时一天调用量比平时多10倍),索引瞬间多10个,ES顶不住;还有一种情况是之前小集群没管,到了大型集群规模,累积的旧索引太多,直接占满空间。

二、解决空间问题的两类核心策略

碰到这个问题不用慌,核心思路就是两个:要么把没用的旧数据删掉,要么把不用的旧数据移到便宜的地方存,这样ES只存有用的新数据,就不会爆了。

2.1 第一招:过期自动删除(只保留最近一段时间的索引)

这个策略最简单,就是给Jaeger的索引设“保质期”,过了时间自动删掉,只留需要的数据(比如最近7天的),让ES永远只存7天内的数据,空间肯定够。 这里用Elasticsearch自带的生命周期管理(简单说就是给索引定规则,到时间自动处理)实现,不用写复杂脚本,配置一次就一劳永逸。示例代码用ES7.x(大型集群常用版本):

{
  "policy": {
    "description": "Jaeger索引过期清理策略,只保留最近7天数据",
    "phases": {
      "hot": { // 活跃阶段:刚生成的索引,用来存新数据
        "actions": {
          "rollover": { // 每天生成新索引,避免单个索引太大
            "max_age": "1d", // 每天滚动一次,生成jaeger-span-2024.xx.xx格式索引
            "max_size": "50gb" // 也可按大小设阈值,比如单个索引满50G就新建,两种选一种
          }
        }
      },
      "warm": { // 温暖阶段:索引过了1天还没新写入,进入该阶段
        "min_age": "1d", // 刚生成1天的索引,还没到过期时间
        "actions": {} // 可优化索引(比如压缩),不用复杂配置也能正常生效
      },
      "delete": { // 删除阶段:超过设定时间的索引
        "min_age": "7d", // 超过7天的索引自动删除,不占ES空间
        "actions": {
          "delete": {} // 自动执行删除,不需要人工干预
        }
      }
    }
  }
}

这个策略优缺点明确:优点是配置简单,不用人工维护,绝对不会爆空间,适合只需要查最近几天调用数据的业务;缺点是删了就找不回,万一要查半个月前的旧数据就没了,适合测试集群或非核心业务集群。 注意事项:一定要先测!别直接在生产集群开,先在测试环境跑一周,确认删除规则正确(比如别设成3天,刚好业务需要7天以上的数据),还要注意Jaeger的索引命名要和策略匹配(Jaeger默认索引是jaeger-span-开头的,会自动识别)。

2.2 第二招:归档旧数据(数据不会丢,要的时候再恢复)

如果业务需要保留所有历史调用数据(比如做月度性能分析),过期删除就不合适了,这时候要用归档策略:把超过7天的旧索引,从ES移到更便宜的存储(比如共享磁盘、对象存储),需要时再恢复到ES,这样ES只存最近7天的,旧数据归档,成本比买ES大容量低很多。 这里用Elasticsearch的快照功能实现,这个功能是ES自带的,专门用来备份恢复索引,不用额外装工具,单一技术栈为Elasticsearch:

# 第一步:创建快照仓库,用来存归档索引,所有ES节点都能访问(比如集群共享磁盘)
curl -XPUT "http://你的ES节点地址:9200/_snapshot/jaeger_archive_repo" -H "Content-Type: application/json" -d'
{
  "type": "fs",
  "settings": {
    "location": "/data/jaeger_snapshots", // 提前建好的所有ES节点都能访问的共享路径
    "compress": true // 压缩归档索引,能省一半空间,减少存储成本
  }
}'

# 第二步:归档超过7天的Jaeger索引,归档完可删除ES里的原索引释放空间
# 示例:今天是2024年5月20日,要归档5月12日之前的索引,调整对应日期即可
curl -XPUT "http://你的ES节点地址:9200/_snapshot/jaeger_archive_repo/jaeger_archive_$(date +%Y%m%d)?wait_for_completion=true" -H "Content-Type: application/json" -d'
{
  "indices": "jaeger-span-2024.05.*,jaeger-service-2024.05.*", // 匹配7天前的Jaeger索引(Jaeger默认命名格式)
  "ignore_unavailable": true, // 某个索引不存在时不报错,避免执行中断
  "include_global_state": false, // 只归档索引数据,不存集群状态,减少归档量
  "metadata": {
    "archived_date": "2024-05-20", // 给归档索引加备注,方便后续查找
    "cluster_name": "prod-cluster" // 标注是哪个集群的归档数据
  }
}'

如果需要查半个月前的数据,只要恢复归档的索引到ES,示例命令:

# 从快照仓库恢复归档索引,替换成实际的快照名和索引名即可
curl -XPOST "http://你的ES节点地址:9200/_snapshot/jaeger_archive_repo/jaeger_archive_20240520/_restore" -H "Content-Type: application/json" -d'
{
  "indices": "jaeger-span-2024.05.*",
  "ignore_unavailable": true
}'

这个策略优缺点:优点是数据不丢,符合全量保留的业务需求,归档存储成本比ES低5倍左右;缺点是配置比过期删除复杂,需要额外的共享/对象存储,恢复数据需要时间、不能马上用,适合核心业务集群。 注意事项:要定期清理过期归档快照,不然归档存储也会满;测试恢复功能,别到要用时发现快照损坏;还要归档服务索引(不止span索引),避免服务数据占用空间。

三、运维时的关键注意事项

不管选哪种策略,运维时要注意这些点,不然还是会出问题:

  1. 先监控再动手:别等ES使用率到90%才处理,平时要盯ES使用率、Jaeger索引增长速度,使用率到70%就该调整过期时间或开始归档。
  2. 适配业务需求:比如业务要求保留14天数据,就把过期删除设成14天,归档也只归档14天前的,别瞎设时间导致业务需要时找不到数据。
  3. 测试再上线:新策略上线前,一定要在测试集群跑一周,测会不会删错索引、会不会丢数据、恢复是否正常,别直接上生产。
  4. 留缓冲时间:设置过期时间时多留1-2天,防止业务偶尔需要更早的排查数据,不用临时恢复。
  5. 从源头减压力:可以调低非核心服务的Jaeger采样率,减少索引生成量,从源头降低空间压力。

四、总结

大型集群里Jaeger索引占爆ES是常见运维问题,核心是选对策略:不需要保留太久历史数据就用过期自动删除,配置简单见效快;需要全量保留数据就用归档策略,既省钱又不丢数据。不管哪种策略,都要先监控、先测试,再结合采样率优化等手段,保障链路追踪服务稳定运行。