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

Redis延時(shí)隊(duì)列,這次徹底給你整明白了

存儲(chǔ) 存儲(chǔ)軟件 Redis
有了 Redis,對于那些只有一組消費(fèi)者的消息隊(duì)列,使用 Redis 就可以非常輕松的搞定。Redis 的消息隊(duì)列不是專業(yè)的消息隊(duì)列,它沒有非常多的高級特性, 沒有 ack 保證,如果對消息的可靠性有著極致的追求,那么它就不適合使用。

[[344441]]

所謂延時(shí)隊(duì)列就是延時(shí)的消息隊(duì)列,下面說一下一些業(yè)務(wù)場景

實(shí)踐場景

訂單支付失敗,每隔一段時(shí)間提醒用戶

用戶并發(fā)量的情況,可以延時(shí)2分鐘給用戶發(fā)短信

先來看看Redis實(shí)現(xiàn)普通的消息隊(duì)列

我們知道,對于專業(yè)的消息隊(duì)列中間件,如Kafka和RabbitMQ,消費(fèi)者在消費(fèi)消息之前要進(jìn)行一系列的繁瑣過程。

如RabbitMQ發(fā)消息之前要?jiǎng)?chuàng)建 Exchange,再創(chuàng)建 Queue,還要將 Queue 和 Exchange 通過某種規(guī)則綁定起來,發(fā)消息的時(shí)候要指定 routingkey,還要控制頭部信息

但是絕大 多數(shù)情況下,雖然我們的消息隊(duì)列只有一組消費(fèi)者,但還是需要經(jīng)歷上面一些過程。

有了 Redis,對于那些只有一組消費(fèi)者的消息隊(duì)列,使用 Redis 就可以非常輕松的搞定。Redis 的消息隊(duì)列不是專業(yè)的消息隊(duì)列,它沒有非常多的高級特性, 沒有 ack 保證,如果對消息的可靠性有著極致的追求,那么它就不適合使用

異步消息隊(duì)列基本實(shí)現(xiàn)

Redis 的 list(列表) 數(shù)據(jù)結(jié)構(gòu)常用來作為異步消息隊(duì)列使用,使用 rpush/lpush 操作入隊(duì)列, 使用 lpop 和 rpop 來出隊(duì)列

  1. > rpush queue 月伴飛魚1 月伴飛魚2 月伴飛魚3 
  2. (integer) 3 
  3. > lpop queue 
  4. "月伴飛魚1" 
  5. > llen queue 
  6. (integer) 2 

問題1:如果隊(duì)列空了

客戶端是通過隊(duì)列的 pop 操作來獲取消息,然后進(jìn)行處理。處理完了再接著獲取消息, 再進(jìn)行處理。如此循環(huán)往復(fù),這便是作為隊(duì)列消費(fèi)者的客戶端的生命周期。

可是如果隊(duì)列空了,客戶端就會(huì)陷入 pop 的死循環(huán),不停地 pop,沒有數(shù)據(jù),接著再 pop, 又沒有數(shù)據(jù)。這就是浪費(fèi)生命的空輪詢。空輪詢不但拉高了客戶端的 CPU,redis 的 QPS 也 會(huì)被拉高,如果這樣空輪詢的客戶端有幾十來個(gè),Redis 的慢查詢可能會(huì)顯著增多。

通常我們使用 sleep 來解決這個(gè)問題,讓線程睡一會(huì),睡個(gè) 1s 鐘就可以了。不但客戶端 的 CPU 能降下來,Redis 的 QPS 也降下來了

問題2:隊(duì)列延遲

用上面睡眠的辦法可以解決問題。同時(shí)如果只有 1 個(gè)消費(fèi)者,那么這個(gè)延遲就是 1s。如果有多個(gè)消費(fèi)者,這個(gè)延遲會(huì)有所下降,因 為每個(gè)消費(fèi)者的睡覺時(shí)間是岔開來的。

有沒有什么辦法能顯著降低延遲呢?

那就是 blpop/brpop。

這兩個(gè)指令的前綴字符 b 代表的是 blocking,也就是阻塞讀。

阻塞讀在隊(duì)列沒有數(shù)據(jù)的時(shí)候,會(huì)立即進(jìn)入休眠狀態(tài),一旦數(shù)據(jù)到來,則立刻醒過來。消 息的延遲幾乎為零。用 blpop/brpop 替代前面的 lpop/rpop,就完美解決了上面的問題。

問題3:空閑連接自動(dòng)斷開

其實(shí)他還有個(gè)問題需要解決—— 空閑連接的問題。

