跳到主要内容

集群架构与 Kubernetes 部署

当单机实例无法满足写入吞吐、数据量、查询并发、故障域或多租户需求时,可使用 VictoriaMetrics 集群形态。集群的关键不是“多起几个 Pod”,而是明确有状态的 vmstorage 与无状态的 vminsert、vmselect 的职责,以及扩容和恢复时的数据一致性边界。

1. 组件与数据路径​

Prometheus / vmagent
|
v
vminsert -- 按一致性哈希写入 --> vmstorage StatefulSet
|
Grafana / vmalert --> vmselect -- 聚合查询 ----+
组件默认端口职责扩容特点
vminsert8480接收写入、按租户和哈希路由数据无状态,可横向扩展
vmselect8481查询、聚合、去重与 Prometheus API 兼容无状态,可按查询压力扩展
vmstorage8482保存数据并处理存储层查询有状态,扩容与恢复需规划数据分布
vmauth(可选)8427认证、路由、租户隔离无状态,但必须高可用

应用不能直接访问 vmstorage。写入只能发到 vminsert,查询只能经过 vmselect 或受控的 vmauth;否则会绕过路由、认证或查询聚合能力。

2. 选型与拓扑​

集群形态适用于以下情况:单机资源已压测到瓶颈、需要隔离多个租户、要求跨故障域保存副本,或需要让写入与查询独立扩容。单纯为了“高可用”而部署集群并不可取,存储卷、备份、网络和运维复杂度会显著提高。

建议的生产起点:至少 2 个 vminsert 和 2 个 vmselect,vmstorage 使用 StatefulSet、独立 PVC、Pod 反亲和及适合的存储性能。副本数应根据节点故障、可用区故障和恢复目标设计,不能只看 Pod 副本。单机版在每秒摄取低于约 100 万数据点时通常更易维护,集群版应以压测结果和明确的容量需求作为决策依据。

3. 部署 vmstorage​

以下资源展示服务间的核心地址关系,不是完整可直接上线的生产清单。实际部署建议采用经审查的 Helm chart 或 Operator,并把镜像版本、资源、持久卷、TLS 与认证纳入 GitOps 管理。

apiVersion: v1
kind: Service
metadata:
name: vmstorage
namespace: monitoring
spec:
clusterIP: None # Headless Service 使 vminsert、vmselect 解析各 StatefulSet Pod。
selector:
app.kubernetes.io/component: vmstorage
ports:
- name: vmselect
port: 8401 # 供 vmselect 执行存储层查询。
- name: vminsert
port: 8400 # 供 vminsert 发送写入数据。
- name: http
port: 8482 # 指标与管理 HTTP 端口,只对受控运维网络开放。
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: vmstorage
namespace: monitoring
spec:
serviceName: vmstorage
replicas: 3 # 每个副本对应一个独立 PVC;变更前先阅读扩容与再均衡文档。
selector:
matchLabels:
app.kubernetes.io/component: vmstorage
template:
metadata:
labels:
app.kubernetes.io/component: vmstorage
spec:
containers:
- name: vmstorage
image: victoriametrics/vmstorage:<validated-version>
args:
# 数据目录与 PVC 挂载路径必须对应。
- -storageDataPath=/storage
# 所有存储节点使用统一的数据保留期;根据容量和合规要求调整。
- -retentionPeriod=180d
ports:
- name: http
containerPort: 8482
- name: vminsert
containerPort: 8400
- name: vmselect
containerPort: 8401
readinessProbe:
# 只有存储服务能够处理请求后,才允许上游组件将流量发给该 Pod。
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 15
livenessProbe:
# 存活探针只检查服务端口,避免高负载下复杂查询导致误杀。
tcpSocket:
port: http
initialDelaySeconds: 30
periodSeconds: 30
volumeMounts:
- name: storage
mountPath: /storage
volumeClaimTemplates:
- metadata:
name: storage
spec:
accessModes: [ReadWriteOnce]
storageClassName: fast-rwo # 替换为已验证的 StorageClass。
resources:
requests:
storage: 500Gi # 按保留期、写入量与冗余空间计算,不能照抄。

组件参数会随发行版变化,且完整集群通常还需要 -retentionPeriod、缓存、内存限制、复制与租户参数。上线前必须以该版本官方文档为准,并用压测结果确定参数。

4. 部署 vminsert 与 vmselect​

下面的清单接续上面的 vmstorage StatefulSet。生产中应根据实际吞吐设定资源请求、水平扩缩容策略、NetworkPolicy 和 Pod 反亲和;对外暴露时优先通过 Ingress、网关或 vmauth 统一进行 TLS 和认证,而不是把 Service 直接改为 NodePort。

