1.2 自研还是买云 IM 服务
场景
立项第一周,我们开了三天会,核心议题只有一个:自研还是买云 IM 服务。市面上有不少成熟的 IM 云服务(腾讯云 IM 之类的商品化方案、以及一批第三方 SaaS),按月活或日消息量计费,几天就能接入完毕。团队里分两派:业务派说买,两周上线不香吗;技术派说自研,数据在别人手里将来很被动。我们谁也说服不了谁,干脆把两边的账都摊开算了一遍。
方案
买服务的好处很直观:SDK 现成、多端齐全(iOS、Android、Web、小程序全覆盖)、各家手机的推送通道人家都打通了,音视频也能顺手接上。坏处同样直观:计费随用户量线性增长,DAU 一旦上去,月费比自研的机器费还贵;而且消息数据存在别人机房里,我们做的是协作工具,消息里有客户的合同和图纸,合规评审那一关就过不去。另外云服务的能力是通用的,我们要做的 @提及定向提醒、消息撤回回执、多端同步策略定制,往往要排期等厂商做,甚至有些根本不支持。
自研的好处是数据自主、成本可控(只算机器和人力)、功能想怎么改怎么改。坏处是投入大——至少两人三个月才能出一个能用的版本,弱网重连、连接风暴、消息乱序这些坑一个都躲不掉,而且稳定性得自己背。
我们还算过一笔具体的账。买服务按 DAU 计费,假设十万 DAU、每人日均五十条消息,一年服务费在六位数量级。自研的话,两台网关 CVM 加一台逻辑层、一个 TDSQL-C 小实例加一个 Redis,初期每月成本也就服务费的零头,人力成本另算。DAU 过了五万这道坎之后,自研开始明显省钱;低于一万 DAU,服务费更低还省心。这个临界点每个厂商不太一样,建议拿自家报价单实算,别信销售嘴上的数字。
账一旦算清楚,选型的争论就结束了。技术派赢在合规和长期成本,业务派也会在三个月后承认这个决定是对的,虽然他们当时并不这么想。自研逼着团队吃透长连接、存储、消息队列,这套经验对后续任何后端系统都是资产。买服务则省心但能力始终在厂商那里。估值时把这条也算上,自研的账面会更好看一些,前提是团队能稳定。
| 维度 | 云 IM 服务 | 自研 | 我们的选择 |
|---|---|---|---|
| 上线周期 | 一到两周 | 两三个月 | 自研(排期允许) |
| 长期成本 | 按 DAU 计费线性增长 | 固定机器成本为主 | 自研 |
| 数据合规 | 数据存第三方 | 全在自有库 | 自研(硬项) |
| 定制能力 | 受厂商能力边界约束 | 完全自主 | 自研 |
| 稳定性兜底 | 厂商 SLA | 自己背锅 | 买服务占优 |
| 多端 SDK | 现成 | 自己写 | 买服务占优 |
| 团队储备 | 无需 IM 经验 | 需要长连接经验 | 自研(有 Go 底子) |
| 运维监控 | 自带控制台 | 自建 | 买服务占优 |
结论很清楚:合规和成本两条硬项决定了我们必须自研。但说句公道话,如果你只是做个客服聊天或者小规模社群,DAU 在几千量级,买服务明显更划算,别为了自研而自研。自研省下的钱本质上是把自己人力折算进去了,小团队未必划算。
还有一种折中方案值得提:核心自研、边缘外采。长连接、消息存储、必达逻辑这些自己写;推送通知这种碎片化严重的买厂商服务;客服会话这种边缘场景用 SaaS。我们最终就是这条路,既保住了核心数据,又没在适配各国厂商推送上耗尽人力。这些判断在立项阶段不可能一次全对,我们的经验是定下主路线后每周做一次小复盘,把新冒出来的不确定性写进决策日志,三个月积攒了四十多条。
配置与代码
自研路线确定后,我们划出了最小可用边界(MVP),先把单聊和群聊跑通,其他花哨功能一律砍掉,等跑稳了再补。功能边界一旦定死,排期就从模糊的三个月变成可交付的版本列表,这是自研项目里最容易被忽视的管理动作:
// MVP 阶段只实现这些指令,其余一律不做
var MVPCommands = map[string]Handler{
"login": handleLogin, // 登录换票
"send_msg": handleSendMsg, // 发消息(仅文本)
"sync": handleSync, // 拉新消息
"ack": handleAck, // 确认已收
"read_report": handleRead, // 多端已读同步
"heartbeat": handleHeartbeat, // 心跳保活
}
MVP 的部署也很克制:两台 CVM 跑网关与逻辑层,一个 TDSQL-C 实例做存储,一个 Redis 实例做未读数与会话列表,先不引入消息队列,等压测出写入瓶颈再加 RocketMQ(见 削峰填谷:RocketMQ 异步写入)。这样一套在云控制台上一上午就能拉起来,机器规格的选择参考 机器测算:CVM 撑多少连接。
自研的技术栈我们也做了取舍表,列在这里给同样纠结的人一个参照:
| 组件 | 商品化替代 | 我们为什么自己写 | 我们为什么买 |
|---|---|---|---|
| 长连接网关 | IM SDK 自带 | 核心能力,必须自主 | — |
| 推送通知 | 厂商推送服务 | — | 各手机厂商适配太碎 |
| 消息存储 | — | — | TDSQL-C 买现成的 |
| 未读数 | — | 逻辑简单自己写 | Redis 买现成的 |
| 日志审计 | — | — | CLS 买现成的 |
这张表帮我们在评审会上省了一个小时——凡是写着买现成的,就不再花人力;凡是核心能力,一个都不让。
顺带说一下灰度迁移方案的伏笔。即使全自研,也不意味着所有客户端版本同步切换。我们约定每个客户端版本在握手时上报自己的协议版本号,服务端按版本走不同处理分支,这样老版本客户端在新服务端上线后还能活两到三个版本周期。这套版本意识后来在 灰度发布:按用户分桶放量 里发挥了关键作用。
踩坑
最大的坑不是技术,是低估了多端客户端的活儿量。我们以为写了服务端,客户端 SDK 省事。实际上 iOS 后台被杀进程后的重连与唤醒、Android 各厂商推送通道的适配、网页端跨标签页的同步,每个都能吃掉团队一周以上的时间。如果有条件,推送通知这部分可以考虑直接买第三方推送服务,只把长连接的核心能力攥在手里,这是性价比最高的妥协。
第二个坑是估值模型错位。我们最初按峰值 QPS 估算机器配置,结果发现 IM 的特点是连接数高但 QPS 低,机器瓶颈在内存和连接数不在 CPU,按 QPS 估算买了一堆高 CPU 机器,内存反而不够。这块在 机器测算 里专门算了一遍账。
第三个坑是售后与 SLA。我们一度想用某家 SaaS 的售前承诺做兜底,真把合同条款要来看,发现 SLA 全是免责条款,出事最多赔当月月费。自研的锅虽然自己背,但至少修不修、什么时候修自己说了算。
第四个坑是迁移成本被低估。其实自研派在争论里隐藏了一个假设:买了云服务就永远不能自研。事实是很多团队先买后自建,但云服务的 SDK 深入客户端各端之后,迁移等于把客户端重写一遍。我们庆幸自己一开始就选了自研,否则这个沉没成本会非常大。
第五个坑是自研早期缺少监控。买服务自带控制台,自研初期什么都没有,出了问题两眼一抹黑。我们前两周全靠日志文件 grep 排障,直到把监控告警体系搭起来才算能睡安稳觉,这段经历写在 监控告警:连接数与积压 里。自研的隐性成本里,监控这一项一定得提前算进去,它属于那种平时不显眼、出事就是大事的投入,和日志审计一样属于底座型工作。
小结
自研与否不是技术问题,是商业问题:看数据敏感性、看用户量级、看团队有没有长连接经验。我们的结论是合规驱动自研、成本奖励自研,代价是三倍工期和多端兼容的无尽琐事。一旦决定自研,接下来就是算机器、定协议,进入真正的实战,这也是第二篇和第三篇的全部内容。书里后面所有章节都建立在自研这条路上,也与 腾讯云实践 里的其他自研案例可以互相印证,建议两本对着看。
回过头看,选型会上最怕的不是选错,而是没有可推翻的决策依据。我们的表格、账单和决策日志,价值不在于一次选中正确方案,而在于三个月后回头看时,知道当初为什么这么选,以及现在该改什么。
补充一个选型时少有人提的维度:退出成本。无论自研还是外采,都要问如果两年后要换掉它,代价是什么。自研的退出成本是把协议接口文档化(后来我们真的把内部协议开放给了生态伙伴),外采的退出成本是数据导出与协议反向兼容。我们与云 IM 服务商谈判时把数据导出条款写进了合同补充页——这条建议值得每个选型阶段的人抄进采购清单,谈判里往往让步最快的也是这类非标条款。另外要做一次小规模试点再签长约:我们让一个边缘业务模块先跑了三个月,跑通了才规模化,避免选型评审会上的纸面判断决定全系统的命运。
补充一条很多团队走过的中间路线:不必非此即彼。我们最终的形态是核心链路自研、外围能力买现成组件——消息存储、网关、序号分配这些决定系统脾气的部分捏在自己手里,但推送通道的厂商对接、富媒体文件的存储与加速、短信验证码这类非核心又琐碎的能力直接用云组件。这样团队规模始终控制在能开饭的范围,真出了问题需要深挖的环节也都在自己掌控之内。判断标准很简单:这块能力如果挂了,用户三分钟内会不会骂你,会就自研,不会就可以外包。