如果線程一直阻塞在哪里,Redis 的客戶端連接就成了閑置連接,閑置過久,服務(wù)器一般 會(huì)主動(dòng)斷開連接,減少閑置資源占用。這個(gè)時(shí)候 blpop/brpop 會(huì)拋出異常來。

所以編寫客戶端消費(fèi)者的時(shí)候要小心,注意捕獲異常,還要重試。

分布式鎖沖突處理

假如客戶端在處理請求時(shí)加分布式鎖沒加成功怎么辦。

一般有 3 種策略來處理加鎖失?。?/strong>

1、直接拋出異常,通知用戶稍后重試;

2、sleep 一會(huì)再重試;

3、將請求轉(zhuǎn)移至延時(shí)隊(duì)列,過一會(huì)再試;

直接拋出特定類型的異常

這種方式比較適合由用戶直接發(fā)起的請求,用戶看到錯(cuò)誤對話框后,會(huì)先閱讀對話框的內(nèi) 容,再點(diǎn)擊重試,這樣就可以起到人工延時(shí)的效果。如果考慮到用戶體驗(yàn),可以由前端的代碼 替代用戶自己來進(jìn)行延時(shí)重試控制。它本質(zhì)上是對當(dāng)前請求的放棄,由用戶決定是否重新發(fā)起 新的請求。

sleep

sleep 會(huì)阻塞當(dāng)前的消息處理線程,會(huì)導(dǎo)致隊(duì)列的后續(xù)消息處理出現(xiàn)延遲。如果碰撞的比 較頻繁或者隊(duì)列里消息比較多,sleep 可能并不合適。如果因?yàn)閭€(gè)別死鎖的 key 導(dǎo)致加鎖不成 功,線程會(huì)徹底堵死,導(dǎo)致后續(xù)消息永遠(yuǎn)得不到及時(shí)處理。

延時(shí)隊(duì)列

這種方式比較適合異步消息處理,將當(dāng)前沖突的請求扔到另一個(gè)隊(duì)列延后處理以避開沖突。

延時(shí)隊(duì)列的實(shí)現(xiàn)

我們可以使用 zset這個(gè)命令,用設(shè)置好的時(shí)間戳作為score進(jìn)行排序,使用 zadd score1 value1 ....命令就可以一直往內(nèi)存中生產(chǎn)消息。再利用 zrangebysocre 查詢符合條件的所有待處理的任務(wù),通過循環(huán)執(zhí)行隊(duì)列任務(wù)即可。也可以通過 zrangebyscore key min max withscores limit 0 1 查詢最早的一條任務(wù),來進(jìn)行消費(fèi)

  1. private Jedis jedis; 
  2.  
  3. public void redisDelayQueueTest() { 
  4.     String key = "delay_queue"
  5.  
  6.     // 實(shí)際開發(fā)建議使用業(yè)務(wù) ID 和隨機(jī)生成的唯一 ID 作為 value, 隨機(jī)生成的唯一 ID 可以保證消息的唯一性, 業(yè)務(wù) ID 可以避免 value 攜帶的信息過多 
  7.     String orderId1 = UUID.randomUUID().toString(); 
  8.     jedis.zadd(queueKey, System.currentTimeMillis() + 5000, orderId1); 
  9.  
  10.     String orderId12 = UUID.randomUUID().toString(); 
  11.     jedis.zadd(queueKey, System.currentTimeMillis() + 5000, orderId2); 
  12.  
  13.     new Thread() { 
  14.         @Override 
  15.         public void run() { 
  16.             while (true) { 
  17.                 Set<String> resultList; 
  18.                 // 只獲取第一條數(shù)據(jù), 只獲取不會(huì)移除數(shù)據(jù) 
  19.                 resultList = jedis.zrangebyscore(key, System.currentTimeMillis(), 0, 1); 
  20.                 if (resultList.size() == 0) { 
  21.                     try { 
  22.                         Thread.sleep(1000); 
  23.                     } catch (InterruptedException e) { 
  24.                         e.printStackTrace(); 
  25.                         break; 
  26.                     } 
  27.                 } else { 
  28.                     // 移除數(shù)據(jù)獲取到的數(shù)據(jù) 
  29.                     if (jedis.zrem(key, resultList.get(0)) > 0) { 
  30.                         String orderId = resultList.get(0); 
  31.                         log.info("orderId = {}", resultList.get(0)); 
  32.                         this.handleMsg(orderId); 
  33.                     } 
  34.                 } 
  35.             } 
  36.         } 
  37.     }.start(); 
  38.  
  39. public void handleMsg(T msg) { 
  40.     System.out.println(msg); 

上面的實(shí)現(xiàn), 在多線程邏輯上也是沒有問題的, 假設(shè)有兩個(gè)線程 T1, T2和其他更多線程, 處理邏輯如下, 保證了多線程情況下只有一個(gè)線程處理了對應(yīng)的消息:

1.T1, T2 和其他更多線程調(diào)用 zrangebyscore 獲取到了一條消息 A

2.T1 準(zhǔn)備開始刪除消息 A, 由于是原子操作, T2 和其他更多線程等待 T1 執(zhí)行 zrem 刪除消息 A 后再執(zhí)行 zrem 刪除消息 A

3.T1 刪除了消息 A, 返回刪除成功標(biāo)記 1, 并對消息 A 進(jìn)行處理

4.T2 其他更多線程開始 zrem 刪除消息 A, 由于消息 A 已經(jīng)被刪除, 所以所有的刪除均失敗, 放棄了對消息 A 的處理

同時(shí),我們要注意一定要對 handle_msg 進(jìn)行異常捕獲,避免因?yàn)閭€(gè)別任務(wù)處理問題導(dǎo)致循環(huán)異常退 出

進(jìn)一步優(yōu)化

上面的算法中同一個(gè)任務(wù)可能會(huì)被多個(gè)進(jìn)程取到之后再使用 zrem 進(jìn)行爭搶,那些沒搶到 的進(jìn)程都是白取了一次任務(wù),這是浪費(fèi)??梢钥紤]使用 lua scripting 來優(yōu)化一下這個(gè)邏輯,將 zrangebyscore 和 zrem 一同挪到服務(wù)器端進(jìn)行原子化操作,這樣多個(gè)進(jìn)程之間爭搶任務(wù)時(shí)就不 會(huì)出現(xiàn)這種浪費(fèi)了

