三个月写了个短信平台,开源出来!

1 初心

大家好,我是勇哥。花了三个月的时间,我手写了个短信平台服务 platform-sms,今天开源出来 Beta 版本。

写这个开源项目的初心其实很简单:"帮助初中级研发工程师入门架构设计,提升他们的技术认知"。

2018年,作为架构师,我参与一个短信平台的重构。发送短信的场景包括还款业务、CRM、促销业务等。

不同的技术团队都是使用客户端模式发送短信,但并不统一,大概分为四种 :

  • 使用阿里云提供的短信 SDK 发送短信 。
  • 根据亿美提供的样例直接发送短信 。
  • 使用绿城提供的短信 SDK 发送短信。
  • 架构团队短信 SDK ,类似于 SMS4J的设计方式,支持亿美、绿城短信发送 。

客户端的模式在多团队协作场景中,缺点还是很明显:

  • 维护成本

    假如运营不再使用某一个短信渠道,那么很多团队将会收到影响,不得不配合重新修改配置,重新上线,耗费的时间成本很高。

  • 无法支持高级功能

    客户端实现某些功能比较麻烦,比如:客户端因为偶发情况(网络原因)通过三方渠道发送短信超时,此时需要将短信发送到备份渠道,从而确保短信发送的成功率。

因此,多团队协作的场景中,短信服务的模式应该是服务端模式

我参考了腾讯云的短信服务的设计思路 :

  1. 模仿腾讯云的 SDK 设计,提供简单易用的发送短信方法 (单发,群发,营销单发,营销群发,模板单发,模板群发) ;
  2. 设计短信服务 API 端,接收发短信请求,发送短信信息到消息队列;
  3. worker 服务消费消息,按照负载均衡的算法,调用不同渠道商的短信接口;
  4. 控制台可以查看短信发送记录,配置渠道商信息、模版信息等。

短信平台研发完成之后,满足了当时的业务需求,因为短信的管理也归于统一,提升了业务接入短信服务的效率,所以各个技术团队也比较认可。

随着经验的累积,我见过了不少公司的短信服务,核心问题不外乎两点:

  1. 短信服务与业务服务边界问题。

    为了满足业务服务需求,在短信平台中添加过多的业务功能,导致短信服务功能臃肿,也不经意的加入了隐藏的风险 。

  2. 切换三方渠道非常不方便。

    当运营端需要从三方短信渠道 A 切换到 B 时,因为代码不够抽象,增加三方渠道代码时维护成本较高。

基于这些原因,我想写一个迷你版的短信服务,它应该包含如下的功能:

  1. 简单的短信 SDK 支持按照模版发送短信 。

    业务服务对于短信是从哪一个三方短信渠道发送出来的并不在乎,只需要确保发送短信的成功率即可。

    因此,SDK 提供的核心接口是:按照模版编号发送短信

    阿里云、腾讯云、华为云提供的都是按照模版发送短信的接口,为了统一管理模版,我们也只提供按照模版发送短信的接口。

    短信平台需要提供业务服务的appKeyappSecret , SDK 与服务端之间通过固定协议交互。

  2. 短信平台支持模版的管理 。

    阿里云、腾讯云、华为云都提供签名、模版管理的接口,因此从产品设计层面,理论上,我们可以通过短信平台管理所有的签名和模版。

    短信平台当前提供了手工绑定的短信模版的功能,也就是我们需要先在阿里云或者腾讯云先申请签名和模版,然后绑定到我们在平台创建的模版。

  3. 适配器模式维护三方短信渠道。

    参考了开源项目canal的适配器模块,将三方短信渠道的 API 独立成模块单独维护,这样可以大大提升代码的可维护性。

2 架构

项目的设计应该设计得简单,因为它的目标首先是让初中级工程师快速入门架构设计

所以,我将短信平台设计成单体应用的模式,架构图如下:

短信平台分为两个部分,这两部分可以独立部署,也可以将前端文件放置在后端中,生成单部署包。

1、前端:admin-ui

控制台模块是 vue 项目,管理员登录之后可以进行应用管理、渠道管理、短信管理、模版管理。

2、后端:admin-web

后端模块按照功能依次分为五个模块:请求控制层、业务服务层、命令处理器、三方渠道适配器插件、数据库访问层。

3 演示

3.1 环境准备

1、创建数据库以及相关表

创建数据库tech_platform ,执行doc/sql 目录下的 tech_platform.sql

执行后效果如下:

2、修改部署包配置

从 Release 下载 platform-sms-admin.tar.gz ,解压缩后,进入 conf目录 。

编辑 application.yml 文件:

