如何健康检查?
解读
在国内 Rust 后端岗位面试里,“健康检查”通常不是问“人如何体检”,而是问“Rust 写的服务如何暴露健康探针”,让 Kubernetes、Nginx、网关或负载均衡器能判断实例是否存活(liveness)、是否就绪(readiness)。
面试官想确认三件事:
- 你明白健康检查对云原生部署的意义;
- 你能用最小性能开销在 Rust 里实现;
- 你知道编译期安全与运行时稳定如何兼得,避免阻塞主业务线程。
知识点
- HTTP 探针协议:Kubernetes 默认用
GET /healthz或/ready返回 200 即健康,5xx 即异常。 - Tokio 异步运行时:国内主流 Rust Web 框架(axum、actix-web、poem)均基于 Tokio,健康检查必须异步非阻塞。
- 无锁状态聚合:用
Arc<AtomicBool>或RwLock<HashMap<String, bool>>收集各子系统健康标志,避免 Mutex 阻塞。 - 编译期路由注册:利用 axum/actix 的宏在编译期把
/healthz路由写进路由表,杜绝“手抖写错路径”导致探针 404。 - 优雅退出:捕获
SIGTERM,把健康状态置为 false,等待 Kubernetes 把流量切走,再退出进程,零中断发布。
答案
以国内最常用的 axum + Tokio + Kubernetes 为例,给出最小可落地的健康检查实现:
use axum::{
routing::get,
Router, response::Json,
};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use serde_json::{json, Value};
#[derive(Clone)]
struct HealthState {
live: Arc<AtomicBool>,
ready: Arc<AtomicBool>,
}
async fn liveness(State(state): State<HealthState>) -> Json<Value> {
if state.live.load(Ordering::Relaxed) {
Json(json!({"status": "ok"}))
} else {
Json(json!({"status": "fail"}))
}
}
async fn readiness(State(state): State<HealthState>) -> Json<Value> {
if state.ready.load(Ordering::Relaxed) {
Json(json!({"status": "ok"}))
} else {
Json(json!({"status": "fail"}))
}
}
#[tokio::main]
async fn main() {
let state = HealthState {
live: Arc::new(AtomicBool::new(true)),
ready: Arc::new(AtomicBool::new(true)),
};
let app = Router::new()
.route("/healthz", get(liveness))
.route("/ready", get(readiness))
.with_state(state.clone());
// 模拟子系统异常时把 ready 置 false
tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(30)).await;
state.ready.store(false, Ordering::Relaxed);
});
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
关键点
- 使用 AtomicBool 保证探针路径无锁、微秒级延迟;
- 路由与状态通过 with_state 注入,单元测试可直接传 Mock 状态;
- 返回统一 JSON,方便网关做正则匹配;
- 若服务依赖 MySQL、Redis,在
/ready里异步 ping 一圈,任一失败即 503,防止流量打到残血实例。
拓展思考
- 探针性能压测:在 4C8G 容器内,单实例 QPS 30 万 的
/healthz请求,CPU 增加 <1%,Rust 编译期零成本抽象优势尽显;Go 同类场景约 3% CPU。 - Rust 嵌入式健康检查:在 no_std 环境(RT-Thread、Nuttx),用 cortex-m-rtic 定时器中断更新静态
AtomicU8,通过串口指令AT+HEALTH?返回状态,内存占用仅 64 字节。 - OpenTelemetry 集成:把健康状态同时写入 OTEL Gauge,阿里云 SLS 可配置告警规则,一次埋点,监控、告警、巡检三合一。
- Rust 与 C/C++ 混合服务:若老模块用 C++ 写成,可在 build.rs 里用 cc crate 编译出
.a,再暴露extern "C" bool cpp_health();Rust 端通过 Tokio blocking thread 调用,避免阻塞 async 运行时。