1. 程式人生 > 程式設計 >關於定時發簡訊業務的討論

關於定時發簡訊業務的討論

事情的起因

需求:在每次線下活動的開始的前一天晚上七點給報名參加價值研習社的使用者發一條通知簡訊使用者記得準時參加活動。

備註:因為我們的業務併發不是很大,所以很多場景並沒有考慮到併發情況下的一些問題,這個需求正好通過crontab執行,並且加上伺服器的自動彈性伸縮,所以相當於模擬了一次併發的業務場景。

先簡單介紹一下資料庫的表結構:

image-20190808234028254

image-20190808234108517

image-20190808234134634

這幾個方案都依賴每天晚上七點執行一次corntab。

方案1

根據開講時間查詢活動表是否有滿足條件的線下活動,如果有的話,再通過活動id關聯到簽到表過濾出send_sms欄位為0的uid並關聯使用者表拿出手機號等資訊。傳送完成後再統一更新send_sms欄位。

缺點:在併發業務場景下,可能會產生髒讀的情況,造成傳送多次簡訊的情況。

方案2

與方案1很相似,唯一的區別就是查詢的時候開啟事務用SELECT ... FOR UPDATE ,這種查詢語句的區別就是在SELECT的時候把結果行上鎖,從而就能避免髒讀,然後再同一個事務中UPDATE send_sms欄位,最後commit

缺點:由於發簡訊不是資料庫操作,不可回滾。所以如果執行的過程中發生回滾,就會出現簡訊已經發出去了,但是資料庫發生回滾,send_sms欄位置為了0,這就產生了矛盾。而且如果是個耗時的任務可能會出現死鎖的問題。

以下就是執行的邏輯

BEGIN;
SELECT ... FOR UPDATE;
UPDATE ... SET send_sms = 1;
COMMIT;
複製程式碼

方案3

與方案2很相似,唯一的區別就是一條一條的取資料上鎖,然後更新send_sms欄位。

缺點:要寫一個迴圈一直去查詢滿足條件但還未傳送簡訊的使用者。處理不好容易產生死迴圈以及死鎖的問題。

方案4

這是我目前能想到的最佳方案,直接用SELECT語句選出所有滿足條件的手機號碼以及簡訊內容,放入Queue中,然後實現對Queue的處理。處理如下:先用SELECT ... FOR UPDATE 判斷send_sms欄位的值,如果為0,那就執行發簡訊,然後更新send_sms欄位為1,最後COMMIT 。這樣就可以避免多次執行發簡訊。

總結:對於這種對實時性要求沒那麼高的業務場景用Queue 還是非常便利的,讓Queue

一條一條的處理,在複雜的系統中還起到了削峰和解耦的作用。大家在工作中有哪些對Queue的應用呢?歡迎留言,一起討論!

大家對上面的這些方案有什麼建議呢?歡迎留言討論!