☰
Centrifugo 测试实战:从单测到压测的5道质量关卡,让消息不再丢失
2026/11/5 3:37:57 网站建设 项目流程

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/ 备好了现成脚本,操作步骤四步:

  1. 拿代码:git clone https://gitcode.com/gh_mirrors/ce/centrifugo,然后cd centrifugo && make build生成centrifugo二进制
  2. 起服务:按 misc/benchmarking/k6/readme.md 写一份配置文件(要点:token_hmac_secret_key设为secret、允许客户端自行订阅),再./centrifugo --config config.json启动
  3. 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
  1. 看指标: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.gopublish、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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询