1. 程式人生 > >Asp.net core中RedisMQ的簡單應用

Asp.net core中RedisMQ的簡單應用

最近一個外部的專案,使用到了訊息佇列,本來是用rabbitmq實現的,但是由於是部署到別人家的伺服器上,想盡量簡化一些,專案中本來也要接入了redis快取,就嘗試使用redis來實現簡單的訊息佇列。 使用redis做訊息佇列有兩種方法,一種是使用pub/sub,另一種是使用list結構,配合brpop來消費。這兩種方式各有特點,這裡簡述一下: - pub/sub模式,支援多客戶端消費,但是不支援持久化,這就意味著客戶端斷開的時間內釋出的訊息將會全部捨棄掉。 - list配合brpop,預設不支援多客戶端消費,支援持久化。這種模式的多客戶端消費可以變相實現,比如下面的虛擬碼: ``` #第一步push訊息到佇列 lpush listA msg #第二步,一個專門的分發客戶端取出訊息,push到各個子佇列 var msg=brpop listA lpush listA1 msg lpush listA2 msg ...... #第三步,多個客戶端從對應的佇列消費訊息 var client1_msg= brpop listA1 var client2_msg= brpop listA2 ...... ``` 訊息丟失不太可取,所以我選擇了list ,下一步需要選擇一個合適的客戶端。 Stackexchange.redis 算是一個老牌的客戶端了,但是由於其採用多路複用的模式,沒法支援Redis的blocking pops特性。所以我採用了國人寫的CSRedisCore。 首先需要在appsettings.json中新增redis的連線字串: ```json { "ConnectionStrings": { "redis": "{ip}:{port},password=123456,prefix=my_" } } ``` 具體配置請參考github上的文件:[https://github.com/2881099/csredis](https://github.com/2881099/csredis) 然後在startup.cs的ConfigureServices中配置redis: ``` public void ConfigureServices(IServiceCollection services) { //redis配置 RedisHelper.Initialization(new CSRedis.CSRedisClient(Configuration.GetConnectionString("redis"))); } ``` 當然也可以採用依賴注入的方式新增CSRedisClient例項,這個不糾結。 在專案中有好幾處使用到了佇列,所以先封裝一個消費服務: ``` public abstract class RedisMQConsumer : BackgroundService { protected abstract string CacheKey { get; } protected ILogger logger; public RedisMQConsumer(ILogger logger) { this.logger = logger; } protected override Task ExecuteAsync(CancellationToken stoppingToken) { return Task.Run( async() => { while (!stoppingToken.IsCancellationRequested) { try { var msg = RedisHelper.BRPop(5, CacheKey); try { if (string.IsNullOrEmpty(msg)) continue; if (!Process(msg)) { //加入錯誤處理佇列,可以在後臺寫功能手動處理 RedisHelper.LPush(CacheKey + "_err", msg); } } catch (Exception exp) { //加入錯誤處理佇列,可以在後臺寫功能手動處理 RedisHelper.LPush(CacheKey + "_err", msg); logger.LogError(exp, "RedisMQConsumer Execute error"); } } catch { //網路可能中斷 await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); } } }, stoppingToken); } protected abstract bool Process(string message); } ``` 然後就可以繼承RedisMQConsumer,編寫實際邏輯: ``` public class AddOrderMQConsumer : RedisMQConsumer { public AddOrderMQConsumer(ILogger logger) : base(logger) { } protected override string CacheKey => "addOrder"; protected override bool Process(string message) { var order = JsonSerializer.Deserialize(message); //處理邏輯 return true; } } ``` 釋出訊息只是往佇列中新增項: ``` RedisHelper.LPush("addOrder", order); ``` 最後把消費服務新增到startup.cs中: ``` public void ConfigureServices(IServiceCollection services) { //redis配置 RedisHelper.Initialization(new CSRedis.CSRedisClient(Configuration.GetConnectionString("redis"))); //redis訊息佇列消費服務,放在redis配置下方 services.AddHostedService(); } ``` 經測試,還算穩定,小併發專案可以