跳转到内容

M3 — Uber 的分布式 TSDB

是什么

M3 是 Uber 2014-2018 年内部打磨、2018 年开源(Apache 2.0)的分布式时序数据库套件,专门解决 Prometheus 单机扛不住的”超大规模监控”。日常类比:

  • prometheus 是社区诊所——一个医生看一片,记录都在自己抽屉,搬家就麻烦
  • victoriametrics 是连锁诊所——同一品牌不同分店,文件柜都一样
  • M3 是国家级医院网络——挂号 / 检验 / 影像 / 病案各部门独立、互相协作,能撑数十亿患者

M3 不是单个二进制,而是四个组件拼起来的系统:M3DB(存储)、M3 Coordinator(Prom 适配)、M3 Aggregator(下采样)、M3 Query(查询)。

为什么重要

不理解 M3,下面这些事都没法解释:

  • 为什么 Uber 内部要写一套”自己的 TSDB”——单 Prometheus 顶不住每秒80 亿 metric 写入
  • 为什么 Prometheus 官方推荐的 remote storage 列表里有 M3——它是水平扩展替代方案,不是周边
  • 为什么同样号称”Prom 长期存储”,Thanos / Cortex 是”拼起来”,M3 是”重写存储引擎”
  • 为什么 Chronosphere 这家公司值十亿美元——它就是 M3 原班团队商业化

核心要点

M3 的设计可以拆成 三层

  1. 存储层 M3DB:自研时序存储,数据按 shard 切分,副本走 Cassandra 风格的 ring + gossip。压缩用类 Gorilla 的 XOR + delta-of-delta,时间戳压到 1.37 字节/样本

  2. 索引层 自研倒排索引:用 Roaring Bitmap + FST(有限状态转换器)存 tag → series 的映射。Prometheus 的索引全部装内存,M3 的索引可以部分常驻 + 部分按需加载,所以能扛得住更高的 series 基数。

  3. 协调层 Etcd + Coordinator:Etcd 存 placement(哪个 shard 在哪台机),元数据强一致;Coordinator 是无状态网关,对外说 Prometheus remote_write/remote_read 协议,对内把请求分发给对应 shard。

实践案例

案例 1:Prometheus 加 M3 当远端

最常见的接入方式:让现有 Prometheus 把数据双写一份到 M3,本地保留 2 小时供告警,长期数据查 M3。

prometheus.yml
remote_write:
- url: "http://m3coordinator:7201/api/v1/prom/remote/write"
remote_read:
- url: "http://m3coordinator:7201/api/v1/prom/remote/read"

Prometheus 推数据进 Coordinator,Coordinator 按 shard hash 分发到 M3DB 节点。Grafana 直接连 Coordinator 的 PromQL 端点,数据看起来跟纯 Prom 一模一样。

案例 2:四组件部署形态

生产环境分四个角色,各自独立扩缩容:

[Prometheus / 应用]
│ remote_write
[M3 Coordinator] ── 路由 ──┐
[M3 Aggregator] ── 下采样 ──┐
[M3DB cluster]
[M3 Query] ◄── Grafana
  • Coordinator:无状态,可以多副本。负责协议翻译 + 请求路由
  • Aggregator:负责把 10 秒原始数据实时聚合成 1 分钟、5 分钟、1 小时多档 rollup
  • M3DB:有状态分片存储,每 shard 默认 3 副本
  • M3 Query:分布式 fanout 查询引擎,并行从多个 M3DB 拉数据再合并

案例 3:单机 Docker 起一个完整 M3

学习 / 评估时不必上集群,一个二进制起 M3DB single-node:

Terminal window
docker run -p 7201:7201 -p 9000:9000 \
--name m3db_local \
quay.io/m3db/m3dbnode:latest

7201 是 Coordinator 端口(PromQL / remote_write),9000 是 M3DB 内部端口。然后建 namespace(namespace 类似数据库里的 schema,决定 retention 和 resolution):

Terminal window
curl -X POST localhost:7201/api/v1/services/m3db/namespace \
-d '{"name":"default","options":{"retentionOptions":{"retentionPeriodNanos":"86400000000000"}}}'

注意里面的 JSON 用了双引号,这是 HTTP 接口要求;写到配置文件里也是 YAML 格式。

