.Net Core3.0 WebApi 項目框架搭建:目錄
介紹
- NewLife.Redis主要作者及經驗介紹來源:大石頭
- 源碼: https://github.com/NewLifeX/NewLife.Redis
- Nuget:NewLife.Redis
- NewLife.Redis是一個Redis客戶端組件,以高性能處理大數據實時計算為目標。
- Redis協議基礎實現Redis/RedisClient位於X組件,包含基礎字符串操作。完整實現由獨立開源項目NewLife.Redis提供。
NewLife.Redis
為擴展實現,主要增加列表結構、哈希結構、隊列等高級功能。 - 采取連接池加同步阻塞架構,具有超低延遲(200~600us)以及超高吞吐量的特點。在物流行業大數據實時計算中廣泛應有,經過日均100億次調用量驗證。
特性
-
在ZTO大數據實時計算廣泛應用,200多個Redis實例穩定工作一年多,每天處理近1億包裹數據,日均調用量80億次
-
低延遲,Get/Set操作平均耗時200~600us(含往返網絡通信)
-
大吞吐,自帶連接池,最大支持1000並發
更新Redis接口

public interface IRedisCacheManager { #region #endregion #region 普通 /// <summary> /// 獲取值,並序列化 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="key"></param> /// <returns></returns> TEntity Get<TEntity>(string key); /// <summary> /// 插入數據到redis /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="cacheTime"></param> void Set(string key, object value, TimeSpan cacheTime); /// <summary> /// 插入數據到redis /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="cacheTime"></param> void Set<TEntity>(string key, TEntity value, TimeSpan cacheTime); /// <summary> /// 判斷是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> bool ContainsKey(string key); /// <summary> /// 移除某一個key /// </summary> /// <param name="key"></param> void Remove(string key); /// <summary> /// 全部清除 /// </summary> void Clear(); /// <summary> /// 設置超時 /// </summary> /// <param name="key"></param> /// <param name="timeSpan"></param> void SetExpire(string key, TimeSpan timeSpan); /// <summary> /// 根據關鍵字移除 /// </summary> /// <param name="key"></param> /// <returns></returns> Task RemoveByKey(string key, int count); /// <summary> /// 根據關鍵字移除所有 /// </summary> /// <param name="key"></param> /// <param name="count"></param> /// <returns></returns> Task RemoveAllByKey(string key, int count = 999); #endregion #region HashMap /// <summary> /// 插入hashmap /// </summary> /// <param name="name"></param> /// <param name="key"></param> /// <param name="value"></param> /// <param name="expire"></param> /// <returns></returns> bool HashSet<T>(string key, Dictionary<string, T> dic, int expire = -1); /// <summary> /// /插入hashmap帶返回結果 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="dic"></param> /// <param name="expire"></param> /// <returns></returns> bool HashSetWithResult<T>(string key, Dictionary<string, T> dic, int expire = -1); /// <summary> /// 獲取hashmap /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="fields"></param> /// <returns></returns> List<T> HashGet<T>(string key, params string[] fields); /// <summary> /// 獲取hashmap /// </summary> /// <param name="name"></param> /// <param name="key"></param> /// <param name="value"></param> /// <param name="expire"></param> /// <returns></returns> string[] HashGet(string key, params string[] fields); #endregion #region 隊列 /// <summary> /// 添加到隊列 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> int AddQueue<T>(string key, T[] value); /// <summary> /// 獲取一批隊列消息 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> List<T> GetQueue<T>(string key, int Count); /// <summary> /// 獲取一個隊列消息 /// </summary> /// <param name="key"></param> /// <returns></returns> Task<T> GetQueueOneAsync<T>(string key); #endregion #region 可靠隊列 /// <summary> /// 獲取可靠隊列實例 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> RedisReliableQueue<T> GetReliableQueue<T>(string key); /* /// <summary> /// 批量獲取可靠隊列消息 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="queue"></param> /// <param name="count"></param> /// <returns></returns> Task<List<T>> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue, int count); /// <summary> /// 獲取一條可靠隊列消息 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="queue"></param> /// <returns></returns> Task<T> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue); /// <summary> /// 回滾所有未確認消息 /// </summary> /// <param name="key"></param> /// <param name="retryInterval">重新處理確認隊列中死信的間隔。默認60s</param> /// <returns></returns> Task<int> RollbackAllAck(string key, int retryInterval = 60); /// <summary> /// 確認消息 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> Task<int> Acknowledge<T>(RedisReliableQueue<T> queue, T value); */ /// <summary> /// 批量添加消息到可靠隊列 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> int AddReliableQueueList<T>(string key, List<T> value); /// <summary> /// 添加消息到可靠隊列 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> int AddReliableQueue<T>(string key, T value); /// <summary> /// 回滾所有未確認消息 /// </summary> /// <param name="key"></param> /// <param name="retryInterval">重新處理確認隊列中死信的間隔。默認60s</param> /// <returns></returns> int RollbackAllAck(string key, int retryInterval = 60); #endregion #region 列表 /// <summary> /// 插入列表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="values"></param> /// <param name="timeSpan"></param> /// <returns></returns> int AddList(string key, IEnumerable<string> values, TimeSpan timeSpan); /// <summary> /// 列表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="values"></param> /// <returns></returns> int AddList(string key, IEnumerable<string> values); #endregion #region SortSet /// <summary> /// 獲取SortSet實例 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> RedisSortedSet<T> GetRedisSortedSet<T>(string key); /// <summary> /// 批量添加Sorted /// 將所有指定成員添加到鍵為key有序集合(sorted set)里面。 添加時可以指定多個分數/成員(score/member)對。 /// 如果指定添加的成員已經是有序集合里面的成員,則會更新改成員的分數(scrore)並更新到正確的排序位置。 /// ZADD 命令在key后面分數/成員(score/member)對前面支持一些參數,他們是: /// XX: 僅僅更新存在的成員,不添加新成員。 /// NX: 不更新存在的成員。只添加新成員。 /// CH: 修改返回值為發生變化的成員總數,原始是返回新添加成員的總數(CH 是 changed 的意思)。 /// 更改的元素是新添加的成員,已經存在的成員更新分數。 所以在命令中指定的成員有相同的分數將不被計算在內。 /// 注:在通常情況下,ZADD返回值只計算新添加成員的數量。 /// INCR: 當ZADD指定這個選項時,成員的操作就等同ZINCRBY命令,對成員的分數進行遞增操作。 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="options"></param> /// <returns></returns> int SortedSetAdd(string key, Dictionary<String, Double> value, string options = null); /// <summary>為有序集key的成員member的score值加上增量increment</summary> /// <param name="member"></param> /// <param name="score"></param> /// <returns></returns> double SortedSetIncrement<T>(string key, T member, double score); /// <summary>刪除並返回有序集合key中的最多count個具有最高得分的成員</summary> /// <param name="count"></param> /// <returns></returns> IDictionary<T, double> SortedSetPopMax<T>(string key, int count = 1); /// <summary>刪除並返回有序集合key中的最多count個具有最低得分的成員</summary> /// <param name="count"></param> /// <returns></returns> IDictionary<T, double> SortedSetPopMin<T>(string key, int count = 1); /// <summary> /// 返回有序集key中,score值在min和max之間(默認包括score值等於min或max)的成員個數 /// </summary> /// <param name="min"></param> /// <param name="max"></param> /// <returns></returns> int SortedSetFindCount<T>(string key, double min, double max); /// <summary>返回指定范圍的列表</summary> /// <param name="start"></param> /// <param name="stop"></param> /// <returns></returns> T[] SortedSetRange<T>(string key, int start, int stop); /// <summary>返回指定范圍的成員分數對</summary> /// <param name="start"></param> /// <param name="stop"></param> /// <returns></returns> IDictionary<T, double> SortedSetRangeWithScores<T>(string key, int start, int stop); /// <summary>返回指定分數區間的成員列表,低分到高分排序</summary> /// <param name="min">低分,包含</param> /// <param name="max">高分,包含</param> /// <param name="offset">偏移</param> /// <param name="count">個數</param> /// <returns></returns> T[] SortedSetRangeByScore<T>(string key, double min, double max, int offset, int count); /// <summary>返回指定分數區間的成員列表,低分到高分排序</summary> /// <param name="min">低分,包含</param> /// <param name="max">高分,包含</param> /// <param name="offset">偏移</param> /// <param name="count">個數</param> /// <returns></returns> Task<T[]> SortedSetRangeByScoreAsync<T>(string key, double min, double max, int offset, int count); /// <summary>返回指定分數區間的成員分數對,低分到高分排序</summary> /// <param name="min">低分,包含</param> /// <param name="max">高分,包含</param> /// <param name="offset">偏移</param> /// <param name="count">個數</param> /// <returns></returns> IDictionary<T, double> SortedSetRangeByScoreWithScores<T>(string key, double min, double max, int offset, int count); /// <summary>返回有序集key中成員member的排名。其中有序集成員按score值遞增(從小到大)順序排列</summary> /// <param name="member"></param> /// <returns></returns> int SortedSetRank<T>(string key, T member); /// <summary>模糊搜索,支持?和*</summary> /// <param name="pattern"></param> /// <param name="count"></param> /// <param name="position"></param> /// <returns></returns> IEnumerable<KeyValuePair<T, double>> SortedSetSearch<T>(string key, string pattern, int count, int position = 0); #endregion #region Set /// <summary> /// 添加Set /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> void SetAdd<T>(string key, T value); /// <summary> /// 批量添加添加Set /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> void SetAddList<T>(string key, T[] value); /// <summary> /// 移除Set某個值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> bool SetRemove<T>(string key, T value); /// <summary> /// 判斷值是否存在 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> bool SetContains<T>(string key, T value); /// <summary> /// 清空Set /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> void SetClear<T>(string key); /// <summary> /// 復制Set /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="array"></param> /// <param name="arrayIndex"></param> /// <returns></returns> void SetCopyTo<T>(string key, T[] array, int arrayIndex); #endregion }
添加實現類
Common類庫中,新建Redis文件夾,新建NewLifeRedisCacheManager.cs

public class NewLifeRedisCacheManager : IRedisCacheManager { private readonly string redisConnenctionString; public volatile FullRedis redisConnection; private readonly object redisConnectionLock = new object(); private readonly int db; public NewLifeRedisCacheManager() { string redisConfiguration = Appsettings.App(new string[] { "AppSettings", "RedisCaching", "ConnectionString" });//獲取連接字符串 string Db = Appsettings.App(new string[] { "AppSettings", "RedisCaching", "Db" }); if (string.IsNullOrWhiteSpace(redisConfiguration)) { throw new ArgumentException("redis config is empty", nameof(redisConfiguration)); } FullRedis.Register(); this.redisConnenctionString = redisConfiguration; this.db = Db.ToInt(); this.redisConnection = GetRedisConnection(); } public NewLifeRedisCacheManager(string redisConfiguration, int Db = 0) { if (string.IsNullOrWhiteSpace(redisConfiguration)) { throw new ArgumentException("redis config is empty", nameof(redisConfiguration)); } FullRedis.Register(); this.redisConnenctionString = redisConfiguration; this.db = Db.ToInt(); this.redisConnection = GetRedisConnection(); } /// <summary> /// 核心代碼,獲取連接實例 /// 通過雙if 夾lock的方式,實現單例模式 /// </summary> /// <returns></returns> private FullRedis GetRedisConnection() { //如果已經連接實例,直接返回 if (this.redisConnection != null) { return this.redisConnection; } //加鎖,防止異步編程中,出現單例無效的問題 lock (redisConnectionLock) { if (this.redisConnection != null) { //釋放redis連接 this.redisConnection.Dispose(); } try { //this.redisConnection = FullRedis.Create(redisConnenctionString); this.redisConnection = FullRedis.Create(redisConnenctionString); this.redisConnection.Timeout = 5000; } catch (Exception ex) { throw new Exception("Redis服務未啟用,請開啟該服務"); } } return this.redisConnection; } #region 普通 public TEntity Get<TEntity>(string key) { return redisConnection.Get<TEntity>(key); } public void Set<TEntity>(string key, TEntity value, TimeSpan cacheTime) { if (value != null) { redisConnection.Set(key, value, cacheTime); } } public void Set(string key, object value, TimeSpan cacheTime) { redisConnection.Set(key, value, cacheTime); } public bool ContainsKey(string key) { return redisConnection.ContainsKey(key); } public void Remove(string key) { redisConnection.Remove(key); } public void Clear() { redisConnection.Clear(); } public void SetExpire(string key, TimeSpan timeSpan) { redisConnection.SetExpire(key, timeSpan); } public async Task RemoveByKey(string key, int count) { await Task.Run(() => { var keys = redisConnection.Search(key, count).ToList(); foreach (var k in keys) redisConnection.Remove(k); }); } public async Task RemoveAllByKey(string key, int count = 999) { await Task.Run(() => { while (true) { var keyList = redisConnection.Search(key, count).ToList(); if (keyList.Count > 0) { foreach (var k in keyList) redisConnection.Remove(k); } else { break; } } }); } #endregion #region HashMap public bool HashSetWithResult<T>(string key, Dictionary<string, T> dic, int expire = -1) { var hash = redisConnection.GetDictionary<T>(key) as RedisHash<string, T>; var result = hash.HMSet(dic); return result; } public bool HashSet<T>(string key, Dictionary<string, T> dic, int expire = -1) { var hash = redisConnection.GetDictionary<T>(key) as RedisHash<string, T>; var result = hash.HMSet(dic); return result; } public string[] HashGet(string key, params string[] fields) { var hash = redisConnection.GetDictionary<string>(key) as RedisHash<string, string>; var result = hash.HMGet(fields); return result; } public List<T> HashGet<T>(string key, params string[] fields) { var hash = redisConnection.GetDictionary<T>(key) as RedisHash<string, T>; var result = hash.HMGet(fields); return result.ToList(); } #endregion #region 隊列 public int AddQueue<T>(string key, T[] value) { var queue = redisConnection.GetQueue<T>(key); return queue.Add(value); } public List<T> GetQueue<T>(string key, int Count = 1) { var queue = redisConnection.GetQueue<T>(key); var result = queue.Take(Count).ToList(); return result; } public async Task<T> GetQueueOneAsync<T>(string key) { var queue = redisConnection.GetQueue<T>(key); return await queue.TakeOneAsync(1); } #endregion #region 可靠隊列 public RedisReliableQueue<T> GetReliableQueue<T>(string key) { var queue = redisConnection.GetReliableQueue<T>(key); return queue; } /* public async Task<List<T>> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue, int count) { return await Task.Run(() => { return queue.Take(count).ToList(); }); } public async Task<T> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue) { return await Task.Run(() => { return queue.TakeOne(); }); } public async Task<int> Acknowledge<T>(RedisReliableQueue<T> queue, T value) { return await Task.Run(() => { var data = value.ToJson(); var count = queue.Acknowledge(data); return count; }); } */ public int RollbackAllAck(string key, int retryInterval = 60) { var queue = redisConnection.GetReliableQueue<string>(key); queue.RetryInterval = retryInterval; return queue.RollbackAllAck(); } public int AddReliableQueueList<T>(string key, List<T> value) { var queue = redisConnection.GetReliableQueue<T>(key); return queue.Add(value.ToArray()); } public int AddReliableQueue<T>(string key, T value) { var queue = redisConnection.GetReliableQueue<T>(key); return queue.Add(value); } #endregion #region 列表 public int AddList(string key, IEnumerable<string> values, TimeSpan timeSpan) { var list = redisConnection.GetList<string>(key) as RedisList<string>; redisConnection.SetExpire(key, timeSpan); return list.AddRange(values); } public int AddList(string key, IEnumerable<string> values) { var list = redisConnection.GetList<string>(key) as RedisList<string>; return list.AddRange(values); } public async Task<string> GetListAsync(string key, string value) { return await Task.Run(() => { var list = redisConnection.GetList<string>(key) as RedisList<string>; return list[list.IndexOf(value)]; }); } #endregion #region SortSet public RedisSortedSet<T> GetRedisSortedSet<T>(string key) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset; } public int SortedSetAdd(string key, Dictionary<string, double> value, string options = null) { var zset = new RedisSortedSet<string>(redisConnection, key); return zset.Add(options, value); } public IDictionary<T, double> SortedSetPopMax<T>(string key, int count = 1) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.PopMax(count); } public IDictionary<T, double> SortedSetPopMin<T>(string key, int count = 1) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.PopMin(count); } public int SortedSetFindCount<T>(string key, double min, double max) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.FindCount(min, max); } public T[] SortedSetRange<T>(string key, int start, int stop) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.Range(start, stop); } public IDictionary<T, double> SortedSetRangeWithScores<T>(string key, int start, int stop) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.RangeWithScores(start, stop); } public T[] SortedSetRangeByScore<T>(string key, double min, double max, int offset, int count) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.RangeByScore(min, max, offset, count); } public async Task<T[]> SortedSetRangeByScoreAsync<T>(string key, double min, double max, int offset, int count) { var zset = new RedisSortedSet<T>(redisConnection, key); return await zset.RangeByScoreAsync(min, max, offset, count); } public IDictionary<T, double> SortedSetRangeByScoreWithScores<T>(string key, double min, double max, int offset, int count) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.RangeByScoreWithScores(min, max, offset, count); } public int SortedSetRank<T>(string key, T member) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.Rank(member); } public IEnumerable<KeyValuePair<T, double>> SortedSetSearch<T>(string key, string pattern, int count, int position = 0) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.Search(pattern, count, position); } public double SortedSetIncrement<T>(string key, T member, double score) { var zset = new RedisSortedSet<T>(redisConnection, key); return zset.Increment(member, score); } #endregion #region Set public void SetAdd<T>(string key, T value) { var set = redisConnection.GetSet<T>(key); set.Add(value); } public void SetAddList<T>(string key, T[] value) { var set = redisConnection.GetSet<string>(key); var set2 = set as RedisSet<T>; set2.SAdd(value); } public bool SetRemove<T>(string key, T value) { var set = redisConnection.GetSet<T>(key); return set.Remove(value); } public bool SetContains<T>(string key, T value) { var set = redisConnection.GetSet<T>(key); return set.Contains(value); } public void SetClear<T>(string key) { var set = redisConnection.GetSet<T>(key); set.Clear(); } public void SetCopyTo<T>(string key, T[] array, int arrayIndex) { var set = redisConnection.GetSet<T>(key); set.CopyTo(array, arrayIndex); } #endregion }
啟動文件注入
services.AddSingleton<IRedisCacheManager, NewLifeRedisCacheManager>();