上篇《.net core实践系列之短信服务-为何选择.net core(开篇)》简单的介绍了(水了一篇).net core。此次针对短信服务的架构设计和技术栈的简析。html
源码地址:https://github.com/SkyChenSky/Sikiro.SMSgit
有人会问短信服务也要架构设计?不就写个service封装个send方法就得了吗?干吗还要大动干戈。github
若是在单块应用的状况下,以上面的作法是无可厚非的。数据库
然而架构设计解决的是应用复杂度,架构设计的大仍是小取决于业务规模,技术的使用是要落实到应用场景。服务器
以咱们公司做为例子:多线程
从上面场景分析出,要由多系统、多平台接入须要单独抽离出来进行服务化,并且随着接入的系统越多,性能将成为瓶颈,所以须要良好的横向拓展能力。定时发送须要调度任务系统进行解决。架构
所以下面为我设计的架构图框架
以HTTP协议RESTful风格JSON格式提供给其余系统(服务)接入,以swagger做为服务描述提供对外查看。post
接口主要功能有:性能
发送短信支持批量,接口接受到请求后将数据先持久化到MongoDB。
若是及时发送则马上发送RabbitMQ,再由Sikiro.SMS.Bus订阅队列进行统一发送;
若是定时发送则等待Sikiro.SMS.Job进行轮循MongoDB,轮询到时的消息则发送到RabbitMQ,再由Sikiro.SMS.Bus订阅队列进行统一发送。
此服务以Quartz.NET框架为基础,经过设计能够随意增长Trigger或者服务,使其多线程或多个进程同时运行,避免数据量大了后成为发送瓶颈。
此服务不直接作短信发送,只是触发器的存在,经过RabbitMQ进行解耦,避免执行过程过长若是中止服务时则中断。
不管定时、及时短信都由该服务进行发送,若是接入了新的短信运营商,只须要中止该服务进行更新便可。中止了服务消息不会丢失,将暂存在RabbitMQ,因需对RabbitMQ的消息作持久化。
能够在不一样的服务器上部署服务,由于订阅同一个队列,良好的横向扩展保证了高可用、高性能
可伸缩性指在不改变系统软硬件设计,仅仅经过新增服务器的状况下,就能提高系统的处理能力。
HTTP API的无状态,在调度任务里的MongoDB原子操做FindOneAndUpdate的使用,多消费者的订阅都是为了可伸缩性。同时经过部署多台服务器也能够提升高性能与高可用。
我选择MongoDB主要缘由是聚合一致性、无模式。
虽然说不须要ACID但不表明没有一致性,而MongoDB体现的聚合一致性,以聚合作操做。
一组具备内聚关系的相关对象的称为集合
则如下面两表经过SmsId关联读取,写入则两表做为一个事务
则如下面聚合方式表示,以聚合取,以聚合写
MongoDB一大特色则是无模式,意思是无需预先定义集合结构与字段类型,这体现了良好的拓展性。这是优势也是缺点,假如别的服务对该集合进行操做,在他不知情的状况下随意写入不一样类型的值,则会影响已运行的服务。
所以须要将此做为应用服务数据库,也就是服务化,把对集合的操做(读与写)以服务形式提供接口给其余服务使用。
有些人会问为何不把三个运营商Service也拆出来做为独立的API服务?
回顾下如今执行流程,一次短信发送最长的调用链为:请求SmsApi,Sikiro.SMS.Job轮询数据,Sikiro.SMS.Bus消费队列消息并请求短信运营商服务。
架构上的扩展性的本质的确是拆,可是拆得过细将出现三个问题:
假如哪天短信没发送成功,首先看看API日志看看是否是调用成功了,若是没问题那可能JOB出问题了。若是JOB正常跑,难道是队列问题?假如再加多一层,那就定位更加的复杂了。
就如开始所说的若是添加一个短信运营商只须要添加一个Service利用工厂模式,就能够良好的拓展了。而添加一个服务的开发、部署、维护成本无疑是比在组件内扩展的成本高。
该篇描述个人架构设计,下篇会正式对各个服务的实现进行讲解。若是您有更好的建议能够在下方评论反馈给我。
个人博客即将搬运同步至腾讯云+社区,邀请你们一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=jjdhw6o619ra