apiVersion: apps/v1
kind: Deployment
metadata:
name: vminsert
namespace: monitoring
spec:
replicas: 2 # 无状态组件可按写入速率、CPU、网络和错误率横向扩展。
selector:
matchLabels:
app.kubernetes.io/component: vminsert
template:
metadata:
labels:
app.kubernetes.io/component: vminsert
spec:
containers:
- name: vminsert
image: victoriametrics/vminsert:<validated-version>
args:
# 将每条时间序列写入可用的 vmstorage 节点;新增节点前需更新此列表。
- -storageNode=vmstorage-0.vmstorage.monitoring.svc:8400
- -storageNode=vmstorage-1.vmstorage.monitoring.svc:8400
- -storageNode=vmstorage-2.vmstorage.monitoring.svc:8400
ports:
- name: http
containerPort: 8480
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 15
---
apiVersion: v1
kind: Service
metadata:
name: vminsert
namespace: monitoring
spec:
selector:
app.kubernetes.io/component: vminsert
ports:
- name: http
port: 8480
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vmselect
namespace: monitoring
spec:
replicas: 2 # 无状态组件可按查询并发、慢查询和内存压力横向扩展。
selector:
matchLabels:
app.kubernetes.io/component: vmselect
template:
metadata:
labels:
app.kubernetes.io/component: vmselect
spec:
containers:
- name: vmselect
image: victoriametrics/vmselect:<validated-version>
args:
# 聚合所有 vmstorage 的查询结果;必须使用 8401 查询端口。
- -storageNode=vmstorage-0.vmstorage.monitoring.svc:8401
- -storageNode=vmstorage-1.vmstorage.monitoring.svc:8401
- -storageNode=vmstorage-2.vmstorage.monitoring.svc:8401
# 仅在 HA 采集端写入完全相同时间序列时启用;值必须等于实际抓取间隔。
# 若抓取间隔不是 30 秒,必须同步调整,或删除该参数保留全部原始样本。
- -dedup.minScrapeInterval=30s
# 缓存可丢失,使用临时卷即可;重启后会自动回暖。
- -cacheDataPath=/cache
ports:
- name: http
containerPort: 8481
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 15
volumeMounts:
- name: cache
mountPath: /cache
volumes:
- name: cache
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: vmselect
namespace: monitoring
spec:
selector:
app.kubernetes.io/component: vmselect
ports:
- name: http
port: 8481
targetPort: http

5. 入口与数据源地址​

# Prometheus 或 vmagent 的集群写入地址;不要写入 vmstorage。
remote_write:
- url: http://vminsert.monitoring.svc:8480/insert/0/prometheus/api/v1/write

# Grafana 的集群查询地址;不要将 Grafana 指向 vminsert 或 vmstorage。
grafana_datasource:
url: http://vmselect.monitoring.svc:8481/select/0/prometheus

路径中的 0 表示租户 ID。单租户也应明确租户边界;多租户场景不要让客户端任意拼接租户 ID,应由 vmauth、网关或身份系统基于凭据进行路由与授权。

6. 副本、部分响应与多租户​

vminsert 可通过 -replicationFactor=N 将每份数据写到 N 个不同的 vmstorage 节点。它会将存储、网络和计算成本近似放大 N 倍;如果依赖该副本容忍 N-1 个存储节点故障,集群至少应有 2 * N - 1 个 vmstorage 节点,才能在故障期间仍维持该复制因子。

复制会产生重复样本。上方 vmselect 已使用 -dedup.minScrapeInterval=30s 作为示例,它需要与所有抓取目标的实际 scrape_interval 一致。该参数只会对标签完全相同的时间序列去重,因此 HA Prometheus/vmagent 必须使用相同的稳定外部标签;如果保留了不同的 replica 标签,两条序列不会被合并。不要盲目设为极短的去重窗口,否则可能改变同一抓取周期内的样本结果。

在某个 vmstorage 不可用时,查询可能返回部分结果。业务看板可以优先可用性;计费、SLO 或审计查询应启用拒绝部分响应的策略,并将“数据不完整”视为查询失败。多租户路径中的账号和项目 ID 只应由 vmauth 或统一网关根据身份凭据决定,客户端不应自行拼接其他租户的 ID。

7. 扩容、可用性与巡检​

  • vminsert:按写入请求、CPU、网络与错误率扩容。新增副本前确认上游使用的是 Service 或负载均衡地址。
  • vmselect:按查询并发、慢查询、内存和 Grafana 并发扩容。限制长时间范围、高基数和大返回集查询。
  • vmstorage:新增节点主要承接后续写入,历史分片不会自动重新均衡。扩容、缩容或替换节点前需要评估数据迁移、备份恢复、可用磁盘和版本升级路径。
  • 网络:仅允许采集端访问 vminsert、查询端访问 vmselect、内部组件互访;vmstorage 管理端口不对业务网开放。
  • 存储:监控每个 PVC 的可用空间、IOPS、延迟和 inode。至少保留扩容、压缩和恢复所需的安全余量。
# 同时查看三个组件的就绪与重启情况。
kubectl -n monitoring get pods -l app.kubernetes.io/part-of=victoriametrics -o wide

# 检查 vminsert 到 vmstorage 的连接或写入错误。
kubectl -n monitoring logs deploy/vminsert --tail=200

# 检查 vmselect 慢查询、内存压力与下游存储错误。
kubectl -n monitoring logs deploy/vmselect --tail=200
# 先确认三类组件均已就绪,再向 vminsert 写入并从 vmselect 查询。
kubectl -n monitoring get pods -l app.kubernetes.io/component

# 通过集群写入入口检查 Remote Write 协议路径;应用端应由 Service 或网关访问此地址。
curl -fsS http://vminsert.monitoring.svc:8480/health

# 通过集群查询入口验证 Prometheus API 路径和租户 ID。
curl -fsSG http://vmselect.monitoring.svc:8481/select/0/prometheus/api/v1/query \
--data-urlencode 'query=up'

任何扩容、降容、版本升级或存储迁移都应在预发回放真实负载,并验证写入连续性、查询正确性、告警规则和恢复流程。集群中“Pod Running”不等于所有分片均可读写。