跳转到主要内容

日志分析与 OpenTelemetry

结合 pg_mooncake 列存镜像与对象存储 Parquet 压缩,在 PostgreSQL 中以极低成本存储并分析海量应用日志与 OpenTelemetry 链路数据。

在传统架构中,人们很少使用 PostgreSQL 承载大规模日志分析,因为行存堆表与索引的磁盘占用增长极快,且对数千万条日志执行全表聚合扫描非常缓慢。

借助 pg_mooncake,你可以将按时间分区的 PostgreSQL 行存写入与基于对象存储的列存镜像结合起来:

  • 极低存储成本:历史日志以高压缩比的列式 Parquet 格式保存在 S3、Cloudflare R2 或本地磁盘上。
  • 架构极简:只需 PostgreSQL + 对象存储,无需额外部署运维 Elasticsearch 或 ClickHouse 集群。
  • 高速向量化检索:利用 DuckDB 2.0 的时间戳分段跳过(Segment Elimination)与向量化扫描,每秒可扫描数百万条日志记录。

推荐实现方案

使用按天/按小时分区的行存表承接实时日志写入,并创建 USING mooncake 列存镜像表执行聚合检索:

-- 1. 创建按时间分区的日志写入表
CREATE TABLE application_logs (
    log_id BIGSERIAL,
    timestamp TIMESTAMPTZ NOT NULL,
    level TEXT NOT NULL,
    service TEXT NOT NULL,
    message TEXT,
    trace_id TEXT,
    span_id TEXT,
    attributes JSONB,
    PRIMARY KEY (log_id, timestamp)
) PARTITION BY RANGE (timestamp);

CREATE TABLE application_logs_today PARTITION OF application_logs
    FOR VALUES FROM ('2026-11-05') TO ('2026-11-06');

-- 2. 创建用于快速聚合检索的列存镜像表
CALL mooncake.create_table('application_logs_analytics', 'application_logs');

-- 3. 将日志写入行存表
INSERT INTO application_logs (timestamp, level, service, message, trace_id, span_id, attributes)
VALUES (
    NOW(),
    'ERROR',
    'api-service',
    'Database connection timeout',
    'trace-123',
    'span-456',
    '{"user_id": 1001, "region": "us-east-1"}'
);

-- 4. 在列存镜像表上执行高速聚合分析
SELECT
    service,
    level,
    COUNT(*) AS error_count
FROM application_logs_analytics
WHERE timestamp >= NOW() - INTERVAL '1 hour'
  AND level = 'ERROR'
GROUP BY service, level
ORDER BY error_count DESC;

当每日日志分区超过热保留窗口(例如 24 或 48 小时后),可按照大表分区冷热归档模式直接从行存中删除旧分区(DROP TABLE application_logs_2026_11_01;),而完整的历史日志依然保留在 application_logs_analytics 中供长期回溯分析。