你真的瞭解延時隊列嗎(一)

1 使用場景

  • 關閉空閒鏈接。服務器中,有不少客戶端的鏈接,空閒一段時間以後須要關閉之。
  • 清理過時數據業務上。好比緩存中的對象,超過了空閒時間,須要從緩存中移出。
  • 任務超時處理。在網絡協議滑動窗口請求應答式交互時,處理超時未響應的請求。
  • 下單以後若是三十分鐘以內沒有付款就自動取消訂單。
  • 訂餐通知:下單成功後60s以後給用戶發送短信通知。
  • 當訂單一直處於未支付狀態時,如何及時的關閉訂單,並退還庫存?
  • 如何按期檢查處於退款狀態的訂單是否已經退款成功?
  • 新建立店鋪,N天內沒有上傳商品,系統如何知道該信息,併發送激活短信?
  • 定時任務調度:使用DelayQueue保存當天將會執行的任務和執行時間,一旦從DelayQueue中獲取到任務就開始執行。

2 延時任務-實現方式

  • 按期輪詢(數據庫等)
  • DelayQueue
  • Timer
  • ScheduledExecutorService
  • 時間輪(kafka)
  • RabbitMQ
  • Quartz
  • Redis Zset
  • Koala
  • JCronTab
  • SchedulerX(阿里)
  • 有贊延遲隊列

2.1 輪詢

特色:按期輪訓數據庫,設置狀態。java

優勢:實現簡單
缺點:數據量過大時會消耗太多的IO資源,效率過低
複製代碼

2.2 DelayQueue

特色: 無界、延遲、阻塞隊列面試

a、BlockingQueue+PriorityQueue(堆排序)+Delayed
b、DelayQueue中存放的對象須要實現compareTo()方法和getDelay()方法。
c、getDelay方法返回該元素距離失效還剩餘的時間,當<=0時元素就失效了,
就能夠從隊列中獲取到。
複製代碼

這裏爲何要用leader/follower模式?數據庫

  • 若是不是隊首節點,根本不須要喚醒操做!
  • 假設取值時,延時時間尚未到,那麼須要等待,但這個時候,隊列中新加入了一個延時更短的,並放在了隊首,那麼 此時,for循環由開始了,取得是新加入的元素,那以前的等待就白等了,明顯能夠早點退出等待!
  • 還有就是若是好多線程都在此等待,若是時間到了,同時好多線程會充等待隊列進入鎖池中,去競爭鎖資源,但結果只能是一個成功, 多了寫無畏的競爭!(屢次的等待和喚醒)

2.3 Timer與TimerTask

  • TaskQueue中的排序是對TimerTask中的下一次執行時間進行堆排序,每次去取數組第一個。
  • 而delayQueue是對queue中的元素的getDelay()結果進行排序

Timer是一種定時器工具,用來在一個後臺線程計劃執行指定任務。它能夠計劃執行一個任務一次或反覆屢次。 主要方法: 數組

2.4 時間輪(kafka)

時間輪名詞解釋:緩存

  • 時間格:環形結構中用於存放延遲任務的區塊;
  • 指針(CurrentTime):指向當前操做的時間格,表明當前時間
  • 格數(ticksPerWheel):爲時間輪中時間格的個數
  • 間隔(tickDuration):每一個時間格之間的間隔
  • 總間隔(interval):當前時間輪總間隔,也就是等於ticksPerWheel*tickDuration

根據每一個TimerTaskEntry的過時時間和當前時間輪的時間,選擇一個合適的bucket(實際上就是TimerTaskList),把這個TimerTaskEntry對象放進去,同時若是bucket的過時時間有更新,就將這個bucket推動DelayQueue,從新排序服務器

例子:假設編號爲0的時間格或者桶保存着到期時間爲t,每個tick的持續時間(tickDuration)爲20ms,在這個格子裏只能保存着到期時間爲[t~t+20]ms的任務,假設時間輪的時間格有n個,每個間隔1ms,到期時間爲m(ms),那麼計算公式m%n = 所在的時間格或者桶,好比n=10,m=34ms,那麼他所在桶或者時間格是4網絡

2.5 RabbitMQ-延時任務

RabbitMQ自己沒有直接支持延遲隊列功能,可是能夠經過如下特性模擬出延遲隊列的功能。多線程

RabbitMQ能夠針對Queue和Message設置 x-message-tt,來控制消息的生存時間,若是超時,則消息變爲dead letter RabbitMQ針對隊列中的消息過時時間有兩種方法能夠設置。 A: 經過隊列屬性設置,隊列中全部消息都有相同的過時時間。 B: 對消息進行單獨設置,每條消息TTL能夠不一樣。併發

2.6 Quartz

爲何不用Timer?工具

  • Timers沒有持久化機制.
  • Timers不靈活 (只能夠設置開始時間和重複間隔,不是基於時間、日期、天等(秒、分、時)的)
  • Timers 不能利用線程池,一個timer一個線程
  • Timers沒有真正的管理計劃

核心概念:調度器、任務和觸發器。

三者關係:調度器負責調度各個任務,到了某個時刻或者過了必定時間,觸發器觸動了,特定任務便啓動執行。

  1. scheduler是一個計劃調度器容器(總部),容器裏面能夠盛放衆多的JobDetail和trigger,當容器啓動後,裏面的每一個JobDetail都會根據trigger循序漸進自動去執行。
  2. JobDetail是一個可執行的工做,它自己是有狀態的。
  3. Trigger表明何時去調。
  4. 當JobDetail和Trigger在scheduler容器上註冊後,造成了裝配好的做業(JobDetail和Trigger所組成的一對兒),就能夠伴隨容器啓動而調度執行了。
  5. scheduler是個容器,容器中有一個線程池,用來並行調度執行每一個做業,這樣能夠提升容器效率。

待續。。。

若是上面問題有什麼疑問的話能夠關注公衆號,來和我一塊兒討論吧,關注便可免費領取海量最新java學習資料視頻,以及最新面試資料。

若是你們以爲這篇文章對你有幫助,或者你有什麼疑問想提供1v1免費vip服務,均可以關注個人公衆號,關注便可免費領取海量最新java學習資料視頻,以及最新面試資料,你的關注和轉發是對我最大的支持,O(∩_∩)O:

相關文章
相關標籤/搜索