前言
希望本文章可以给那些需要设计或重构自己公司短信基础服务同学指明道路,考虑更多、更长远,更具稳定性、扩展性。
一 背景
- 痛点1:旧短信基础服务不清楚上游调用情况,完全无法确定哪些服务调用了短信发送功能,或者无法确定已发送的短信是哪个服务调用的。
- 痛点2:旧短信基础服务非常不稳定,发送短信接口失败率接近5%,偶尔更高(因为集成到了已有的crm系统中,与系统的其他功能相互影响,导致其他功能也不稳定),稳定性差。
- 痛点3:旧短信基础服务没有接入短信供应商的回执,导致发送情况无法自查,无法监控供应商发送质量情况,而且排查问题都需要登陆到多家供应商后台去查短信发送情况,效率地下,账号存在外泄风险。
- 痛点4:旧短信基础服务没有接入供应商的上行短信,导致无法跟踪用户的上行回复情况,也无法做自己的黑名单控制,经常用户回T退订仅仅是退订了其中一个供应商的短信,导致经常收到用户投诉。
- 痛点5:旧短信基础服务接入新供应商很麻烦,增加短信类型更加麻烦,扩展性差。
- 痛点6:旧短信基础服务发送短信的过程是同步的,存在较大性能瓶颈,并发性能差。
二 针对以上痛点的设计
由于旧短信是以模块方式嵌入在crm系统的,无法直接在原基础上去重构,而是选择完全摒弃了原短信模块,整个短信基础服务用java重写。
先附一张我们短信基础服务的系统设计流程图:
以上流程图还有很多细节并未画出来,但是大致的整个系统的设计流程图就是这样。以下针对我们旧系统的的痛点看一下我们的解决方案。
1)针对痛点1
给短信系统加上了账号basic验证,其他服务调用短信服务,都需要提前申请basic auth的账号密码。并且在短信发送记录中保存了账号ID,确保每条短信都是可跟踪到是哪个服务发送的。
2)针对痛点2与6
使用了mq队列做了异步解耦,并且做了全方位的失败重试,特别是针对验证码短信,调供应商失败会重试、回执短时间失败会重试、30s(时间可设置)内没收到回执会重试,这很大程度提升了我们系统稳定性、并发性能。
3)针对痛点3与4
我们接了每个供应商的回执与上行短信,系统做了查询功能提供业务人员查询短信发送情况,也可人工管理黑名单等。
4)针对痛点5
为了方便供应商快速接入,我们使用了设计模式-工厂模式,每接入一个供应商,只需要实现了自己的工厂方法,把发送短信、回执处理、上行处理的方法处理好了即可。不需要额外修改其他地方。一般对接一个供应商都可以在1-2小时内完成。
针对添加短信类型(我们的短信类型最初只有验证码短信、营销短信,后来区分了通知短信、语音短信、语音验证码短信),我们抽象工厂抽象了短信发送的共同的特性,每增加一种类型,只需要处理好差异即可。
5)其他增强
供应商的通道可能会经常出问题,特别是营销短信,没对接回执之前,这些都是要一段时间去查查各供应商回执情况,都是后知后觉,无法快速发现并降权或置0权重,导致出现营销短信大批量失败都不得而知的情况。针对这个问题,我们用redis做了回执的简单统计,并每分钟把统计结果同步到了mysql。每次同步之前会校验每个供应商的回执情况,低于监控告警值的会及时告警,低于置0权重阈值的直接置0权重并告警,这些措施都大大增强了我们系统的稳定性,更加保障了我们短信发送到达率。
三 总结
一篇文章难以覆盖到我们短信基础服务的方方面面,但是却可以给大家以启迪,可以避免更多在短信基础服务设计方面的坑,让系统可以更强壮更具扩展性。