进入 bin 目录,启动服务:

bash 复制代码
bin/startup.sh

3.2 操作流程

1、登录页面

服务启动后,访问地址:http://localhost:8089

用户名和密码存储在 conf 目录的 application.yml,默认用户名密码分别是:admin/admin1984 。

2、新建应用

应用信息包含应用名称、应用 appKey , 应用秘钥备注。其中,应用 key 和 密钥在使用客户端 SDK 时需要配置 。

3、新建三方短信渠道

注意:因为腾讯云的 SDK 请求 中需要携带 APPID ,所以 Beta 版中将 appId 存储在 附件属性中。

4、创建模版模版管理模块,点击新建模版按钮。

新建模版时,签名名称必须和渠道申请的签名必须一致。

下图展示了笔者的腾讯云申请的签名,笔者创建的模版必须和腾讯云账号的签名保持一致。

创建完模版之后,需要绑定渠道,我们需要在三方渠道先创建短信模版,然后提交绑定。

  1. 三方渠道先创建短信模版

如上图,笔者创建了编号为 1955325 的短信模版,因为我们需要在绑定界面绑定该渠道的模版,理论上在短信平台创建的模版可以绑定多个渠道。

  1. 绑定渠道

绑定完成之后,可以在模版管理页面查看模版列表 。

3.3 发送短信

发送短信可以参考 DEMO 模块:

1、添加依赖

xml 复制代码
<dependency>
    <groupId>com.courage</groupId>
    <artifactId>platform-sms-client</artifactId>
    <version>${parent.version}</version>
</dependency>

2、客户端配置

首先在 application.yml中配置如下:

yaml 复制代码
sms:
  smsServerUrl: http://localhost:8089
  appKey: qQjEiFzn80v8VM4h
  appSecret: 9c465ece754bd26a9be77f3d0e2606bd

然后编写配置类:

kotlin 复制代码
@Configuration
public class SmsConfiguration {
​
    @Value("${sms.smsServerUrl}")
    private String smsServerUrl;
​
    @Value("${sms.appKey}")
    private String appKey;
​
    @Value("${sms.appSecret}")
    private String appSecret;
​
    @Bean
    public SmsSenderClient createClient() {
        SmsConfig smsConfig = new SmsConfig();
        smsConfig.setAppKey(appKey);
        smsConfig.setSmsServerUrl(smsServerUrl);
        smsConfig.setAppSecret(appSecret);
        SmsSenderClient smsSenderClient = new SmsSenderClient(smsConfig);
        return smsSenderClient;
    }
​
}
​

3、单发短信

typescript 复制代码
@Autowired
private SmsSenderClient smsSenderClient;
​
@GetMapping("/test")
public String test() {
    // 手机号
    String mobile = "15011319235";
    // 短信平台模版编号
    String templateId = "555829270636703745";
    // 模版参数
    Map<String, String> param = new HashMap<String, String>();
    param.put("code", "1234");
    param.put("time", "10");
    SmsSenderResult senderResult = smsSenderClient.sendSmsByTemplateId(mobile, templateId, param);
    System.out.println("senderResult:" + JSON.toJSONString(senderResult));
    return "hello , first short message !";
}

调用接口之后,用户就会收到如下的短信:

4 开源

代码库地址:

github.com/makemyownli...

勇哥想把这个项目做为架构入门的教学项目,您可以从中学到 :

  1. 设计一个精简的客户端 SDK 。
  2. 理解 SPI 机制以及适配器模式。
  3. 配置合理的线程模型。

如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!

相关推荐
why15137 分钟前
腾讯(QQ浏览器)后端开发
开发语言·后端·golang
浪裡遊41 分钟前
跨域问题(Cross-Origin Problem)
linux·前端·vue.js·后端·https·sprint
声声codeGrandMaster1 小时前
django之优化分页功能(利用参数共存及封装来实现)
数据库·后端·python·django
呼Lu噜1 小时前
WPF-遵循MVVM框架创建图表的显示【保姆级】
前端·后端·wpf
bing_1581 小时前
为什么选择 Spring Boot? 它是如何简化单个微服务的创建、配置和部署的?
spring boot·后端·微服务
学c真好玩2 小时前
Django创建的应用目录详细解释以及如何操作数据库自动创建表
后端·python·django
Asthenia04122 小时前
GenericObjectPool——重用你的对象
后端
Piper蛋窝2 小时前
Go 1.18 相比 Go 1.17 有哪些值得注意的改动?
后端
excel2 小时前
招幕技术人员
前端·javascript·后端
盖世英雄酱581362 小时前
什么是MCP
后端·程序员