踩过的坑

  1. Etcd 是必需的,不是可选:M3 的 placement(shard 到节点的映射)写在 etcd,不是 M3DB 内部。生产部署必须先有 etcd 集群;测试环境用 single-node 把 etcd embed 进去,但 placement 一旦改坏,整个集群读不到数据

  2. Namespace 的 retention 不能”只增不减改大”:建 namespace 时定的 retentionPeriod=24h,后面想改成 7d——不能。要新建一个 namespace,写双写,等历史够 7 天再切。这设计是为防止把已删数据”复活”,但运维起来很反直觉。

  3. Coordinator 和 Aggregator 经常被新人混:Coordinator 是无状态网关,每次调用都转发;Aggregator 是有状态聚合器,缓存窗口数据做 rollup。文档里两个名字长得像,但部署、扩缩容策略完全不同——Coordinator 挂了重启就行,Aggregator 挂了窗口数据可能丢。

  4. 高基数 label 把倒排索引炸了:M3 的倒排索引虽然分级加载,但 series 基数(不同 label 组合数)超过千万级别后,写入路径上的索引更新会变成瓶颈。Uber 内部踩过的教训:user_id / request_id 这种唯一 ID 不能进 label,要么 hash 截断,要么走日志系统。

适用 vs 不适用场景

适用

  • 单 Prometheus 已经撑不住的中大型公司——百万 series/s 以上写入
  • 需要多年长期存储且查询要快——M3 按 shard 切分,不会因为数据多就慢
  • 已有 Prometheus / Graphite 生态,要无缝替换底层存储——Coordinator 兼容三种协议
  • 团队有专人运维基础设施,能搞定 etcd + Cassandra 风格分片

不适用

  • 团队规模小、运维人力少——M3 部署复杂度比 victoriametrics 高一个量级
  • 数据规模低于百万 series/s——杀鸡用牛刀,VM 或单 Prom 就够
  • 想要 SQL 查询——M3 只支持 PromQL / M3QL / Graphite 三种
  • 需要日志 / 追踪——M3 是纯指标系统,日志走 ELK / Loki,追踪走 Jaeger

历史小故事(可跳过)

  • 2014 年:Uber 监控用 Graphite + Carbon,业务暴涨后单机扛不住,开始研发内部 M3
  • 2015-2017 年:M3 在 Uber 内部完整迭代,名字是 “Metrics Monitoring Mission”
  • 2018 年 8 月:M3 在 KubeCon 北美开源(Apache 2.0),主仓 m3db/m3
  • 2019 年:原核心团队 Rob Skillington / Martin Mao 离开 Uber,成立 Chronosphere
  • 2020 年起:Chronosphere 基于 M3 做商业版本,公司估值进入十亿美元级独角兽

M3 不是社区驱动型项目——它是先有真实超大规模的内部需求,迭代成熟后才开源,所以代码反而比”先开源后扩规模”的项目更成熟。

学到什么

  1. 超大规模监控的瓶颈不在算力在索引——M3 最难的部分是倒排索引能否撑住高基数 label
  2. 协议兼容是降低迁移成本的杠杆——M3 兼容 Prom 三种协议,让企业可以”先双写再切换”
  3. Cassandra ring + gossip 这套架构虽老但稳——M3 把它套用到时序数据,证明了基础设施模式的复用性
  4. 开源时机很重要——内部跑稳后再开源,比”边开源边迭代”省了大量 breaking change

延伸阅读

关联

  • prometheus —— M3 的协议兼容目标,remote_write / PromQL 全照搬
  • victoriametrics —— 同样定位”Prom 长期存储”,但 VM 走单二进制无状态路线
  • opentsdb —— 第一代分布式 TSDB,依赖 HBase;M3 选自带存储不外挂 KV
  • grafana —— 最常见的 M3 前端,连 Coordinator 当 Prom 数据源即可

反向链接

  • grafana —— Grafana — 监控可视化看板
  • opentsdb —— OpenTSDB — HBase 上的第一代分布式 TSDB
  • prometheus —— Prometheus — 时序监控系统
  • victoriametrics —— VictoriaMetrics — 高性能 Prometheus 替代