国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

拼夕夕訂單超時未支付自動關閉實現方案!

開發 架構 開發工具
在開發中,往往會遇到一些關于延時任務的需求。例如:生成訂單 30 分鐘未支付,則自動取消;生成訂單 60 秒后,給用戶發短信。

 [[422166]]

圖片來自 包圖網

對上述的任務,我們給一個專業的名字來形容,那就是延時任務。那么這里就會產生一個問題,這個延時任務和定時任務的區別究竟在哪里呢?

一共有如下幾點區別:

  • 定時任務有明確的觸發時間,延時任務沒有
  • 定時任務有執行周期,而延時任務在某事件觸發后一段時間內執行,沒有執行周期
  • 定時任務一般執行的是批處理操作是多個任務,而延時任務一般是單個任務

下面,我們以判斷訂單是否超時為例,進行方案分析。

方案分析

①數據庫輪詢

思路:該方案通常是在小型項目中使用,即通過一個線程定時的去掃描數據庫,通過訂單時間來判斷是否有超時的訂單,然后進行 update 或 delete 等操作。

實現:博主當年早期是用 quartz 來實現的(實習那會的事),簡單介紹一下。

maven 項目引入一個依賴,如下所示:

  1. <dependency> 
  2.  
  3.     <groupId>org.quartz-scheduler</groupId> 
  4.  
  5.     <artifactId>quartz</artifactId> 
  6.  
  7.     <version>2.2.2</version> 
  8.  
  9. </dependency> 

