Redis入門到進階之消息隊列

一、消息隊列

1.1消息隊列概述

消息隊列(Message Queue),是分佈式系統中重要的組件

1.2消息隊列使用場景

分佈式場景

  • 異步處理
  • 應用解耦
  • 流量削峯

日誌場景

  • 優化日誌傳輸,提升系統性能 

及時通信

  • 聊天室 

解決應用解耦,異步消息,流量削鋒等問題,實現高性能,高可用,可伸縮

 

1.3消息隊列相關概念 

  1. 消息隊列:即存儲消息的容器,圖中的兩條直線描繪的管道即消息隊列
  2. 消息:消息即需要寫入的隊列的數據,圖中用A1、A2、A3、An表示
  3. 入隊出隊:消息隊列是先進先出的
  4. 生產者:數據的來源
  5. 消費者:數據的去向

 我們常用RabbitMQ和kafka等專業的消息隊列中間件完成異步消息隊列功能,這些專業的消息隊列功能強大特性豐富,但是使用也相對繁瑣。對於一些簡單的消息隊列場景和對消息的可靠性沒有極致的追求,可以使用Redis完成消息隊列的需求。我們這裏講的是Redis 的消息隊列,相瞭解RabbitMQ的相關知識可以關注我的另一個系列《RabbitMQ入門到進階系列》

二、Redis消息隊列

我們在上一講中已經瞭解了redis有5中數據結構,其中list 數據常被用來作爲消息隊列使用。操作redis消息隊列時,使用lpush/rpush操作入隊列,使用lpop/rpop操作出隊列。lpush/rpop是一組操作,rpush/lpop是一組操作,也就是說左邊進隊,右邊出隊,右邊進隊,左邊出隊,二者使用上沒有區別。這個很容易理解,消息隊列就像一個密閉的管道左邊進去肯定是右邊出來,右邊進去肯定是左邊出來,中間是沒辦法掉頭的。

 

要在.Net Core 中使用Redis的話最好是使用Service.Stack.Redis進行操作。可以使用Nuget安裝(Service.Stack.Redis是收費的,免費的一小時限制6000次請求,後面會教大家如何破解)

 生產者代碼

            //1、創建RedisClient
            RedisClient redisClient = new RedisClient("localhost:6379");
            //2、創建生產者,並插入消息
            byte[] bytes = Encoding.UTF8.GetBytes("這是一條消息");
            redisClient.LPush("TestMQ", bytes);//參數解析:1、消息隊列名字,消息轉換成的byte數組

第一行代碼:通過RedisClient對象(需要引入ServiceStack.Redis命名空間)創建Redis 的連接實例,參數爲redis服務器和端口

第二行代碼:由於在消息隊列中都是通過byte數組傳輸的,所以得先把要入隊的消息轉換成byte數組

第三行代碼:使用LPush方法向隊列插入信息,第一個參數爲目標隊列名字,如果redis中沒有這個隊列則會創建一個,第二個參數是剛纔轉換好的消息byte數組

代碼執行後在Redis Desktop Manager中看到響應的消息

消費者代碼

 

            //1、創建RedisClient
            RedisClient redisClient = new RedisClient("localhost:6379");
            //2、消費消息
            while(true){
            byte[]reads= redisClient.RPop("TestMQ");
            Console.WriteLine($"獲取到消息爲:{Encoding.UTF8.GetString(reads)}");
            }

因爲我們生產者使用的LPush插入數據,所以消費者端需要使用RPop來獲取數據 。插入數據時需要轉換成byte數組,接受也是通過byte數組接受,後面再轉成正確類型。

BRPop/BLPop

細心的同學可能會發現,上面的代碼使用while循環獲取隊列消息,但是如果隊列已經沒有數據,肯定會陷入死循環。這時我們可以使用BRPop或者BLpop方法替換原先的RPop/LPop。Brpop 命令移出並獲取列表的最後一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。

 如果有多個消費者端,將會通過輪詢的方式分攤給消費者端。下面結合BRPop進行演示

修改生產者代碼變成手動輸入消息,以便更好演示

生產者代碼

 Console.WriteLine("當前爲生產者:請輸入消息,輸入exit退出!");
string input;
            do
            {
                input = Console.ReadLine();
 
                var msg = Encoding.UTF8.GetBytes(input);
                redisClient.LPush("hello", msg);               
            } while (input.Trim().ToLower() != "exit");

 消費者代碼

            while (true) 
            {
                
                RedisClient redisClient = new RedisClient("localhost:6379");
                byte[] reads = redisClient.BRPopValue("hello",60);
                Console.WriteLine($"獲取到消息爲:{Encoding.UTF8.GetString(reads)}");
            }   

 然後通過命令或exe啓動兩個消費者

可以看到消息被兩個消費者端通過輪詢的方式給分攤掉了。

即使使用了BRpop阻塞獲取隊列,如果隊列長時間沒有數據,最終還是會拋異常,我們應該捕獲異常,並第一時間重試

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章