# IM 多开跨 Pod 实时投递压测方案 日期:2026-09-13 > 006 商户、2000 账号、两台压测机的可执行场景与统计口径见 > [IM-006商户双机消息压力测试方案](./IM-006商户双机消息压力测试方案.md)。本文保留为通用阶梯与指标说明。 ## 1. 目标 验证 IM Server 使用 Redis realtime fanout 后,在多 Pod、多端登录、群消息和群业务事件场景下的实时投递能力。 本次压测重点观察: 1. 跨 Pod 在线消息是否能投递到所有目标 WS 连接。 2. 群消息在多 Pod 下的端到端延迟。 3. Redis Pub/Sub 发布、接收、投递失败和本地无连接的比例。 4. Hub 队列满、WS 写队列满、Redis 发布失败等异常是否可观测。 5. Pod 扩缩容、单 Pod 重启时是否出现明显丢消息或延迟尖刺。 ## 2. 前置环境 建议至少准备: - IM Server:3 个 Pod。 - Redis:独立实例或 Redis Cluster,开启 `group_fanout_enabled`。 - MySQL:使用压测租户库。 - 监控:开启 `/metrics`,采集 Prometheus 指标。 - 账号:准备足够多的群成员账号 CSV,格式为 `username,password[,token]`。 - 群 topic:提前创建一个大群,并把压测账号加入该群。 每个 Pod 必须配置不同的节点标识: ```json "node_id": "im-pod-1" ``` 或通过环境变量: ```shell IM_NODE_ID=im-pod-1 ``` ## 3. 新增服务端指标 本次改造新增 Prometheus 指标: ```text realtime_fanout_events_total{stage,kind,target_type,status} realtime_fanout_delivery_duration_seconds_bucket{kind,target_type} ``` 常用查询: ```promql sum by (stage, kind, target_type, status) (rate(realtime_fanout_events_total[1m])) ``` ```promql histogram_quantile( 0.95, sum by (le, kind, target_type) (rate(realtime_fanout_delivery_duration_seconds_bucket[5m])) ) ``` 重点关注 status: - `publish/ok`:本 Pod 成功发布到 Redis。 - `publish/error`:Redis 发布失败。 - `publish/skip_native_cluster`:启用了 Tinode 原生 cluster,跳过 Redis topic fanout。 - `receive/ok`:其他 Pod 收到 Redis fanout。 - `receive/malformed`:收到无法解析的消息。 - `deliver/local_delivered`:本 Pod 找到本地 WS 并投递。 - `deliver/no_local_session`:本 Pod 没有目标本地连接,属于正常情况。 - `deliver/hub_full`:Hub routeSrv 队列满,需要重点告警。 - `deliver/skip_no_session_store`:session store 未初始化。 ## 4. 压测脚本 脚本位置: ```shell loadtest/realtime_fanout_probe.go ``` 运行示例: ```shell go run ./loadtest/realtime_fanout_probe.go \ -ws "ws://im-pod-1.example.com/v0/channels,ws://im-pod-2.example.com/v0/channels,ws://im-pod-3.example.com/v0/channels" \ -apikey "$IM_API_KEY" \ -accounts loadtest/users.csv \ -topic grpXXXXXXXXXXXX \ -subscribers 3000 \ -publishers 10 \ -rate 200 \ -duration 10m \ -ramp 2m ``` 脚本行为: 1. 按 CSV 账号建立 WS 连接。 2. 将连接均匀分布到 `-ws` 提供的多个 Pod 地址。 3. 每个连接登录并订阅同一个群 topic。 4. 从前 `-publishers` 个连接中选择发布者。 5. 按 `-rate` 总速率发布带 `probe_id` 和 `sent_at_unix_nano` 的群消息。 6. 所有订阅连接统计收到的 `{data}`,输出接收数、丢失率、p50/p95/p99/max 延迟。 输出示例: ```text ==== realtime fanout probe summary ==== published=120000 active_subscribers=3000 expected_deliveries=360000000 received=359998200 lost=1800 loss_rate=0.0005% unique_messages_seen=120000 errors=0 ctrl_acks=120000 latency p50=18ms p95=65ms p99=140ms max=900ms samples=359998200 ``` ## 5. 压测阶梯 建议按下面阶梯逐步推进,每个阶梯至少跑 10 分钟: | 阶段 | Pod | 在线连接 | 发布者 | 总 QPS | 目标 | | --- | --- | ---: | ---: | ---: | --- | | S1 | 3 | 300 | 1 | 10 | 验证链路正确性 | | S2 | 3 | 3000 | 10 | 100 | 验证常规群聊压力 | | S3 | 3 | 10000 | 20 | 300 | 验证大群在线 fanout | | S4 | 6 | 30000 | 50 | 500 | 验证扩容后的 Redis fanout | | S5 | 6 | 30000 | 50 | 1000 | 探测上限和队列瓶颈 | ## 6. 通过标准 建议初始通过标准: - `publish/error` 为 0。 - `receive/malformed` 为 0。 - `deliver/hub_full` 为 0。 - 压测脚本统计丢失率低于 0.01%。 - p95 端到端延迟低于 200ms。 - p99 端到端延迟低于 500ms。 - Pod CPU、内存、GC 无持续上升趋势。 - Redis CPU 不超过 70%,网络出入带宽有余量。 ## 7. 故障注入 基础压测通过后执行: 1. 压测中重启一个 IM Pod,观察其他 Pod 是否继续投递。 2. 压测中扩容 Pod 数,观察 `receive/ok` 是否按 Pod 数增加。 3. 临时降低 Hub/WS 队列容量或制造慢客户端,确认 `hub_full`、WS 写失败日志可见。 4. Redis 短暂不可用,确认 `publish/error` 增加,恢复后新消息继续投递。 ## 8. 结果记录 每轮记录: - Git commit。 - IM Pod 数量和规格。 - Redis 规格。 - 在线连接数、发布 QPS、消息大小。 - 脚本输出摘要。 - Prometheus p95/p99。 - `publish/error`、`deliver/hub_full`、WS 写失败数量。 - Pod 重启/扩容期间的最大延迟和丢失率。