又來水文了...
但感覺沒什么其他內容可寫,就將之前做的一個消息平台稍微做點總結.
簡單說說短信模塊的實現,做的東西不復雜,權當總結了~.
需求
功能需求
功能需求比較直接.
需要提供一些短信和統計功能即可:
- 通知短信
- 驗證碼短信
- 語音短信
- 發送量統計
非功能需求
主要是以下幾點
- 穩定的發送保證:
分為兩部分,一個是服務本身的穩定性,另一個是短信服務提供商的穩定性.
服務本身穩定是自己需要實現的,可以通過微服務平台已經有的一些工具保證,這里不進行展開.而另一個是需要外部保證的,外部需要保證的東西永遠是脆弱的,所以不能僅僅使用一家服務商,需要使用多家. - 方便擴展:
接着第一點,服務商可能會有更換的需求,需要保證能夠方便接入下架服務商. - 資產保護:
短信相比郵件,微信通知等的一個不同是他花費比較高,一條的計價在3分左右,較長的短信會被拆為多條,如果不加限制進行保護很容易造成大量的資損.
技術選型
有了上面的需求之后就是選用什么技術了.
基礎的web服務就使用公司現有的即可.
對於存儲,因為涉及到發送信息和報告的記錄,量可能會很大(其實上線之后也還好,3個月不到千萬記錄),統計時可能會按照某些發送內容統計,使用MySQL之類的可能會不太靠譜,選擇使用ES.
對於安全,一定需要做手機號每日發送量和發送頻率等的限制,這個用redis可以較為輕松解決.
最后一個簡化版的架構圖如下:
實現細節
上面都是這個服務戰略上的一些東西,這里說一些戰術上的.
接入多家服務商
需要有多家服務商的接入,一家服務商可能同時供應多個短信功能.
同時同一個短信功能需要輪流調用所有提供的服務商,並在一家失敗后進行重試.
也需要支持靈活的配置,可以禁用掉一些服務商,也可以方便加入新的.
在實現上先定義了各個發送功能接口,例如:
interface NotiSmsSender {
SmsSubmitResult sendNoti(NotiRequest request);
}
interface VerifyCodeSmsSender {
SmsSubmitResult sendVerifyCode(VerifyCodeRequest request);
}
對應的服務商實現不同的接口,提供不同的服務,每個對應的實現都有一個id字段,用於之后的配置.
現在有了一坨sender,接下來要定義router,用來進行請求的分發.
router內含有sender列表,配置router內的sender就可以實現服務商的下線功能了.
大致流程如下:
實際實現中使用了Akka,各個sender是一個actor,router負責監督各個sender的健康情況,此外天然獲得了超時時間的能力(底層使用了異步HttpClient,actor內部不會發生阻塞).
發送限制設置
關於手機號和ip的發送數量計數使用reids
的incr
配合時間戳相關的key就可以很簡單完成,這里不累述這個.
發送限制的話首先要針對不同功能,因為不同功能的使用量是截然不同的,並且也有隔離的作用,一個功能超限不能影響其他功能.
其次,發送的限制需要分層級,當達到了全局最大限制后,就算沒有超過單手機限制也不應該發出去了.
使用的層次是:
功能全局次數(次數) -> 單接入應用限制(次數/白名單/開關) -> 單手機/ip限制(次數/白名單/開關) -> 風控服務(開關)
最后次數要根據統計情況和業務更改做適當調整.
性能
這個服務很明顯是IO密集的,就沒什么計算,主要是調用各種外部服務,等IO返回.
所以對於這些各個用來做請求的線程池就可以配置稍微大一點,實際最主要的就是HTTP的連接池.但連接超時,讀取超時也不適合設置過大.
實際測試也沒多大問題,平日一天短信請求量也在幾w左右,並沒有太大的瓶頸.
其他的一些點和普通的web服務也大同小異了,沒有什么特別的技巧.
其實之前一些文章也是在構建這個服務的時候寫的,這段時間沒寫什么就當划水了,比如:
Akka實踐一些總結
ES踩坑筆記
這個服務構建的時候根據需要用了些之前沒有使用的組件,也算額外獲得了一些回報吧~