Neon autoscaler-agent

通过 HTTP 轮询 VM 内部的 Vector 进程(Prometheus 格式 metrics),具体链路:

VM 内部 Vector (host_metrics 源, 每秒采集)

→暴露 /metrics 端点 (默认 9100 端口)

→autoscaler-agent 每 5 秒 HTTP GET 拉取

→用 prometheus expfmt 解析

四个维度的扩缩容指标

维度 信号 目标阈值
CPU host_load1 / host_load5 (Linux load average) load ≤ 90% 可用 CPU
内存使用 host_memory_total - host_memory_available 使用率 ≤ 75%
内存总量 (含 page cache) 同上 + host_memory_cached_bytes 总量 ≤ 90%
LFC 本地缓存 lfc_hits/misses + working set size 多窗口斜率估算 预分配缓存空间,防误降

核心算法是分别计算三个维度的 goal CU(Compute Unit),取最大值作为目标规格。

扩缩容流程

  • 扩容:agent →scheduler plugin 检查节点资源预留 →NeonVM CRD patch →通知 vm-monitor

  • 缩容:agent →vm-monitor 确认安全 →NeonVM CRD patch →通知 scheduler plugin

配置化程度很高,每个 VM 还可通过 annotation 覆盖参数。

NeonVM 是一个基于 Kubernetes 的轻量级虚拟机管理器(类似 KubeVirt,但更轻)。它的核心思想是把每台 VM 建模成一个 CRD 资源对象(Custom Resource

Definition),叫做 VirtualMachine。

什么是 CRD Patch

在 Kubernetes 里,CRD 扩展了 API 的原生资源类型。NeonVM 定义了自己的 VirtualMachine 类型,比如:

在 Kubernetes 里,CRD 扩展了 API 的原生资源类型。NeonVM 定义了自己的 VirtualMachine 类型,比如:

yaml 复制代码
apiVersion: vm.neon.tech/v1beta1
kind: VirtualMachine
metadata:
  name: my-vm
spec:
  guest:
    cpus:
      use: 4  # 当前分配 4 vCPU
    memorySlots:
      use: 8  # 当前分配 8 Gi 内存

Patch 就是指 autoscaler-agent 调用 Kubernetes API,对已有的 VM 资源对象做增量修改(JSON Patch),而不是删除重建。比如扩容时发一个 PATCH 请求:

json 复制代码
[
  {
    "op": "replace",
    "path": "/spec/guest/cpus/use",
    "value": 8
  },
  {
    "op": "replace",
    "path": "/spec/guest/memorySlots/use",
    "value": 16
  }
]

为什么这么做

  1. 不重启 VM ---相比删掉旧 VM 再创建新的,PATCH 让 NeonVM 控制器热调整资源

  2. 声明式 ---最终一致模型,Kubernetes 保证状态收敛

  3. 与 k8s 生态集成 ---可以用 kubectl 查看/调试,有事件日志

简单说:CRD Patch = 通过修改 Kubernetes 自定义资源的字段来动态调整 VM 配置。

  1. CPU 指标由 autoscaler-agent 直接采集

在 runner.go:273-287,autoscaler-agent 启动后台进程 getMetricsLoop 来获取系统指标:

在 runner.go:273-287,autoscaler-agent 启动后台进程 getMetricsLoop 来获取系统指标:

go 复制代码
r.spawnBackgroundWorker(ctx, logger, "get system metrics", func(ctx2 context.Context, logger2 *zap.Logger) {
    getMetricsLoop(
        r, ctx2, logger2,
        r.global.config.Metrics.System,  // ←配置指向 system metrics 端点
        metricsMgr[*core.SystemMetrics]{...},
    )
})

在 pkg/agent/core/metrics.go:82-116,这些指标是从 vector.dev 暴露的 Prometheus 端点(端口 9100)直接爬取的:

