From 2e338846fb725286b8408250b3fa9b04891134a3 Mon Sep 17 00:00:00 2001 From: wangbin3 Date: Sat, 6 Aug 2022 23:00:47 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E7=BD=91=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...41\347\275\221\345\205\263\357\274\211.md" | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 "src/\351\241\271\347\233\256/\345\274\200\346\272\220\351\241\271\347\233\256\346\216\250\350\215\220\347\263\273\345\210\227\357\274\210\347\237\255\344\277\241\347\275\221\345\205\263\357\274\211.md" diff --git "a/src/\351\241\271\347\233\256/\345\274\200\346\272\220\351\241\271\347\233\256\346\216\250\350\215\220\347\263\273\345\210\227\357\274\210\347\237\255\344\277\241\347\275\221\345\205\263\357\274\211.md" "b/src/\351\241\271\347\233\256/\345\274\200\346\272\220\351\241\271\347\233\256\346\216\250\350\215\220\347\263\273\345\210\227\357\274\210\347\237\255\344\277\241\347\275\221\345\205\263\357\274\211.md" new file mode 100644 index 0000000..00f664e --- /dev/null +++ "b/src/\351\241\271\347\233\256/\345\274\200\346\272\220\351\241\271\347\233\256\346\216\250\350\215\220\347\263\273\345\210\227\357\274\210\347\237\255\344\277\241\347\275\221\345\205\263\357\274\211.md" @@ -0,0 +1,229 @@ + +# 前言 +>文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger +> **种一棵树最好的时间是十年前,其次是现在** +## Tips +开源项目推荐系列是,小六六平时不是会逛逛开源平台嘛!然后就想着把一些项目分享给到大家,给大家说说我对这个开源项目的一些看法,当然,在写的过程中,也可以让自己的知识面更广,希望能给大家带来不一样的东西。 + +## 短信网关 +> 今天分享的项目是短信网关,这个项目呢?是某马在B站上放出来的项目,我也称之它为开源项目吧!哈哈 + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/40614856402d427cb578db358f1d529e~tplv-k3u1fbpfcp-watermark.image) + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ba10439e6c5f467a897c0ab5b4e21fad~tplv-k3u1fbpfcp-watermark.image) + +### 为啥要用短信网关 + +随着企业业务扩张、应用成倍的增加、短信规模化使用,传统短信平台的接入方式和单一的信息发送功能,已经不能完全满足现代企业管理的需求,所以统一入口、减少对接成本、同时兼顾多种短信业务、简单易行的操作与维护、高稳定、高可靠的移动信息化应用成为短信平台发展趋势。 + + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b236f495b5364839b7b34f3fa53d632e~tplv-k3u1fbpfcp-watermark.image) + +- 服务越来越多,每个服务都有可能发送短信,是否每个服务都需要对接一遍? +- 多应用对接短信,如何做到短信发送服务高效、稳定? +- 短信通道出现异常时,如何快速切换通道? +- 切换通道时,如何做到应用服务无感知? +- 如何统计各服务短信发送情况,以便进行后续营销分析? + +本项目(集信达短信平台)的核心在于保证短信高效、准确的送达、简单易操作的对接方式。通过对服务的解耦、通讯方式的升级来提升系统的吞吐量。同时在多通道的加持下,通过智能动态的通道评级、选举、降级、热插拔,增强了系统的健壮性,摆脱对单一通道的依赖。并且提供多种对接方式,满足企业内部的各种需求。 + +### 平台架构 +集信达短信平台的整体架构如下: + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/35f56f86f595404ebfdfb320f7dfb161~tplv-k3u1fbpfcp-watermark.image) + +主要有以下几个服务 +- pd-sms-api 给业务用 +- pd-sms-manage 后台管理 +- pd-sms-server 真正发送短信 + + +### 业务架构 + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e47f51fc2d0f425a9694e790c0bedd0d~tplv-k3u1fbpfcp-watermark.image) + +通过上面的业务架构可以看到,短信接收服务(pd-sms-api)提供3种方式供业务系统调用: + +- HTTP接口 +- TCP +- SDK形式 + +短信接收服务通过资质验证(可开关)、短信内容校验后将短信信息发送到对应中间件中(Redis、MySQL)。 + +短信发送方式分为两种类型: + +- 定时发送短信:将短信内容存储到MySQL数据库中,由短信发送服务通过定时任务获取并发送 +- 普通短信:将短信内容推送到Redis队列中,由短信发送服务异步接收并发送 + + + + +### 项目结构 + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4da9ecaec1cf474caaa4142df4c87f28~tplv-k3u1fbpfcp-watermark.image) + +集信达短信平台,项目整体工程结构和模块功能如下: + + +```js + +pd-sms-backend # 集信达 短信平台父工程 + ├── pd-sms-entity # 短信平台实体 + ├── pd-sms-manage # 系统管理服务 + ├── pa-sms-api # 短信接收服务,应用系统调用接口、发送短信 + ├── pd-sms-server # 短信发送服务,调用短信通道、发送短信 + └── pd-sms-sdk # 短信SDK,应用系统引入、发送短信 +``` +集信达短信服务有三个:后台管理服务,短信接收服务,短信发送服务: + +应用 | 端口 | 说明 | 启动命令 | +| ------------- | ---- | ------ | ----------------------------- | +| pd-sms-manage | 8770 | 后台管理服务 | java -jar pd-sms-manage.jar & | +| pd-sms-api | 8771 | 短信接收服务 | java -jar pd-sms-api.jar & | +| pd-sms-server | 8772 | 短信发送服务 | java -jar pd-sms-server.jar & | + +### 业务方调用处理流程 +**调用方式:** +- 业务统调用短信接收服务提供的接口,由短信接收服务将信息保存到消息缓冲区(Mysql、Redis) +- 调用方式:HTTP、TCP(Netty)、SDK + +**处理流程:** + +短信接收服务接收到应用系统请求后,会进行相关的校验处理,校验通过则将信息保存到消息缓存区,具体处理流程如下: + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29f303e398764963b60818d1df3bb3ac~tplv-k3u1fbpfcp-watermark.image) + +### 短信发送服务的发送过程 + +**相关功能:** +- 和具体的短信通道对接(例如:阿里云短信、梦网短信等),发送短信 +- 短信定时发送 +- 短信实时发送 +- 服务注册,保证短信发送服务高可用 +- 通道自动选举、降级 + + +**处理过程:** + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/93be44ec82324cdb9a6756326aef45ab~tplv-k3u1fbpfcp-watermark.image) + + + +## 项目亮点 + +### 架构的设计 + +架构的设计和耦合性还是很好的,代码的风格也很优雅,代码通俗易懂,我随机截取一个类给大家看看 + + +![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ac73c4ef93d848a8a592868318f39746~tplv-k3u1fbpfcp-watermark.image) + + +### 短信发送服务核心类 +- ServerRegister:服务注册器,用于将短信发送服务注册到Redis中,定时服务上报,定时服务检查 +- ConfigServiceImpl:通道配置器,用于查询可用通道(阿里短信、华为短信等),通道选举、降级 +- AbstractSmsService:短信发送器抽象父类,子类需要和具体的短信通道对接来完成发送短信的工作 +- SmsConnectLoader:通道实例加载器,根据通道配置,初始化每个通道的Bean对象 +- SmsFactory:短信发送工厂,获取具体的通道实例Bean对象(例如AliyunSmsService)来发送短信, 如果发送出现异常,触发通道选举和通道降级策略 +- SendTimingSmsImpl:定时短信业务处理器,具体负责定时短信的发送 +- SendSmsJob:短信发送定时任务,用于定时短信的发送,调用SendTimingSmsImpl发送定时短信 +- GeneralSmsListener、HighSmsListener:短信接收器,Redis队列的消费者,监听队列中的消息,如果有消息则调用SmsFactory发送实时短信 +- HighServerReceiver:通道消息监听器,通过Redis的发布订阅模式监听通道相关消息,调用SmsConnectLoader初始化通道和更新通道 +- SubscriberConfig:订阅发布模式的容器配置,创建消息监听容器,并将HighServerReceiver加入容器中 + + +### 服务注册器 +大家知道这个是干嘛的吧?哈哈往下看,保证让你觉得有点东西 + +**其实这块的概念和我们服务的注册于发现其实差不多的,但是作用确是不同,为啥这里我们要服务注册呢?原因如下** + +短信发送服务支持分布式集群部署,可以是多个实例,实例越多,发送短信的能力越强。但是对于通道选举、持久化通道等操作,只能有一个服务实例执行,其他服务实例通过redis的广播机制获得通道变化。 + +如果要实现这一功能,需要将所有短信发送服务实例注册到某个地方,当前实现是将所有服务实例注册到Redis中。并且为了能够监控每个服务实例运行状态,需要每个服务实例定时上报并且定时进行服务检查。 + +**业务逻辑** + +- 服务注册,项目启动时将当前服务实例id注册到redis +- 服务上报,每三分钟报告一次,并传入当前时间戳 +- 服务检查,每十分钟检查一次服务列表,清空超过五分钟没有报告的服务 + + +### 通道实例加载器 + + +通道实例加载器对应的为SmsConnectLoader类。 + +短信发送服务存在多个通道(例如阿里云短信、梦网短信等),这些通道是通过后台管理系统设置的,包括通道的名称、签名、模板、连接方式等信息。当短信发送服务启动时,或者后台管理系统设置通道时,将会初始化短信通道。 + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b7e35d7b7c6a46d5aa9c9186ed0328d6~tplv-k3u1fbpfcp-watermark.image) + +通道实例加载器的作用就是根据通道配置,初始化每个通道的Bean对象(例如AliyunSmsService、MengWangSmsService等)。 + +### 真正发送流程 + +``` + +/** + * 短信发送工厂 + 1. 获取构建好的短信通道 + 2. 调用通道方法,发送短信 + 3. 如果发送出现异常,触发通道选举和通道降级策略 + 4. 当通道选举被触发时:smsConnectLoader.buildNewConnect() + 5. 当通道降级被触发时:smsConnectLoader.changeNewConnectMessage() + 6. 记录短信发送日志 + */ +``` + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f597377dd25f45c0a2e8bfe6bf14bb98~tplv-k3u1fbpfcp-watermark.image) + +采用do while的模式,直到遍历所有的通道把短信成功发送 + +### 异步通道降级选举 +再真正下发短信的流程中 + +![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ed6aa178bf4d4f2c87dd148d77e7867e~tplv-k3u1fbpfcp-watermark.image) + +在一次真正向第三方发送短信的时候,如果发送失败,就会走进到这个重新排序通道逻辑,判断是否需要重排序 + +在这逻辑中有2个很关键的点 +- 固定阈值 (具体数值) +- 固定因子 (按比例) + + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4d49520c51b5464881620b8c8f11037c~tplv-k3u1fbpfcp-watermark.image) + +里面呢?有2个核心逻辑 +- 降级 +- 选举 + +### 异步通道选举流程 + +![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6fe6524996a04260b91c0a3b18239818~tplv-k3u1fbpfcp-watermark.image) + +通道选择,只能再一台通道中选举,所以用分布式锁。 + +**listForNewConnect 选择策略** + +``` +* 通道选举,选举策略: +* 1、剔除掉第一级通道 +* 2、查询最近一小时内通道发送短信数量,按数量排序通道 +* 3、如果最近一小时没有发送短信,按最后发送成功排序 +``` + +具体的逻辑还是有点东西的,哈哈。大家自己去看源码吧 + + + + +## 结束 +我觉得,这个项目的设计,技术,架构都是非常不错的,而且又全是crud,对于个人的帮助还是很不错的,如果有时间大家花点时间去吃透它,对于之后的架构设计,面试等都有很大的帮助,并且这个项目很小,代码量也少,花的时间也不多,我是非常推进的拉。好了,就到这了 我是小六六 三天打鱼,两天晒网。 + + + +## 日常求赞 +> 好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是**真粉**。 + +> 创作不易,各位的支持和认可,就是我创作的最大动力,我们下篇文章见 + +>微信 搜 "六脉神剑的程序人生" 回复888 有我找的许多的资料送给大家