使用調(diào)用Lua腳本進(jìn)一步優(yōu)化

Lua 腳本, 如果有超時(shí)的消息, 就刪除, 并返回這條消息, 否則返回空字符串:

  1. String luaScript = "local resultArray = redis.call('zrangebyscore', KEYS[1], 0, ARGV[1], 'limit' , 0, 1)\n" + 
  2.         "if #resultArray > 0 then\n" + 
  3.         "    if redis.call('zrem', KEYS[1], resultArray[1]) > 0 then\n" + 
  4.         "        return resultArray[1]\n" + 
  5.         "    else\n" + 
  6.         "        return ''\n" + 
  7.         "    end\n" + 
  8.         "else\n" + 
  9.         "    return ''\n" + 
  10.         "end"
  11.  
  12. jedis.eval(luaScript, ScriptOutputType.VALUE, new String[]{key}, String.valueOf(System.currentTimeMillis())); 

Redis延時(shí)隊(duì)列優(yōu)勢

Redis用來進(jìn)行實(shí)現(xiàn)延時(shí)隊(duì)列是具有這些優(yōu)勢的:

1.Redis zset支持高性能的 score 排序。

2.Redis是在內(nèi)存上進(jìn)行操作的,速度非???。

3.Redis可以搭建集群,當(dāng)消息很多時(shí)候,我們可以用集群來提高消息處理的速度,提高可用性。

4.Redis具有持久化機(jī)制,當(dāng)出現(xiàn)故障的時(shí)候,可以通過AOF和RDB方式來對數(shù)據(jù)進(jìn)行恢復(fù),保證了數(shù)據(jù)的可靠性

Redis延時(shí)隊(duì)列劣勢

使用 Redis 實(shí)現(xiàn)的延時(shí)消息隊(duì)列也存在數(shù)據(jù)持久化, 消息可靠性的問題

沒有重試機(jī)制 - 處理消息出現(xiàn)異常沒有重試機(jī)制, 這些需要自己去實(shí)現(xiàn), 包括重試次數(shù)的實(shí)現(xiàn)等

沒有 ACK 機(jī)制 - 例如在獲取消息并已經(jīng)刪除了消息情況下, 正在處理消息的時(shí)候客戶端崩潰了, 這條正在處理的這些消息就會(huì)丟失, MQ 是需要明確的返回一個(gè)值給 MQ 才會(huì)認(rèn)為這個(gè)消息是被正確的消費(fèi)了

如果對消息可靠性要求較高, 推薦使用 MQ 來實(shí)現(xiàn)

Redission實(shí)現(xiàn)延時(shí)隊(duì)列

