高并發(fā)場景:下單后定時(shí)發(fā)短信的問題
問題描述:讓您做一個(gè)電商平臺(tái),您如何設(shè)置一個(gè)在買家下訂單后的”第60秒“發(fā)短信通知賣家發(fā)貨,您需要考慮的是 像淘寶一樣的大并發(fā)量的訂單。
從廣大網(wǎng)友集思廣益,有兩種主流思路如下:
1、具有排序功能的隊(duì)列
2、Redis+定時(shí)器
思路 1
原理:第一種思路也就是大家推薦的延遲隊(duì)列實(shí)現(xiàn)的原理,其就是一個(gè)按時(shí)間排好序的隊(duì)列,每次put的時(shí)候排序,然后take的時(shí)候就計(jì)算時(shí)間是否過期,如果過期則返回隊(duì)列第一個(gè)元素,否則當(dāng)前線程阻塞X秒,這個(gè)也是JDK 自帶 DelayQueue 的思路。詳細(xì)可看源碼
代碼實(shí)現(xiàn):待實(shí)現(xiàn)后補(bǔ)充
思路 2
原理:第二種思路需要利用Redis的有序集合,說到使用 Redis 就不得不考慮Score的設(shè)計(jì),因?yàn)樗苯記Q定你代碼的復(fù)雜度,你思路的清晰性,在這我并沒有采用林中漫步?先生的設(shè)計(jì),而是通過精確到秒的時(shí)間做Score(去掉毫秒),然后使用線程每一秒掃一次,使用當(dāng)前時(shí)間作為zrangeBysocre命令的Score去查詢。詳細(xì)請看代碼。
業(yè)務(wù)場景:按京東一天500萬的成交量,一天主要成交時(shí)間為8小時(shí),計(jì)算得出每秒173個(gè)訂單,當(dāng)然實(shí)際上訂單不能均勻分布在每秒,但我們主要為了論證思想的可行性。
代碼實(shí)現(xiàn):這里首先我簡單的利用Spring Scheduled作為訂單的生產(chǎn)者,每一秒制造170個(gè)訂單,放入Redis,注意Score的生成,為當(dāng)前時(shí)間的后60秒,removeMillis()生成去掉毫秒的時(shí)間戳作為Rredis的Zadd方法的 Score(不了解的可以百度下)。
第二步:同樣利用Spring Scheduled 一秒鐘心跳一次,每次利用當(dāng)前時(shí)間作為Key 從Redis 取數(shù)據(jù)。
經(jīng)過測試,沒有出現(xiàn)漏單的情況,這只是簡單的實(shí)現(xiàn),很多地方可以優(yōu)化,在實(shí)際中用也可能會(huì)出現(xiàn)很多問題,需要不斷完善,此案例只是提供思路,另外我覺得JDK的 DelayQueue 相對于Redis來說沒有那么好,因?yàn)镼ueue畢竟每次取一個(gè),如果同一時(shí)間的比較多可能不能符合當(dāng)前這種時(shí)間嚴(yán)謹(jǐn)?shù)男枨?,另外他是單機(jī)的,有時(shí)間我去研究下kafka、Rabbit的延遲隊(duì)列再來補(bǔ)充。
終于寫完了,因?yàn)楣镜拇a是加密的,所以不能上傳源碼了(其實(shí)也沒得什么上的,哈哈),另外本人技術(shù)有限難免會(huì)有紕漏或者錯(cuò)誤,歡迎拍磚,另外希望自己以后能夠堅(jiān)持寫技術(shù)日志。