調用 Demo 類 MyJob,如下所示:

  1. package com.rjzheng.delay1; 
  2.  
  3. import org.quartz.JobBuilder; 
  4.  
  5. import org.quartz.JobDetail; 
  6.  
  7. import org.quartz.Scheduler; 
  8.  
  9. import org.quartz.SchedulerException; 
  10.  
  11. import org.quartz.SchedulerFactory; 
  12.  
  13. import org.quartz.SimpleScheduleBuilder; 
  14.  
  15. import org.quartz.Trigger
  16.  
  17. import org.quartz.TriggerBuilder; 
  18.  
  19. import org.quartz.impl.StdSchedulerFactory; 
  20.  
  21. import org.quartz.Job; 
  22.  
  23. import org.quartz.JobExecutionContext; 
  24.  
  25. import org.quartz.JobExecutionException; 
  26.  
  27.  
  28.  
  29. public class MyJob implements Job { 
  30.  
  31.     public void execute(JobExecutionContext context) 
  32.  
  33.             throws JobExecutionException { 
  34.  
  35.         System.out.println("要去數據庫掃描啦。。。"); 
  36.  
  37.     } 
  38.  
  39.  
  40.  
  41.     public static void main(String[] args) throws Exception { 
  42.  
  43.         // 創建任務 
  44.  
  45.         JobDetail jobDetail = JobBuilder.newJob(MyJob.class) 
  46.  
  47.                 .withIdentity("job1""group1").build(); 
  48.  
  49.         // 創建觸發器 每3秒鐘執行一次 
  50.  
  51.         Trigger trigger = TriggerBuilder 
  52.  
  53.                 .newTrigger() 
  54.  
  55.                 .withIdentity("trigger1""group3"
  56.  
  57.                 .withSchedule( 
  58.  
  59.                         SimpleScheduleBuilder.simpleSchedule() 
  60.  
  61.                                 .withIntervalInSeconds(3).repeatForever()) 
  62.  
  63.                 .build(); 
  64.  
  65.         Scheduler scheduler = new StdSchedulerFactory().getScheduler(); 
  66.  
  67.         // 將任務及其觸發器放入調度器 
  68.  
  69.         scheduler.scheduleJob(jobDetail, trigger); 
  70.  
  71.         // 調度器開始調度任務 
  72.  
  73.         scheduler.start(); 
  74.  
  75.     } 
  76.  

運行代碼,可發現每隔 3 秒,輸出如下:要去數據庫掃描啦!

優缺點:

  • 優點:簡單易行,支持集群操作
  • 缺點:對服務器內存消耗大;存在延遲,比如你每隔 3 分鐘掃描一次,那最壞的延遲時間就是 3 分鐘;假設你的訂單有幾千萬條,每隔幾分鐘這樣掃描一次,數據庫損耗極大。

②JDK 的延遲隊列

思路:該方案是利用 JDK 自帶的 DelayQueue 來實現,這是一個無界阻塞隊列,該隊列只有在延遲期滿的時候才能從中獲取元素,放入 DelayQueue 中的對象,是必須實現 Delayed 接口的。

DelayedQueue 實現工作流程如下圖所示:

其中 Poll():獲取并移除隊列的超時元素,沒有則返回空。take():獲取并移除隊列的超時元素,如果沒有則 wait 當前線程,直到有元素滿足超時條件,返回結果。

實現:定義一個類 OrderDelay 實現 Delayed。

代碼如下:

  1. package com.rjzheng.delay2; 
  2.  
  3.  
  4.  
  5. import java.util.concurrent.Delayed; 
  6.  
  7. import java.util.concurrent.TimeUnit; 
  8.  
  9.  
  10.  
  11. public class OrderDelay implements Delayed { 
  12.  
  13.  
  14.  
  15.     private String orderId; 
  16.  
  17.     private long timeout; 
  18.  
  19.  
  20.  
  21.     OrderDelay(String orderId, long timeout) { 
  22.  
  23.         this.orderId = orderId; 
  24.  
  25.         this.timeout = timeout + System.nanoTime(); 
  26.  
  27.     } 
  28.  
  29.  
  30.  
  31.     public int compareTo(Delayed other) { 
  32.  
  33.         if (other == this) 
  34.  
  35.             return 0; 
  36.  
  37.         OrderDelay t = (OrderDelay) other; 
  38.  
  39.         long d = (getDelay(TimeUnit.NANOSECONDS) - t 
  40.  
  41.                 .getDelay(TimeUnit.NANOSECONDS)); 
  42.  
  43.         return (d == 0) ? 0 : ((d < 0) ? -1 : 1); 
  44.  
  45.     } 
  46.  
  47.  
  48.  
  49.     // 返回距離你自定義的超時時間還有多少 
  50.  
  51.     public long getDelay(TimeUnit unit) { 
  52.  
  53.         return unit.convert(timeout - System.nanoTime(),TimeUnit.NANOSECONDS); 
  54.  
  55.     } 
  56.  
  57.  
  58.  
  59.     void print() { 
  60.  
  61.         System.out.println(orderId+"編號的訂單要刪除啦。。。。"); 
  62.  
  63.     } 
  64.  

運行的測試 Demo 為,我們設定延遲時間為 3 秒:

  1. package com.rjzheng.delay2; 
  2.  
  3.  
  4.  
  5. import java.util.ArrayList; 
  6.  
  7. import java.util.List; 
  8.  
  9. import java.util.concurrent.DelayQueue; 
  10.  
  11. import java.util.concurrent.TimeUnit; 
  12.  
  13.  
  14.  
  15. public class DelayQueueDemo { 
  16.  
  17.      public static void main(String[] args) {   
  18.  
  19.             // TODO Auto-generated method stub   
  20.  
  21.             List<String> list = new ArrayList<String>();   
  22.  
  23.             list.add("00000001");   
  24.  
  25.             list.add("00000002");   
  26.  
  27.             list.add("00000003");   
  28.  
  29.             list.add("00000004");   
  30.  
  31.             list.add("00000005");   
  32.  
  33.             DelayQueue<OrderDelay> queue = newDelayQueue<OrderDelay>();   
  34.  
  35.             long start = System.currentTimeMillis();   
  36.  
  37.             for(int i = 0;i<5;i++){   
  38.  
  39.                 //延遲三秒取出 
  40.  
  41.                 queue.put(new OrderDelay(list.get(i),   
  42.  
  43.                         TimeUnit.NANOSECONDS.convert(3,TimeUnit.SECONDS)));   
  44.  
  45.                     try {   
  46.  
  47.                          queue.take().print();   
  48.  
  49.                          System.out.println("After " +   
  50.  
  51.                                  (System.currentTimeMillis()-start) + " MilliSeconds");   
  52.  
  53.                 } catch (InterruptedException e) {   
  54.  
  55.                     // TODO Auto-generated catch block   
  56.  
  57.                     e.printStackTrace();   
  58.  
  59.                 }   
  60.  
  61.             }   
  62.  
  63.         }   
  64.  
  65.  
  66.  

輸出如下:

  1. 00000001編號的訂單要刪除啦。。。。 
  2.  
  3. After 3003 MilliSeconds 
  4.  
  5. 00000002編號的訂單要刪除啦。。。。 
  6.  
  7. After 6006 MilliSeconds 
  8.  
  9. 00000003編號的訂單要刪除啦。。。。 
  10.  
  11. After 9006 MilliSeconds 
  12.  
  13. 00000004編號的訂單要刪除啦。。。。 
  14.  
  15. After 12008 MilliSeconds 
  16.  
  17. 00000005編號的訂單要刪除啦。。。。 
  18.  
  19. After 15009 MilliSeconds 

可以看到都是延遲 3 秒,訂單被刪除。

優缺點:

  • 優點:效率高,任務觸發時間延遲低。
  • 缺點:服務器重啟后,數據全部消失,怕宕機;集群擴展相當麻煩;因為內存條件限制的原因,比如下單未付款的訂單數太多,那么很容易就出現 OOM 異常;代碼復雜度較高。

③時間輪算法

思路:先上一張時間輪的圖。

時間輪算法可以類比于時鐘,如上圖箭頭(指針)按某一個方向按固定頻率輪動,每一次跳動稱為一個 tick。

這樣可以看出定時輪由個 3 個重要的屬性參數,ticksPerWheel(一輪的 tick 數),tickDuration(一個 tick 的持續時間)以及 timeUnit(時間單位)。

例如當 ticksPerWheel=60,tickDuration=1,timeUnit=秒,這就和現實中的始終的秒針走動完全類似了。

如果當前指針指在 1 上面,我有一個任務需要 4 秒以后執行,那么這個執行的線程回調或者消息將會被放在 5 上。

那如果需要在 20 秒之后執行怎么辦,由于這個環形結構槽數只到 8,如果要 20 秒,指針需要多轉 2 圈。位置是在 2 圈之后的 5 上面(20 % 8 + 1)。

實現:我們用 Netty 的 HashedWheelTimer 來實現。

給 Pom 加上下面的依賴:

  1. <dependency> 
  2.  
  3.     <groupId>io.netty</groupId> 
  4.  
  5.     <artifactId>netty-all</artifactId> 
  6.  
  7.     <version>4.1.24.Final</version> 
  8.  
  9. </dependency> 

測試代碼 HashedWheelTimerTest,如下所示:

  1. package com.rjzheng.delay3; 
  2.  
  3.  
  4.  
  5. import io.netty.util.HashedWheelTimer; 
  6.  
  7. import io.netty.util.Timeout; 
  8.  
  9. import io.netty.util.Timer; 
  10.  
  11. import io.netty.util.TimerTask; 
  12.  
  13.  
  14.  
  15. import java.util.concurrent.TimeUnit; 
  16.  
  17.  
  18.  
  19. public class HashedWheelTimerTest { 
  20.  
  21.     static class MyTimerTask implements TimerTask{ 
  22.  
  23.         boolean flag; 
  24.  
  25.         public MyTimerTask(boolean flag){ 
  26.  
  27.             this.flag = flag; 
  28.  
  29.         } 
  30.  
  31.         public void run(Timeout timeout) throws Exception { 
  32.  
  33.             // TODO Auto-generated method stub 
  34.  
  35.              System.out.println("要去數據庫刪除訂單了。。。。"); 
  36.  
  37.              this.flag =false
  38.  
  39.         } 
  40.  
  41.     } 
  42.  
  43.     public static void main(String[] argv) { 
  44.  
  45.         MyTimerTask timerTask = new MyTimerTask(true); 
  46.  
  47.         Timer timer = new HashedWheelTimer(); 
  48.  
  49.         timer.newTimeout(timerTask, 5, TimeUnit.SECONDS); 
  50.  
  51.         int i = 1; 
  52.  
  53.         while(timerTask.flag){ 
  54.  
  55.             try { 
  56.  
  57.                 Thread.sleep(1000); 
  58.  
  59.             } catch (InterruptedException e) { 
  60.  
  61.                 // TODO Auto-generated catch block 
  62.  
  63.                 e.printStackTrace(); 
  64.  
  65.             } 
  66.  
  67.             System.out.println(i+"秒過去了"); 
  68.  
  69.             i++; 
  70.  
  71.         } 
  72.  
  73.     } 
  74.  

輸出如下:

  1. 1秒過去了 
  2.  
  3. 2秒過去了 
  4.  
  5. 3秒過去了 
  6.  
  7. 4秒過去了 
  8.  
  9. 5秒過去了 
  10.  
  11. 要去數據庫刪除訂單了。。。。 
  12.  
  13. 6秒過去了 

優缺點:

  • 優點:效率高,任務觸發時間延遲時間比 delayQueue 低,代碼復雜度比 delayQueue 低。
  • 缺點:服務器重啟后,數據全部消失,怕宕機;集群擴展相當麻煩;因為內存條件限制的原因,比如下單未付款的訂單數太多,那么很容易就出現 OOM 異常。

④Redis 緩存

思路一:利用 Redis 的 zset。zset 是一個有序集合,每一個元素(member)都關聯了一個 score,通過 score 排序來取集合中的值。

zset 常用命令:

  • 添加元素:ZADD key score member [[score member] [score member] …]
  • 按順序查詢元素:ZRANGE key start stop [WITHSCORES]
  • 查詢元素 score:ZSCORE key member
  • 移除元素:ZREM key member [member …]

測試如下:

  1. 添加單個元素 
  2.  
  3.  
  4.  
  5. redis> ZADD page_rank 10 google.com 
  6.  
  7. (integer) 1 
  8.  
  9.  
  10.  
  11.  
  12.  
  13. 添加多個元素 
  14.  
  15.  
  16.  
  17. redis> ZADD page_rank 9 baidu.com 8 bing.com 
  18.  
  19. (integer) 2 
  20.  
  21.  
  22.  
  23. redis> ZRANGE page_rank 0 -1 WITHSCORES 
  24.  
  25. 1) "bing.com" 
  26.  
  27. 2) "8" 
  28.  
  29. 3) "baidu.com" 
  30.  
  31. 4) "9" 
  32.  
  33. 5) "google.com" 
  34.  
  35. 6) "10" 
  36.  
  37.  
  38.  
  39. 查詢元素的score值 
  40.  
  41. redis> ZSCORE page_rank bing.com 
  42.  
  43. "8" 
  44.  
  45.  
  46.  
  47. 移除單個元素 
  48.  
  49.  
  50.  
  51. redis> ZREM page_rank google.com 
  52.  
  53. (integer) 1 
  54.  
  55.  
  56.  
  57. redis> ZRANGE page_rank 0 -1 WITHSCORES 
  58.  
  59. 1) "bing.com" 
  60.  
  61. 2) "8" 
  62.  
  63. 3) "baidu.com" 
  64.  
  65. 4) "9" 

