前言
文本已收錄至我的GitHub倉庫,歡迎Star:github.com/bin39232820…種一棵樹最好的時間是十年前,其次是現在
Tips
開源項目推薦系列是,小六六平時不是會逛逛開源平台嘛!然後就想着把一些項目分享給到大家,給大家說說我對這個開源項目的一些看法,當然,在寫的過程中,也可以讓自己的知識面更廣,希望能給大家帶來不一樣的東西。
短信網關
為啥要用短信網關
随着企業業務擴張、應用成倍的增加、短信規模化使用,傳統短信平台的接入方式和單一的資訊發送功能,已經不能完全滿足現代企業管理的需求,是以統一入口、減少對接成本、同時兼顧多種短信業務、簡單易行的操作與維護、高穩定、高可靠的移動資訊化應用成為短信平台發展趨勢。
- 服務越來越多,每個服務都有可能發送短信,是否每個服務都需要對接一遍?
- 多應用對接短信,如何做到短信發送服務高效、穩定?
- 短信通道出現異常時,如何快速切換通道?
- 切換通道時,如何做到應用服務無感覺?
- 如何統計各服務短信發送情況,以便進行後續營銷分析?
本項目(集信達短信平台)的核心在于保證短信高效、準确的送達、簡單易操作的對接方式。通過對服務的解耦、通訊方式的更新來提升系統的吞吐量。同時在多通道的加持下,通過智能動态的通道評級、選舉、降級、熱插拔,增強了系統的健壯性,擺脫對單一通道的依賴。并且提供多種對接方式,滿足企業内部的各種需求。
平台架構
集信達短信平台的整體架構如下:
主要有以下幾個服務
- pd-sms-api 給業務用
- pd-sms-manage 背景管理
- pd-sms-server 真正發送短信
業務架構
通過上面的業務架構可以看到,短信接收服務(pd-sms-api)提供3種方式供業務系統調用:
- HTTP接口
- TCP
- SDK形式
短信接收服務通過資質驗證(可開關)、短信内容校驗後将短信資訊發送到對應中間件中(Redis、MySQL)。
短信發送方式分為兩種類型:
- 定時發送短信:将短信内容存儲到MySQL資料庫中,由短信發送服務通過定時任務擷取并發送
- 普通短信:将短信内容推送到Redis隊列中,由短信發送服務異步接收并發送
項目結構
集信達短信平台,項目整體工程結構和子產品功能如下:
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
處理流程:
短信接收服務接收到應用系統請求後,會進行相關的校驗處理,校驗通過則将資訊儲存到消息緩存區,具體處理流程如下:
短信發送服務的發送過程
相關功能:
- 和具體的短信通道對接(例如:阿裡雲短信、夢網短信等),發送短信
- 短信定時發送
- 短信實時發送
- 服務注冊,保證短信發送服務高可用
- 通道自動選舉、降級
處理過程:
項目亮點
架構的設計
架構的設計和耦合性還是很好的,代碼的風格也很優雅,代碼通俗易懂,我随機截取一個類給大家看看
短信發送服務核心類
- 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類。
短信發送服務存在多個通道(例如阿裡雲短信、夢網短信等),這些通道是通過背景管理系統設定的,包括通道的名稱、簽名、模闆、連接配接方式等資訊。當短信發送服務啟動時,或者背景管理系統設定通道時,将會初始化短信通道。
通道執行個體加載器的作用就是根據通道配置,初始化每個通道的Bean對象(例如AliyunSmsService、MengWangSmsService等)。
真正發送流程
/**
* 短信發送工廠
1. 擷取建構好的短信通道
2. 調用通道方法,發送短信
3. 如果發送出現異常,觸發通道選舉和通道降級政策
4. 當通道選舉被觸發時:smsConnectLoader.buildNewConnect()
5. 當通道降級被觸發時:smsConnectLoader.changeNewConnectMessage()
6. 記錄短信發送日志
*/
采用do while的模式,直到周遊所有的通道把短信成功發送
異步通道降級選舉
再真正下發短信的流程中
在一次真正向第三方發送短信的時候,如果發送失敗,就會走進到這個重新排序通道邏輯,判斷是否需要重排序
在這邏輯中有2個很關鍵的點
- 固定門檻值 (具體數值)
- 固定因子 (按比例)
裡面呢?有2個核心邏輯
- 降級
- 選舉
異步通道選舉流程
通道選擇,隻能再一台通道中選舉,是以用分布式鎖。
* 通道選舉,選舉政策:
* 1、剔除掉第一級通道
* 2、查詢最近一小時内通道發送短信數量,按數量排序通道
*