3、日志存储与索引:Elasticsearch集群搭建、索引生命周期管理(ILM)、分片与副本策略、冷热数据分层

金融Agent跑起来之后,日志就像潮水一样涌来。我见过不少团队,日志系统跑着跑着就崩了,查询越来越慢,磁盘空间报警。说白了,日志存储不是简单的“写进去、查出来”,你得从一开始就规划好。

这一章,我们聊聊Elasticsearch。它是金融日志的标配存储引擎。怎么搭集群?怎么管理索引的生命周期?分片和副本怎么配?冷热数据怎么分层?嗯,这些都是实战中绕不开的坑。

3.1 Elasticsearch集群搭建:别让单点成为瓶颈

金融场景下,ES集群最少三节点起步。我个人习惯是奇数节点,方便选举。你想想看,如果只有两个节点,脑裂了怎么办?

搭建时,有几个关键参数必须调:

  • discovery.seed_hosts:种子节点列表,别漏了
  • cluster.initial_master_nodes:初始主节点,第一次启动时指定
  • network.host:绑定IP,别用0.0.0.0裸奔
  • path.datapath.logs:数据目录和日志目录分开,别挤在一起

我在项目中遇到过,有人把path.data和path.logs都放在系统盘,结果日志把根分区写满了,整个集群挂了。嗯,血的教训。

一个典型的docker-compose配置长这样:

version: '3.7'
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=fin-log-cluster
      - discovery.seed_hosts=es02,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms4g -Xmx4g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
      - logs01:/usr/share/elasticsearch/logs
    ports:
      - 9200:9200
  es02:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=fin-log-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms4g -Xmx4g"
    volumes:
      - data02:/usr/share/elasticsearch/data
      - logs02:/usr/share/elasticsearch/logs
  es03:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=fin-log-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms4g -Xmx4g"
    volumes:
      - data03:/usr/share/elasticsearch/data
      - logs03:/usr/share/elasticsearch/logs

volumes:
  data01:
  data02:
  data03:
  logs01:
  logs02:
  logs03:
小提示:内存锁定(bootstrap.memory_lock=true)一定要开。否则ES的堆内存可能会被swap出去,性能直接腰斩。我见过一个案例,没开这个参数,查询延迟从10ms飙到500ms。

3.2 索引生命周期管理(ILM):让日志自动“退休”

金融Agent的日志量有多大?一天几十GB很正常。如果不做管理,索引会越来越多,查询越来越慢,磁盘迟早爆掉。

ILM就是干这个的。它定义了索引从创建到删除的完整生命周期。一般分四个阶段:

  • Hot(热阶段):正在写入,频繁查询。用SSD,副本数可以少一点
  • Warm(温阶段):不再写入,偶尔查询。用HDD,可以压缩
  • Cold(冷阶段):很少查询,但需要保留。可以只保留一份数据
  • Delete(删除阶段):过期数据,直接删掉

我建议你按天创建索引,比如fin-agent-logs-2025.01.15。然后配置一个ILM策略,让索引在7天后进入温阶段,30天后进入冷阶段,90天后删除。

一个典型的ILM策略配置:

PUT _ilm/policy/fin_agent_logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "1d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "freeze": {},
          "set_priority": {
            "priority": 0
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}
注意:rollover的条件要合理。我曾经设过max_size=100GB,结果单个分片太大,查询时内存直接爆了。建议50GB一个分片,别贪心。

3.3 分片与副本策略:平衡的艺术

分片(shard)是ES分布式的基础。每个索引被分成多个分片,分布在不同的节点上。副本(replica)是分片的拷贝,用于高可用和读负载均衡。

分片数怎么定?我有个经验公式:

  • 每个分片的大小控制在20GB到50GB之间
  • 分片总数不要超过节点数乘以20
  • 副本数一般设为1(即一份数据,一份备份)

举个例子:如果每天产生100GB日志,按50GB一个分片,就是2个分片。保留7天,总共14个分片。3个节点,每个节点约5个分片,很合理。

副本数不是越多越好。副本多了,写入性能会下降,因为每个分片都要复制。我建议:

  • 热数据:副本数=1,保证高可用
  • 温数据:副本数=0,节省空间
  • 冷数据:副本数=0,只保留一份

配置示例:

PUT fin-agent-logs-2025.01.15
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1
  }
}
核心原则:分片是并行的单位,副本是冗余的单位。别把分片设太多,否则管理开销大;也别设太少,否则无法利用集群的并行能力。

3.4 冷热数据分层:把钱花在刀刃上

金融日志有个特点:最近几天的数据查询最频繁,越老的数据越少人看。如果所有数据都放在SSD上,成本太高了。

冷热数据分层就是解决这个问题的。热节点用SSD,温节点用HDD,冷节点甚至可以上对象存储(比如S3)。

在ES里,通过节点角色来实现:

  • hot节点:设置 node.roles: [ data_hot ]
  • warm节点:设置 node.roles: [ data_warm ]
  • cold节点:设置 node.roles: [ data_cold ]

然后,在ILM策略里指定每个阶段的数据迁移目标:

PUT _ilm/policy/fin_agent_logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "allocate": {
            "require": {
              "data": "hot"
            }
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "allocate": {
            "require": {
              "data": "warm"
            }
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": {
            "require": {
              "data": "cold"
            }
          }
        }
      }
    }
  }
}

这样,数据会自动从热节点迁移到温节点,再到冷节点。你什么都不用管,ES自己搞定。

实战经验:我曾经帮一家券商搭过这套架构。他们每天产生200GB日志,之前全放SSD,一个月光存储成本就十几万。用了冷热分层后,热节点只保留7天,温节点保留30天,冷节点用廉价HDD保留90天。成本直接降了60%。

3.5 知识体系总览

下面这张图,把本章的核心逻辑串起来了。从集群搭建,到索引管理,再到分片策略和冷热分层,每一步都环环相扣。

日志存储与索引 · 知识体系 ES集群搭建 索引生命周期管理(ILM) 分片与副本策略 冷热数据分层 3节点起步 Hot → Warm → Cold → Delete 20-50GB/分片 SSD → HDD → 对象存储 内存锁定 rollover + shrink 副本数=1 节点角色分离 从搭建到分层,每一步都影响性能和成本

好了,这一章的内容就这些。集群搭建、ILM、分片副本、冷热分层,每个点都是实战中必须掌握的。你把这些搞定了,金融Agent的日志存储基本不会出大问题。

一句话总结:日志存储不是存了就完事,要管好它的“生老病死”。ILM帮你自动化,冷热分层帮你省钱,分片副本帮你保性能。

公众号:蓝海资料掘金营,微信deep3321