那么如何實現呢?我們將訂單超時時間戳與訂單號分別設置為 score 和 member,系統掃描第一個元素判斷是否超時。

具體如下圖所示:

實現一:

  1. package com.rjzheng.delay4; 
  2.  
  3.  
  4.  
  5. import java.util.Calendar; 
  6.  
  7. import java.util.Set
  8.  
  9.  
  10.  
  11. import redis.clients.jedis.Jedis; 
  12.  
  13. import redis.clients.jedis.JedisPool; 
  14.  
  15. import redis.clients.jedis.Tuple; 
  16.  
  17.  
  18.  
  19. public class AppTest { 
  20.  
  21.     private static final String ADDR = "127.0.0.1"
  22.  
  23.     private static final int PORT = 6379; 
  24.  
  25.     private static JedisPool jedisPool = new JedisPool(ADDR, PORT); 
  26.  
  27.  
  28.  
  29.  
  30.     public static Jedis getJedis() { 
  31.  
  32.        return jedisPool.getResource(); 
  33.  
  34.     } 
  35.  
  36.  
  37.  
  38.  
  39.     //生產者,生成5個訂單放進去 
  40.  
  41.     public void productionDelayMessage(){ 
  42.  
  43.         for(int i=0;i<5;i++){ 
  44.  
  45.             //延遲3秒 
  46.  
  47.             Calendar cal1 = Calendar.getInstance(); 
  48.  
  49.             cal1.add(Calendar.SECOND, 3); 
  50.  
  51.             int second3later = (int) (cal1.getTimeInMillis() / 1000); 
  52.  
  53.             AppTest.getJedis().zadd("OrderId",second3later,"OID0000001"+i); 
  54.  
  55.             System.out.println(System.currentTimeMillis()+"ms:redis生成了一個訂單任務:訂單ID為"+"OID0000001"+i); 
  56.  
  57.         } 
  58.  
  59.     } 
  60.  
  61.  
  62.  
  63.  
  64.     //消費者,取訂單 
  65.  
  66.     public void consumerDelayMessage(){ 
  67.  
  68.         Jedis jedis = AppTest.getJedis(); 
  69.  
  70.         while(true){ 
  71.  
  72.             Set<Tuple> items = jedis.zrangeWithScores("OrderId", 0, 1); 
  73.  
  74.             if(items == null || items.isEmpty()){ 
  75.  
  76.                 System.out.println("當前沒有等待的任務"); 
  77.  
  78.                 try { 
  79.  
  80.                     Thread.sleep(500); 
  81.  
  82.                 } catch (InterruptedException e) { 
  83.  
  84.                     // TODO Auto-generated catch block 
  85.  
  86.                     e.printStackTrace(); 
  87.  
  88.                 } 
  89.  
  90.                 continue
  91.  
  92.             } 
  93.  
  94.             int  score = (int) ((Tuple)items.toArray()[0]).getScore(); 
  95.  
  96.             Calendar cal = Calendar.getInstance(); 
  97.  
  98.             int nowSecond = (int) (cal.getTimeInMillis() / 1000); 
  99.  
  100.             if(nowSecond >= score){ 
  101.  
  102.                 String orderId = ((Tuple)items.toArray()[0]).getElement(); 
  103.  
  104.                 jedis.zrem("OrderId", orderId); 
  105.  
  106.                 System.out.println(System.currentTimeMillis() +"ms:redis消費了一個任務:消費的訂單OrderId為"+orderId); 
  107.  
  108.             } 
  109.  
  110.         } 
  111.  
  112.     } 
  113.  
  114.  
  115.  
  116.  
  117.     public static void main(String[] args) { 
  118.  
  119.         AppTest appTest =new AppTest(); 
  120.  
  121.         appTest.productionDelayMessage(); 
  122.  
  123.         appTest.consumerDelayMessage(); 
  124.  
  125.     } 
  126.  
  127.  
  128.  
  129.  

此時對應輸出如下:

可以看到,幾乎都是 3 秒之后,消費訂單。

然而,這一版存在一個致命的硬傷,在高并發條件下,多消費者會取到同一個訂單號,我們上測試代碼 ThreadTest:

  1. package com.rjzheng.delay4; 
  2.  
  3.  
  4.  
  5. import java.util.concurrent.CountDownLatch; 
  6.  
  7.  
  8.  
  9. public class ThreadTest { 
  10.  
  11.     private static final int threadNum = 10; 
  12.  
  13.     private static CountDownLatch cdl = newCountDownLatch(threadNum); 
  14.  
  15.     static class DelayMessage implements Runnable{ 
  16.  
  17.         public void run() { 
  18.  
  19.             try { 
  20.  
  21.                 cdl.await(); 
  22.  
  23.             } catch (InterruptedException e) { 
  24.  
  25.                 // TODO Auto-generated catch block 
  26.  
  27.                 e.printStackTrace(); 
  28.  
  29.             } 
  30.  
  31.             AppTest appTest =new AppTest(); 
  32.  
  33.             appTest.consumerDelayMessage(); 
  34.  
  35.         } 
  36.  
  37.     } 
  38.  
  39.     public static void main(String[] args) { 
  40.  
  41.         AppTest appTest =new AppTest(); 
  42.  
  43.         appTest.productionDelayMessage(); 
  44.  
  45.         for(int i=0;i<threadNum;i++){ 
  46.  
  47.             new Thread(new DelayMessage()).start(); 
  48.  
  49.             cdl.countDown(); 
  50.  
  51.         } 
  52.  
  53.     } 
  54.  

輸出如下所示:

顯然,出現了多個線程消費同一個資源的情況。

解決方案:

(1)用分布式鎖,但是用分布式鎖,性能下降了,該方案不細說。

(2)對 ZREM 的返回值進行判斷,只有大于 0 的時候,才消費數據,于是將 consumerDelayMessage() 方法里的:

  1. if(nowSecond >= score){ 
  2.  
  3.     String orderId = ((Tuple)items.toArray()[0]).getElement(); 
  4.  
  5.     jedis.zrem("OrderId", orderId); 
  6.  
  7.     System.out.println(System.currentTimeMillis()+"ms:redis消費了一個任務:消費的訂單OrderId為"+orderId); 
  8.  

修改為:

  1. if(nowSecond >= score){ 
  2.  
  3.     String orderId = ((Tuple)items.toArray()[0]).getElement(); 
  4.  
  5.     Long num = jedis.zrem("OrderId", orderId); 
  6.  
  7.     if( num != null && num>0){ 
  8.  
  9.         System.out.println(System.currentTimeMillis()+"ms:redis消費了一個任務:消費的訂單OrderId為"+orderId); 
  10.  
  11.     } 
  12.  

在這種修改后,重新運行 ThreadTest 類,發現輸出正常了。

思路二:該方案使用 Redis 的 Keyspace Notifications。中文翻譯就是鍵空間機制,就是利用該機制可以在 key 失效之后,提供一個回調,實際上是 Redis 會給客戶端發送一個消息。是需要 Redis 版本 2.8 以上。

實現二:在 redis.conf 中,加入一條配置:

  1. notify-keyspace-events Ex 

運行代碼如下:

  1. package com.rjzheng.delay5; 
  2.  
  3.  
  4.  
  5. import redis.clients.jedis.Jedis; 
  6.  
  7. import redis.clients.jedis.JedisPool; 
  8.  
  9. import redis.clients.jedis.JedisPubSub; 
  10.  
  11.  
  12.  
  13. public class RedisTest { 
  14.  
  15.     private static final String ADDR = "127.0.0.1"
  16.  
  17.     private static final int PORT = 6379; 
  18.  
  19.     private static JedisPool jedis = new JedisPool(ADDR, PORT); 
  20.  
  21.     private static RedisSub sub = new RedisSub(); 
  22.  
  23.  
  24.  
  25.  
  26.  
  27.     public static void init() { 
  28.  
  29.         new Thread(new Runnable() { 
  30.  
  31.             public void run() { 
  32.  
  33.                 jedis.getResource().subscribe(sub, "__keyevent@0__:expired"); 
  34.  
  35.             } 
  36.  
  37.         }).start(); 
  38.  
  39.     } 
  40.  
  41.  
  42.  
  43.  
  44.  
  45.     public static void main(String[] args) throws InterruptedException { 
  46.  
  47.         init(); 
  48.  
  49.         for(int i =0;i<10;i++){ 
  50.  
  51.             String orderId = "OID000000"+i; 
  52.  
  53.             jedis.getResource().setex(orderId, 3, orderId); 
  54.  
  55.             System.out.println(System.currentTimeMillis()+"ms:"+orderId+"訂單生成"); 
  56.  
  57.         } 
  58.  
  59.     } 
  60.  
  61.  
  62.  
  63.  
  64.     static class RedisSub extends JedisPubSub { 
  65.  
  66.         <ahref='http://www.jobbole.com/members/wx610506454'>@Override</a> 
  67.  
  68.         public void onMessage(String channel, String message) { 
  69.  
  70.             System.out.println(System.currentTimeMillis()+"ms:"+message+"訂單取消"); 
  71.  
  72.         } 
  73.  
  74.     } 
  75.  

輸出如下:

可以明顯看到 3 秒過后,訂單取消了。PS:Redis 的 pub/sub 機制存在一個硬傷,官網內容如下:

原文:Because Redis Pub/Sub is fire and forget currently there is no way to use this feature if your application demands reliable notification of events, that is, if your Pub/Sub client disconnects, and reconnects later, all the events delivered during the time the client was disconnected are lost.

翻譯:Redis 的發布/訂閱目前是即發即棄(fire and forget)模式的,因此無法實現事件的可靠通知。也就是說,如果發布/訂閱的客戶端斷鏈之后又重連,則在客戶端斷鏈期間的所有事件都丟失了。因此,方案二不是太推薦。當然,如果你對可靠性要求不高,可以使用。

優缺點:

  • 優點:由于使用 Redis 作為消息通道,消息都存儲在 Redis 中。如果發送程序或者任務處理程序掛了,重啟之后,還有重新處理數據的可能性;做集群擴展相當方便;時間準確度高。
  • 缺點:需要額外進行 Redis 維護。

⑤使用消息隊列

我們可以采用 RabbitMQ 的延時隊列。RabbitMQ 具有以下兩個特性,可以實現延遲隊列。

  • RabbitMQ 可以針對 Queue 和 Message 設置 x-message-tt,來控制消息的生存時間,如果超時,則消息變為 dead letter。
  • lRabbitMQ的 Queue 可以配置 x-dead-letter-exchange 和 x-dead-letter-routing-key(可選)兩個參數,用來控制隊列內出現了 deadletter,則按照這兩個參數重新路由。

結合以上兩個特性,就可以模擬出延遲消息的功能。

優缺點:

  • 優點:高效,可以利用 RabbitMQ 的分布式特性輕易的進行橫向擴展,消息支持持久化增加了可靠性。
  • 缺點:本身的易用度要依賴于 RabbitMQ 的運維,因為要引用 RabbitMQ,所以復雜度和成本變高。

作者:hjm4702192

編輯:陶家龍

出處:http://adkx.net/w73gf

 

責任編輯:武曉燕 來源: adkx.net
相關推薦

2025-04-22 08:01:00

2021-01-08 08:30:04

996ICUPDD

2024-03-28 08:32:10

美團關閉訂單輪訓

2025-08-01 04:10:00

RocketMQ訂單分布式

2020-10-21 09:25:01

互聯網訂單自動關閉

2023-01-30 08:12:53

訂單超時自動取消延長訂單

2024-02-26 08:50:37

訂單自動取消消息

2022-12-01 08:25:03

訂單超時定時任務

2024-12-20 08:20:46

2016-02-25 10:09:15

MapReduceHadoopHDFS

2025-05-09 09:31:31

支付訂單Timer

2018-08-17 16:53:00

商派ERP

2021-08-23 11:03:54

鴻蒙HarmonyOS應用

2021-08-20 14:26:17

鴻蒙HarmonyOS應用

2022-03-02 15:14:09

訂單計時器持久化

2018-08-19 14:30:42

女性分析網站

2015-08-21 17:10:03

云安全

2012-08-24 10:49:51

備份恢復

2020-08-26 06:04:25

信息泄露密鑰加密信息安全

2023-08-22 21:39:25

點贊
收藏

51CTO技術棧公眾號

国产乱理伦片在线观看夜一区| 一区二区三区在线观看免费| 欧美福利在线播放网址导航| 欧美在线色图| 蜜乳av一区二区| 国产精品美女在线观看| 久久久久久一区| 粉嫩一区二区三区国产精品| 99精品综合| 国产区视频在线| 成人综合视频在线| 国产日韩第一页| 日本香蕉视频在线观看| 日韩中文字幕在线免费| 免费看a级黄色片| 天堂av在线资源| 国产欧美日韩视频在线| 欧美视频在线观看免费| 国产一区欧美二区| 国产精品久久久久久久| 成人a在线观看高清电影| 黄色污网站在线免费观看| 蜜臀久久99精品久久久画质超高清| 黄色网页在线免费看| 97视频在线| 在线看成人av电影| 成人有码在线视频| 欧美大片免费观看在线观看网站推荐| 欧美酷刑日本凌虐凌虐| 亚洲精选一二三| 国产精品99久久久久久有的能看| 久久成人久久鬼色| 金瓶狂野欧美性猛交xxxx| 区一区二日本| 自拍偷拍视频在线| 国产精品免费一区二区三区四区| 97色伦亚洲国产| 亚洲欧美国产精品| 在线电影欧美成精品| 麻豆国产欧美日韩综合精品二区| 99ri日韩精品视频| 国产亚洲毛片| 国产女主播一区| 欧美卡1卡2卡| 91精品91久久久久久| 亚洲欧美日韩在线综合| 老司机在线视频二区| 精品高清久久| 国产理论电影在线观看| 99久久精品国产导航| 国产www.大片在线| 97se亚洲国产一区二区三区| 午夜cr在线观看高清在线视频完整版| 国产极品尤物在线| 日韩中文一区| 97人人模人人爽人人少妇| 91精品国产色综合久久不卡98口| 一区二区欧美亚洲| 亚洲第一免费播放区| 在线免费精品视频| 亚洲成av人片一区二区| 中文字幕在线一区二区三区| 99精品桃花视频在线观看| 美女视频黄a大片欧美| 日韩视频在线一区二区三区| 天天操综合网| 欧美日韩国产免费观看视频| 好吊妞视频这里有精品| 欧美a在线观看| 开心久久婷婷综合中文字幕| 中文字幕乱码中文乱码51精品| 污视频在线看网站| 久操视频在线免费播放| 91社区在线观看| 国产成+人+综合+亚洲欧美丁香花| 在线中文字幕一区| av最新地址| 一区二区三区欧美日| 白天操夜夜操| 国产成人一区在线| 精品999在线观看| 五月婷婷在线视频| 国产精品久久久久精k8| 国产欧美一区二区三区另类精品| 在线毛片观看| 亚洲在线久久| 精品欧美一区二区三区精品久久 | 正在播放一区二区三区| 国产亚洲依依| 午夜精品久久久久久久99水蜜桃| 黄色三级中文字幕| 国产精品久久久久7777按摩| a视频在线看| 亚洲国产一区二区三区在线观看| a天堂资源在线| 亚洲三级免费看| 精精国产xxx在线视频app| 五月婷婷激情综合| 欧美日韩一区二区三区在线观看免 | 97久久综合精品久久久综合| 欧美视频中文字幕| a在线观看免费视频| 18欧美乱大交hd1984| 韩国一区二区电影| 国产精品蜜月aⅴ在线| 精品国产一区二区三区久久狼5月| 电影亚洲精品噜噜在线观看| 国产成人精品亚洲精品| 欧美亚洲一区二区三区| 青青在线视频免费| 欧美撒尿777hd撒尿| 国产 日韩 欧美| 国产精品第一区| 精品一区二区三区在线播放| 看高清中日韩色视频| 免费观看成人av| 国产精品日韩专区| 欧美久久99| 99超碰麻豆| 91成人精品| 91精品视频在线看| 最新国产在线拍揄自揄视频| 亚洲免费在线视频| 女人裸体免费网站| 日韩视频在线你懂得| 午夜激情电影在线播放| 亚洲精品xxxx| 欧美a级在线观看| 欧美国产日韩免费| 亚洲网色网站| 国产乱码一区| 欧美a级片一区| 国产男人精品视频| 免费成人三级| 九九精品在线播放| 精品日产乱码久久久久久仙踪林| 欧美一级免费观看| 18av在线视频| 欧美日韩一区二区三区在线看| 四虎精品一区二区免费| 亚洲一区免费网站| 国产日韩一区| 亚洲欧洲国产日韩精品| 成人av动漫在线| 一区二区三区四区五区视频| 天天久久综合| 99热这里只有精品7| 国产亚洲午夜高清国产拍精品| 五月天av在线播放| 在线观看一区不卡| 天天免费亚洲黑人免费| 日韩精品影音先锋| 91国内精品久久| 国产精品99| 91黄色8090| 欧美成人基地| 亚洲精品第一国产综合精品| 欧美18—19sex性hd| 91啪国产在线| 99久久久免费精品国产一区二区 | 日韩精品一区二区三区免费视频| 欧美性三三影院| 白嫩白嫩国产精品| 92福利视频午夜1000合集在线观看 | 国产亚洲精品美女久久| 国产精品v一区二区三区| 成人中文字幕电影| 精品久久久久久久久久ntr影视| 精品无人区太爽高潮在线播放| 国产v综合ⅴ日韩v欧美大片| 亚洲一区免费看| 色资源网在线观看| 国产麻豆一区二区三区| 欧美亚洲网站| 亚洲国产精品自拍| 最近免费中文字幕视频2019| 99精彩视频在线观看免费| 超碰影院在线观看| 99色在线观看| 中文字幕免费一区二区三区| 久久久91精品国产一区二区三区| 欧美一区二区精美| 91精品久久久久久久久久久久久| 国产免费黄色小视频| 在线中文字幕第一页| 国产欧美久久一区二区三区| 国产成人综合在线播放| 欧洲国产伦久久久久久久| 久久99精品国产99久久6尤物| 日韩国产欧美一区| 欧美一区二区视频| 亚洲图色一区二区三区| 久久精品国产999大香线蕉| 91久久奴性调教| 欧美有码在线观看视频| 国产不卡一区二区视频| 日本大胆在线观看| 精品999日本| 午夜av一区二区| 欧美做受高潮电影o|