go 复制代码
func (m *SystemMetrics) fromPrometheus(mfs map[string]*promtypes.MetricFamily) error {
    // ...
    load1 := getFloat("host_load1")      // ←CPU 负载指标
    load5 := getFloat("host_load5")      // ←CPU 负载指标
    memTotal := getFloat("host_memory_total_bytes")
    memAvailable := getFloat("host_memory_available_bytes")
    memCached := getFloat("host_memory_cached_bytes")
    // ...
}
  1. vm-monitor 不负责 CPU 监控

vm-monitor 运行在每个 VM 内部,它主要处理:

  • 内存使用量(从 PostgreSQL 进程读取)

  • downscale 请求(拒绝缩容如果正在忙)

  • upscale 请求(通知 autoscaler-agent 它需要更多资源)

CPU 负载(load average)是宿主机的指标,在 VM 内部看不到整个宿主机的 load。所以 vm-monitor 不采集也不上报 CPU 指标。

  1. CPU 扩容完全由 autoscaler-agent 决策

在 pkg/agent/core/goalcu.go:84-94,autoscaler-agent 用自采集的 LoadAverage1Min/LoadAverage5Min 计算目标 CPU:

go 复制代码
blendedLoadAverage := load1Weight*systemMetrics.LoadAverage1Min +
                     (1-load1Weight)*systemMetrics.LoadAverage5Min

然后在 core/state.go 的 NextActions() 状态机中,通过 calculatePluginAction 向 scheduler plugin 请求增加 CPU,通过 calculateNeonVMAction 更新 VirtualMachine

的 VCPU 规格。

  1. 完整的扩容流程

CPU 指标采集 →vector (端口9100) →autoscaler-agent 解析 host_load1/host_load5

计算 desired CU

┌────────────┴────────────┐

↓ ↓

scheduler plugin (permit) NeonVM API (调整 VCpu)

↑ ↑

最终执行靠 vm-monitor vm-monitor 配合调整

响应 downscale/upscale 内存,但不参与 CPU 决策

总结:autoscaler-agent 自采 CPU 指标,vm-monitor 不收集和上报 load average。

vector 不登录数据库,它从主机操作系统层面采集指标。

vector 的工作原理

看配置 vm-builder/files/vector.yaml:

看配置 vm-builder/files/vector.yaml:

yaml 复制代码
sources:
  host_metrics:
    type: host_metrics          # ←内置的宿主机指标采集源
    scrape_interval_secs: 1     # 每秒采样一次
sinks:
prom_exporter:
type: prometheus_exporter   # ←暴露为 Prometheus 文本格式
inputs:
- host_metrics
address: "0.0.0.0:9100"    # ←监听在 9100 端口

type: host_metrics 是 vector 自带的 source,底层读的是 Linux /proc 和 /sys 文件系统,不是连数据库:

Vector 指标来源对照表

指标名 来源
host_load1, host_load5 /proc/loadavg
host_memory_total_bytes /proc/meminfo
host_memory_available_bytes /proc/meminfo
host_memory_cached_bytes /proc/meminfo
host_cpu_seconds_total /proc/stat
... ...

验证方法

在一个开启了 autoscaling 的 VM 上执行:

bash 复制代码
# curl vector 的端点
curl http://localhost:9100/metrics | grep 'host_load\|host_memory'

应该能看到类似输出:

text 复制代码
host_load1 0.45
host_load5 0.38
host_memory_total_bytes 4294967296
host_memory_available_bytes 1073741824
host_memory_cached_bytes 524288000

整体数据流

text 复制代码
/proc/loadavg ──┐
/proc/meminfo ──┼── vector (host_metrics source) ──→ Prometheus 文本格式 (:9100)
/proc/stat ─────┘
                ↓
        autoscaler-agent
        每2秒 curl localhost:9100/metrics
        ParseMetrics() 解析

总结: vector 只是一个"搬运工",把宿主机的系统指标从 /proc 转成 Prometheus 格式,autoscaler-agent 去拉取、解析,然后做扩容决策。跟数据库没有任何关系。

两个 sql_exporter 实例: 监控LFC指标

