Centrifugo 测试实战:从单测到压测的5道质量关卡,让消息不再丢失
【免费下载链接】centrifugoScalable real-time messaging server in a language-agnostic way. Self-hosted alternative to Pubnub, Pusher, Ably, socket.io, Phoenix.PubSub, SignalR. Set up once and forever.项目地址: https://gitcode.com/gh_mirrors/ce/centrifugo
凌晨三点,告警响了:聊天产品的后端声称消息已发出,所有 API 都返回 200,可用户的屏幕就是没亮。对于 Centrifugo 这类实时消息服务器,这种“静默丢失”是最难缠的故障——没有报错、没有 5xx,只是消息在某个环节掉了:可能是一个 JWT 恰好在这几秒过期,可能是异步消费者悄悄停摆,也可能是节点之间那条链路没有真正送达。
所以,实时消息服务器测试要回答的真问题不是“有多少用例”,而是:链路上哪几个环节可能丢消息,怎么在丢之前把它抓住?
Centrifugo 把这个答案拆成了几层代码。下面按执行顺序带你过一遍,每条命令都能直接在你机器上跑。
提交前自检:先把 API、令牌、协议三道关跑绿
这一步解决“git push 之前你该确认什么”。
Go 的约定很直白:每个源文件配一个_test.go测试文件,go test自动识别。Centrifugo 里最值得先看的是这三份:
- API 行为:internal/api/api_test.go —— publish、broadcast、历史查询等入口全覆盖,连 JSON / binary 两种数据格式都有独立用例
- 令牌关卡:internal/jwtverify/token_verifier_jwt_test.go —— 合法、过期、签名被篡改、audience、issuer,二十多个用例
- 协议编解码:internal/proxyproto/proxy_test.go —— 协议的字节级编码若错了,整个集群会互相读不懂
如果你正琢磨“Go 单元测试怎么写”,看 JWT 校验模块就明白了:
// JWT 校验模块的三个典型用例 func Test_tokenVerifierJWT_Valid(t *testing.T) {} // 合法令牌必须放行 func Test_tokenVerifierJWT_Expired(t *testing.T) {} // 过期令牌必须拒绝 func Test_tokenVerifierJWT_InvalidSignature(t *testing.T) {} // 篡改签名必须拒绝套路固定:正常路径必须放行,错误路径必须拒绝,边界各占一条用例。别急着跑全量,单条用例这样执行:
go test ./internal/jwtverify -run Test_tokenVerifierJWT_Valid -v
-run是正则,想跑整个系列就写-run Test_tokenVerifierJWT_。
让组件互相握手:哪些环节 mock 不了
这一步解决“单测和联调的边界在哪”。
一条消息在 Centrifugo 里要经手很多角色:API 入口、节点间的 NATS broker、还有从 Postgres、Kafka、Google Pub/Sub 等外部源异步消费进来的消息。有些交互可以打桩,有些不行——凡涉及外部状态的环节:Postgres 的行可见性、流里的 offset、队列的 claim、两个节点之间真实收发,这些语义只有真服务能验证。
所以项目把这些用例放在带//go:build integration构建标签的文件里:
- internal/natsbroker/broker_test.go:
TestNatsPubSubTwoNodes起两个真实节点,一端发布、另一端订阅,还验证 channel 替换 - internal/consuming/postgresql_test.go:
TestPostgresConsumer_GreenScenario走完整事务 outbox 流程,另有分区、drain 等场景 - internal/consuming/google_pub_sub_test.go:与 Google Pub/Sub 的拉取握手
边界原则一句话:纯逻辑(令牌校验、协议编解码)用单测;涉及外部状态的一律起真服务。联调测试需要先用 docker-compose 拉起 Redis、PostgreSQL、NATS、Kafka(见 CONTRIBUTING.md 和 docker-compose.yml):
make test-integration
把服务器放进压力锅:一条命令起步的压测
这一步解决“正确之后,扛得住吗”。正确性立住后,下一个问题是连接数和吞吐。项目在 misc/benchmarking/ 备好了现成脚本,操作步骤四步:
- 拿代码:
git clone https://gitcode.com/gh_mirrors/ce/centrifugo,然后cd centrifugo && make build生成centrifugo二进制 - 起服务:按 misc/benchmarking/k6/readme.md 写一份配置文件(要点:
token_hmac_secret_key设为secret、允许客户端自行订阅),再./centrifugo --config config.json启动 - k6 连接压测:脚本 misc/benchmarking/k6/benchmark.js 给 1000 个 VU 各生成一个 JWT,经 WebSocket 连入并订阅
test频道,逐步加压——这是 k6 压测实时服务的标准姿势
# 1000 连接 + 订阅压测 k6 run misc/benchmarking/k6/benchmark.js # API 发布压测:40 并发、2 秒(服务需以 --http_api.insecure 启动) wrk -s misc/wrk/api_publish.lua http://localhost:8000/api -d 2s -t 5 -c 40- 看指标:k6 会输出连接建立耗时、RPS 和错误率,若 1000 连接爬升段错误抬头,先查内核 fd 上限;wrk 输出 req/s 和延迟分位,拿它和基线对比即可确认发布 API 的吞吐。misc/benchmarking/k6/uni_ws/ 里还有免 SDK 单向传输的变体。
把测试变成习惯:Makefile 两行就够
这一步解决“怎么让这些测试真的天天跑”。
Makefile 里只有两个测试目标,也就是 CI 用的同一套命令:
make test—— 展开为go test -count=1 -v <除 misc 外全部包> -cover -race,竞态检测开、覆盖率开、不做缓存make test-integration—— 同上加--tags=integration,带上真实服务那批用例
-cover已让每个包附覆盖率报告;想要逐行 HTML 报告,加-coverprofile=coverage.out再喂给go tool cover -html即可。只跑一部分包时覆盖TEST_PACKAGES变量,这正是 CI 的做法:
make test-integration TEST_PACKAGES="$(bash misc/scripts/test_packages.sh integration)"
misc/scripts/test_packages.sh 会自动把包分成 unit 和 integration 两拨。挂 CI 流水线时照 .github/workflows/test.yml 抄作业即可:先make lint(golangci-lint),再跑 unit 组,最后跑 integration 组(用 service container 起好对应中间件)。
质量自查清单:五道关,一道都不能少
| 检查项 | 对应文件或命令 | 作用 |
|---|---|---|
| 全量单测 | make test | -race -cover全包扫过,提交前关卡 |
| API 协议行为 | internal/api/api_test.go | publish、broadcast、历史查询的正确性 |
| 令牌校验 | internal/jwtverify/token_verifier_jwt_test.go | 过期、篡改、错 audience 一律拒绝 |
| 真实服务握手 | make test-integration+ internal/consuming/ | Postgres、NATS、Pub/Sub 等不丢消息 |
| 压力负荷 | misc/benchmarking/ 与 misc/wrk/ | 千级连接与 API 吞吐基线 |
回到开头那次凌晨三点的丢消息:现在你知道该查哪儿了。200 不代表送达——令牌用例拒掉过期的、消费者用例在分区下仍能取到、压测里 1000 连接零错误,这三件事同时成立,静默丢消息才没有机会走到用户的屏幕上。
【免费下载链接】centrifugoScalable real-time messaging server in a language-agnostic way. Self-hosted alternative to Pubnub, Pusher, Ably, socket.io, Phoenix.PubSub, SignalR. Set up once and forever.项目地址: https://gitcode.com/gh_mirrors/ce/centrifugo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考