← 中文资源

简体中文版本

基于 OpenSearch 构建日志检索服务

一个完整的日志检索服务:结构化写入、带 rollover 的索引模板、时间范围查询、聚合与保留策略测试。

阅读英文原文

项目概述

本项目实现日志检索服务:把结构化日志导入按天切分的索引,提供限定时间范围的过滤与聚合查询,并按保留策略滚动与删除旧索引。日志写起来廉价、查起来昂贵,若保留没有被设计就会无限增长。

架构与关键决策

导入端点按映射校验文档后批量写入别名之下的当日索引,使查询路径无需知道哪个具体索引持有近期数据;查询端点要求时间范围并在此内过滤,只触达与范围重叠的索引。保留以索引生命周期表达:按容量或时间滚动,把旧索引迁移到更廉价的层,超过窗口后删除。刷新间隔按查询 SLA 取舍,短则新日志可见更快而导入更贵,长则相反。

实施与测试

导入固定文档集断言过滤查询计数与聚合桶与预期一致;断言超过保留窗口的索引被选中删除;断言缺少时间范围的查询被拒;通过索引一条覆盖各字段类型的文档并回查验证映射。

限制与后续

  • 仅接收结构化日志,自由文本解析留给生产方。
  • 超出保留窗口无跨集群检索或冷存储归档。
  • 聚合无物化视图,宽聚合每次渲染都重算。

代码示例

pnpm init
pnpm add @opensearch-project/opensearch express
pnpm add -D typescript tsx vitest
log-search/
├── src/ingest.ts
├── src/search.ts
├── src/rollover.ts
├── src/retention.ts
├── tests/search.test.ts
└── package.json
PUT _index_template/logs {
  "index_patterns": ["logs-*"],
  "template": { "settings": { "number_of_shards": 2 }, "mappings": { "properties": { "@timestamp": {"type":"date"}, "level": {"type":"keyword"} } } }
}
await client.bulk({ refresh: false, body: docs.flatMap((d) => [{ index: { _index: 'logs-write' } }, d]) });
{ query: { bool: { filter: [ { range: { '@timestamp': { gte: from, lte: to } } }, { term: { level: 'error' } } ] } } }
"aggs": { "per_minute": { "date_histogram": { "field": "@timestamp", "fixed_interval": "1m" } } }
await client.indices.delete({ index: 'logs-' + cutoffDate, ignore_unavailable: true });
pnpm vitest run