基于Redis的Redisson分布式延遲隊(duì)列結(jié)構(gòu)的RDelayedQueue Java對象在實(shí)現(xiàn)了RQueue接口的基礎(chǔ)上提供了向隊(duì)列按要求延遲添加項(xiàng)目的功能。該功能可以用來實(shí)現(xiàn)消息傳送延遲按幾何增長或幾何衰減的發(fā)送策略

  1. RQueue<String> distinationQueue = ... 
  2. RDelayedQueue<String> delayedQueue = getDelayedQueue(distinationQueue); 
  3. // 10秒鐘以后將消息發(fā)送到指定隊(duì)列 
  4. delayedQueue.offer("msg1", 10, TimeUnit.SECONDS); 
  5. // 一分鐘以后將消息發(fā)送到指定隊(duì)列 
  6. delayedQueue.offer("msg2", 1, TimeUnit.MINUTES); 

在該對象不再需要的情況下,應(yīng)該主動(dòng)銷毀。僅在相關(guān)的Redisson對象也需要關(guān)閉的時(shí)候可以不用主動(dòng)銷毀。

  1. RDelayedQueue<String> delayedQueue = ... 
  2. delayedQueue.destroy(); 

 

是不是很方便...............

本文轉(zhuǎn)載自微信公眾號「月伴飛魚」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系月伴飛魚公眾號。

 

責(zé)任編輯:武曉燕 來源: 月伴飛魚
相關(guān)推薦

2020-10-26 07:02:11

ConcurrentH存儲(chǔ)

2023-04-26 01:17:16

惡意注冊Java驗(yàn)證

2022-03-04 14:57:50

緩存數(shù)據(jù)庫代碼

2023-11-29 08:01:38

websocket協(xié)議

2024-11-15 09:29:12

2025-05-29 01:00:00

數(shù)據(jù)架構(gòu)大數(shù)據(jù)數(shù)據(jù)湖

2020-02-06 14:57:11

明白SpringMvc異步處理

2023-02-27 08:10:16

2024-05-10 11:35:22

Redis延時(shí)隊(duì)列數(shù)據(jù)庫

2024-02-26 00:00:00

Redis持久化AOF

2023-04-03 07:23:06

Java線程通信

2020-06-08 11:10:53

Java回調(diào)機(jī)制代碼

2022-04-25 09:03:16

JavaScript代碼

2025-03-17 00:21:00

2020-07-08 08:07:23

高并發(fā)系統(tǒng)消息隊(duì)列

2021-05-08 07:14:38

MySQL數(shù)據(jù)庫安全性

2024-05-16 12:24:53

2020-03-09 09:13:40

HTTPSTCP網(wǎng)絡(luò)協(xié)議

2019-06-26 09:41:44

分布式事務(wù)微服務(wù)

2019-06-24 05:05:40

緩沖池查詢數(shù)據(jù)InnoDB
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