sql_exporter 是一个独立的可执行二进制文件(burningalchemist/sql_exporter (https://github.com/burningalchemist/sql_exporter),v0.17.3),编译进 compute 的

Docker 镜像中,在容器里以 daemon 形式运行。

工作链路是:

*.jsonnet (源码)

→Makefile jsonnet 编译

→生成 *.yml (构建产物,见 .gitignore)

→sql_exporter 二进制读取 yml

→连接本地 PostgreSQL,定期执行其中的 SQL

→暴露 Prometheus 格式的 /metrics 端点

→Prometheus 拉取指标

Makefile 里明确定义了 connection_string:

postgresql://cloud_admin@127.0.0.1:5432/postgres?sslmode=disable

也就是说 sql_exporter 跑在同一台 compute 上,连的是本地的 Neon Postgres。


自动扩缩容用这些指标吗?

分两个 collector:

  1. sql_exporter.yml / neon_collector.yml ---常规监控

Neon Collector 包含 ~50 个指标(neon_collector.jsonnet 里 imported),包括 checkpoint、replication delay、connections、WAL、buffer cache、pageserver

请求等。这些主要用于 Prometheus 监控告警,不是用来触发扩缩容的。

  1. sql_exporter_autoscaling.yml / neon_collector_autoscaling.yml ---专门给 HSCC 用的

neon_collector_autoscaling.jsonnet 只引入 5 个指标,全部跟 LFC(Local File Cache) 相关:

HSCC 自动扩缩容专用指标

指标 用途
lfc_approximate_working_set_size_windows 过去 1-60 分钟的 working set 大小(核心指标)
lfc_cache_size_limit LFC 缓存上限
lfc_hits / lfc_misses 缓存命中率
lfc_used / lfc_writes 缓存使用量

这组才是 HSCC(Hyper Automatic Autoscaler)用来判断该扩还是缩的依据。 尤其是 lfc_approximate_working_set_size_windows 看历史 working set 趋势。


补充说明

注意到有个 .17 后缀的文件(如 checkpoints_req.17.sql),对应 PG 17 有单独的查询,因为 PG 16→17内部某些 catalog 结构变了(比如 checkpoint 相关的系统表)。

Neon 的 compute VM 里跑了两个 sql_exporter 进程,各自监听不同端口:

sql_exporter 实例配置

实例 配置 端口 用户
sql-exporter /etc/sql_exporter.yml :9399 nobody
sql-exporter-autoscaling /etc/sql_exporter_autoscaling.yml :9499 nobody

启动命令就是:

bash 复制代码
/bin/sql_exporter -config.file=/etc/sql_exporter.yml -web.listen-address=:9399
/bin/sql_exporter -config.file=/etc/sql_exporter_autoscaling.yml -web.listen-address=:9499

它们是通过 init system(sysvinit / runit 之类,由 vm-image-spec 管理)拉起并自动 respawn 的。

访问 /metrics 端点

在 compute VM 内部:

bash 复制代码
# 常规监控指标
curl http://localhost:9399/metrics
自动扩缩容专用指标
curl http://localhost:9499/metrics

或者直接用 ps -ef 能看到:

bash 复制代码
ps -ef | grep sql_exporter

会看到两个进程,分别带不同的 -config.file 和 -web.listen-address 参数。

外部怎么访问

这些端口只在 VM 内部绑定。外部 Prometheus 采集时,通过 Neon 的 metrics

collector(apps/base/compute-metrics/scrape-compute-sql-exporter.yaml)把流量转发到对应的 VM 端口,或者通过内部的 service mesh / proxy 访问。

相关推荐
YOU OU8 小时前
Redis基础常识与命令
数据库·redis·缓存
Database_Cool_10 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森11 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
Database_Cool_11 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白12 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql
窝子面12 小时前
手搓最简前后端协作-node
javascript·数据库
吳所畏惧12 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈12 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
HPFBoy13 小时前
log4net 数据库存日志正确配置
数据库