短信服务看似简单,但真要自己搭一个能支撑业务运转的平台,坑比想象中多得多。
去年有个朋友找我吐槽:公司每个月短信费用好几万,想自建平台省点钱。我反问了他三个问题——高并发怎么扛?通道故障怎么切?账单对不上怎么办? 他沉默了。
这就是短信平台的真相:发一条短信容易,发一亿条还能稳定、安全、可追踪,完全是另一回事。
今天聊聊我自己写的 LESMS这个项目,看看一个轻量级企业短信平台是怎么从 0 到 1 搭建起来的。

一、为什么要自己搭短信平台?
先泼点冷水——大部分公司不需要自建短信平台。直接接阿里云、腾讯云,API 调一下就能用,省心省力。
但以下几种情况,自建就有意义了:
- 成本敏感:月发送量过百万,第三方平台的单价和附加费会吃掉不少利润
- 数据合规:金融、医疗行业,用户手机号不能外流到第三方
- 功能定制:需要特殊的签名审核流程、定时发送策略、精细化的通道调度
- 技术储备:团队有能力维护,且业务长期依赖短信触达
LESMS 的定位很明确:中小型企业的自建方案,不求大而全,但求核心链路稳、二次开发易。
二、三模块架构设计
整个系统拆成三大块,每块只干一件事:

1. Django 管理后台:业务的"大脑"
Django 在这里扮演两个角色:
一是客户中心 API。用户注册、登录、余额查询、发送记录查看,这些面向客户的接口都由 Django 提供。用 Django REST Framework(DRF)写起来很快,自带序列化、权限控制、限流。
二是运营管理后台。基于 Django Admin 改造的管理界面,运营人员可以在里面审核签名、配置通道、查看统计报表。SimpleUI 美化了一下,至少不像原生 Admin 那么丑。
关键模块包括:
- 用户管理:实名认证、企业认证、余额与计费
- 消息管理:模板审核、签名报备、上下行记录
- 通道管理:多运营商通道配置、黑名单管理
- 充值管理:套餐、订单、卡密核销

2. Vue 3 前端:用户的"门面"
前端用的是 Vue 3 + TypeScript + Element Plus,基于 Vben Admin 框架二次开发。
为什么不用 Django 自带的模板?因为现代前端工程化已经成熟了,Vue 的组件复用、状态管理、构建优化都比传统后端渲染强太多。
前端主要承载:
- 客户自助服务:发送短信、查看记录、管理通讯录
- 可视化数据:发送成功率、消费趋势、通道质量
- 开发者工具:API 密钥管理、SDK 下载、调试控制台
3. Go API 服务:性能的"发动机"
这是整个系统的性能担当,用 Go + Gin 框架实现。
短信发送有几个特点:高并发、低延迟、重可靠。Django 是同步阻塞模型,处理这种场景比较吃力;Go 的 goroutine + channel 天然适合高并发网络 IO。
Go 服务负责的核心功能:
- 短信发送接口:接收请求、校验签名、写入队列
- Worker 调度:从 Redis 队列取任务,分发到不同运营商通道
- 状态回执:接收运营商的送达报告,更新数据库
- 上行处理:处理用户回复的短信(MO)

三、技术选型背后的思考
有人可能会问:为什么搞这么复杂,用一种技术栈不行吗?
当然行,但会有代价。
| 模块 | 选型 | 理由 |
|---|---|---|
| 管理后台 | Django | 快速开发、生态成熟、Admin 开箱即用 |
| 核心 API | Go | 高并发性能、部署简单、资源占用低 |
| 前端 | Vue 3 | 组件化、TypeScript 支持好、团队熟悉 |
| 数据库 | PostgreSQL | ACID 保障、JSON 字段支持、运维友好 |
| 队列/缓存 | Redis | 原子操作丰富、持久化可选、生态完善 |
一句话总结:让合适的工具做合适的事。
Django 适合业务逻辑复杂、变更频繁的场景;Go 适合性能敏感、高并发的场景。两者通过 REST API + Redis 队列协作,既保留了各自的优势,又避免了过度耦合。
四、一条短信的完整旅程
光讲架构有点抽象,我们跟踪一条短信从用户点击"发送"到手机收到的全过程:
第一步:前端提交
用户在 Vue 界面填写手机号、选择模板、点击发送。前端组装请求体,带上时间戳、nonce、签名,调用 /api/v1/sms/send。
第二步:Go 服务接入
Go 服务收到请求,依次执行:
- 中间件链:CORS → 日志 → 签名校验 → 限流检查
- 参数校验:手机号格式、模板是否存在、余额是否充足
- 写入队列:将任务序列化后推入 Redis 队列
第三步:Worker 调度
Worker 进程从队列取出任务:
- 解析手机号前 7 位,识别归属运营商(移动/联通/电信)
- 查询用户的通道配置策略
- 选择最优通道,HTTP 调用运营商网关
第四步:运营商处理
运营商网关返回提交结果(成功/失败),Worker 记录提交状态。真正的送达是异步的——运营商会在短信送达后推送状态报告。
第五步:状态回执
运营商回调 Go 服务的 /callback/status 接口,携带手机号、状态、时间戳。Go 服务更新数据库中的发送明细,同时触发计费扣减。
第六步:用户感知
用户在前端刷新页面,看到"已送达"状态。如果失败了,能看到失败原因(余额不足、黑名单拦截、通道故障等)。
整个过程通常在 3-5 秒内完成,其中大部分时间花在运营商网络上。
五、写在最后
LESMS 的架构没有炫技,就是一个务实的企业级方案:
- 用 Django 快速搞定业务和管理后台
- 用 Go 保证核心链路的性能和稳定性
- 用 Redis 解耦同步压力和异步处理
- 用 Vue 提供现代化的用户体验
这套架构支撑过日发送量百万级的业务,也经历过双 11 的流量洪峰。它不是最完美的,但在开发效率、运维成本、性能表现之间找到了一个不错的平衡点。
下篇文章,我会带你 15 分钟把这套环境在本地跑起来,从安装依赖到发出第一条测试短信,手把手教你踩完所有的坑。
本文基于 LESMS 开源项目撰写,如需了解更多实现细节,可参考项目文档或源码。
评论 (0)