精品视频—区二区三区免费| 亚洲片国产一区一级在线观看| 亚洲国产日韩综合久久精品| 成人9ⅰ免费影视网站| 亚洲国产视频二区| 欧美成人精品高清在线播放| 色资源在线观看| 亚洲三级在线观看| av动漫免费看| 成人午夜精品在线| 婷婷综合在线观看| av天天av| 91超碰成人| 国产精品网站在线播放| 亚洲欧美一二三| 日韩图片一区| 国产乱人伦精品一区二区| 午夜av区久久| 欧美成人dvd在线视频| 欧美18 19xxx| 国产日韩精品视频一区| 日本五级黄色片| 国产成人一区在线| 成年人三级视频| 国产毛片精品视频| 国产激情片在线观看| 国产精品一色哟哟哟| 国产精品久久久久9999爆乳| 日韩毛片视频在线看| 国产一区二区三区日韩欧美| 9999精品成人免费毛片在线看| 91精品国产高清一区二区三区蜜臀| 羞羞视频在线观看| 91国内精品野花午夜精品| 国产网站在线播放| 日韩午夜精品电影| 中文在线最新版地址| 色爱精品视频一区| 国产精品乱战久久久| 国产91色在线播放| 中国成人一区| 天堂资源在线亚洲视频| 成人性生交大片免费看视频在线 | 久青草国产在线| 欧美午夜精品久久久久久孕妇 | 国产精品视频免费一区二区三区| 亚洲成色精品| 一区二区视频在线观看| 久久影院午夜论| 男女激情片在线观看| 69久久99精品久久久久婷婷| 国产在线精彩视频| 久久久久久一区二区三区 | 91精品国产91久久久久福利| 欧美电影免费播放| 日韩经典在线视频| 99视频一区二区| 国产精品免费视频一区二区| 视频在线观看成人| 精品一区二区免费在线观看| 国产天堂视频在线观看| 2019国产精品| 欧美13~18sex性hd| 9191成人精品久久| 免费观看亚洲| 国产精品黄色影片导航在线观看| 99这里有精品| 老子影院午夜伦不卡大全| 亚洲男人的天堂av| a毛片在线播放| 欧美成人在线网站| 午夜电影亚洲| 黄色动漫网站入口| 在线日韩国产精品| 日韩深夜福利网站| 亚洲影院色在线观看免费| 国产一区二区精品久久| 欧美xx网站| 日韩电影网在线| 精品在线99| 亚洲资源视频| 亚洲欧美日韩电影| 国产福利电影在线播放| 国产v综合ⅴ日韩v欧美大片| 日本午夜一区二区| 黄色福利视频网站| 日韩精品一二三四区| 成人亚洲一区| 国产欧美精品aaaaaa片| 在线亚洲欧美专区二区| 欧美另类中文字幕| 久久久一本精品99久久精品| 国产精品久线观看视频| 青青草原av在线| 国产成+人+综合+亚洲欧洲| 国内精品伊人久久久久av一坑| 男女无套免费网站| 亚洲精品小视频| 激情综合视频| www.成人69.com| 亚洲欧美在线看| 亚洲欧美伊人| 婷婷丁香六月天| 超薄丝袜一区二区| 精品一区在线看| 日本在线人成| 成人免费视频网| 国产欧美日韩在线看| 最新欧美电影| 亚洲亚洲精品三区日韩精品在线视频| 欧美日韩国产丝袜美女| 精品精品国产三级a∨在线| 欧美交换配乱吟粗大25p| 91精品国产综合久久香蕉麻豆| 国产毛片一区二区三区| 女人扒开屁股爽桶30分钟| 亚洲国产又黄又爽女人高潮的| 中文乱码免费一区二区三区下载| 成人3d漫画免费无遮挡软件| 久久精品青青大伊人av| 国产精品自在在线| av电影在线地址| 欧美久久在线| 91福利视频在线| 自拍偷拍欧美| 免费在线高清av| 91亚洲午夜在线| 欧美视频在线看| 久久久久亚洲| 四虎成人免费在线| 成人性生交大片免费观看嘿嘿视频 | 性欧美大战久久久久久久久| 日本免费精品| 欧美黄色一级片视频| www.午夜精品| 99久久精品国产观看| 日本成人片在线| www.射射射| 色偷偷噜噜噜亚洲男人| 成人av网站免费观看| 久久不卡日韩美女| 成 年 人 黄 色 大 片大 全| 色偷偷偷亚洲综合网另类| 久久精品亚洲乱码伦伦中文| 精品福利一区| 免费特级黄毛片| 国产日韩在线视频| 欧洲一区二区三区在线| 另类国产ts人妖高潮视频| 大黄网站在线观看| 一卡二卡三卡视频| 高清欧美性猛交| 欧美日韩一区二区免费在线观看| 黄色日韩在线| 色戒汤唯在线| 久久久久国产精品熟女影院| 欧洲美女7788成人免费视频| 亚洲五码中文字幕| 亚洲一区欧美二区| 91精品美女| 久久综合色播| 久久综合入口| 中文字幕av一区中文字幕天堂 | 无遮挡在线观看| 水蜜桃色314在线观看| 性欧美xxxx视频在线观看| 亚洲18女电影在线观看| 亚洲欧美高清| 亚洲伦理一区二区| 毛片在线网址播放| 奇米888一区二区三区| www.久久色.com| 亚洲观看高清完整版在线观看| 欧美日本一区二区高清播放视频| 中文在线免费| 国产情侣av自拍| 3d动漫精品啪啪一区二区三区免费 | 成人精品高清在线视频| 成人免费观看在线网址| 国产精品视频福利| 亚洲日本中文字幕免费在线不卡| 国产精品久久久久久久裸模| 亚洲视频狠狠| 国产 日韩 欧美| 国产69久久| 国产麻花豆剧传媒精品mv在线| 成人黄色在线观看| 尤物九九久久国产精品的特点| 亚洲人成网站精品片在线观看| 午夜在线观看免费一区| 亚洲精品aⅴ| 亚洲成人三级| 蜜臀视频一区二区三区| 国产福利久久精品| 欧美成人免费小视频| 91精品国产综合久久精品性色| 久久久高清一区二区三区| 亚洲久久一区二区| 老司机凹凸av亚洲导航| 国产高清中文字幕在线|