天天看點

Redis緩存NoSQL

下面是一些關于Redis比較好的文章,因為篇幅較大,我就将其折疊起來了。不太喜歡分不同的筆記去記載,除非真的很多很多。是以本文不僅要對Redis做簡單的介紹,還要分别介紹Redis中的五種結構,并會貼上一些示例代碼,因為篇幅比較大,是以示例代碼都是折疊起來的,有需要看代碼的請自行點開,還請諒解。這裡隻附上了不分示例代碼,如需要全部的代碼,可以私聊我的郵箱。

redis.conf配置詳細解析https://www.cnblogs.com/kreo/p/4423362.html
項目首頁,下方是各種語言支援清單:

http://code.google.com/p/redis/

作者在wiki中給出了一個非常好的例子,以使我們可以快速上手,位址:

http://code.google.com/p/redis/wiki/TwitterAlikeExample

同時作者推薦的另一個教程,位址:

http://labs.alcacoop.it/doku.php?id=articles:redis_land

一個redis愛好者建立的相關問題讨論網站:

http://www.rediscookbook.org/

為什麼使用 Redis及其産品定位

http://www.infoq.com/cn/articles/tq-why-choose-redis

Redis記憶體使用優化與存儲

http://www.infoq.com/cn/articles/tq-redis-memory-usage-optimization-storage

https://www.linuxidc.com/Linux/2011-02/32700.htm      

View Code

本地緩存,目前程序的記憶體,把資料存起來,下次直接使用,可以提升效率。

  1、容量有限,window下面,32位一個程序最多2G或者3G,64位最多也就4G

  2、多伺服器直接需要緩存共享,需要分布式緩存,遠端伺服器記憶體管理資料,提供讀寫接口,效率高。

分布式緩存:

  1、Memcached,最早流行的

  2、Redis(NoSQL)現在的主流方案

為什麼現在都更新到Redis(NoSQL)去了?

  NoSQL:

    非關系型資料庫,Not Only SQL

    web1.0時代,服務端提供資料,用戶端看,隻能看新聞

    web2.0時代,用戶端可以向服務端互動了,現在能評論了

    資料的關系負責:

      好友關系(張三有100個好友,映射表,其實這個映射表就榮譽了,關系型資料庫開始累贅了)

      再就是資料庫讀取和寫入壓力,硬碟的速度滿足不了,尤其是一些大資料量,是以産生了NoSQL。

    特點:基于記憶體(MongoDB是基于文檔的),沒有嚴格的資料格式,不是一行資料的列必須一樣。封堵的類型,滿足web2.0的需求。

    Redis和MongoDB都是NoSQL,應該在什麼場景去選擇呢?資料量比較大,用MongoDB,否則其他的一切需求,用Redis就可以解決。

  Redis:REmote DIctionary Server,遠端點點伺服器,基于記憶體管理(資料存在記憶體),實作了五種資料結構(String、HashTable、Set、ZSet、List去分别對應各種具體需求),單線程模型應用程式(單程序單線程),對外提供插入-查詢-固化-叢集功能。

  Redis----SQLServer

  Redis-Cli---SQLClient

  Redis支援N多個指令,相當于SQL語句

  ServerStack(1小時3600次請求)----ADO.NET

  StackExchange,免費的,其實更像是ORM,封裝了連接配接+指令。

Redis緩存NoSQL

https://github.com/dmajkic/redis/downloads 下載下傳位址

管理者模式打開控制台(配置成自己的路徑)

可以打開redis-cli.exe嘗試使用,

輸入:set key value 

結果:OK

輸入:get key 

結果:value

用cli,可以簡單的對Redis資料新增和擷取

Redis緩存NoSQL
Redis緩存NoSQL

   基于記憶體管理,速度快,不能當做資料庫。Redis還有個固化資料的功能,VitualMemory,把一些不經常通路是會存在硬碟。可以哦诶之的,down掉會丢失資料snapshot可以儲存到硬碟。AOF,資料辯護記錄日志,很少用。Redis畢竟不是資料庫,隻能用來提升性能,不能作為資料的最終依據。

多線程模型:

  .NET應用都是多線程模型,尤其是網站,可以更好的發揮硬體的能力,但是也有線沖突的問題和排程成本。

單線程模型:

  Node.js是單線程,整個程序隻有一個線程,線程就是執行流,性能低?實際上并非如此。一次網絡請求操作----正則解析請求----加減乘除+資料庫操作(發指令--等結果),讀檔案(發指令---等結果)+調用接口(發指令----等結果),單線程都是事件驅動,發起指令就做下一件事,這個線程是完全不做等待的,一直在計算。

  多程序,多程序提供叢集;單線程多程序的模式來提供叢集服務。,B 查詢還有沒有--有---1更新

  單線程最大的好處就是原子性操作,就是要麼都成功,要麼都失敗,不會出現中間狀态,Redis中的每個指令都是原子性的(因為單線程),不用考慮并發。

C#程式中,要使用Redis,首先要Nuget包安裝一些程式集。下面是一些初始化的工作,寫法一般都是固定的,我就折疊起來了。

/// <summary>
 /// redis配置檔案資訊
 /// 也可以放到配置檔案去
 /// </summary>
 public sealed class RedisConfigInfo
 {
     /// <summary>
     /// 可寫的Redis連結位址
     /// format:ip1,ip2
     /// 
     /// 預設6379端口
     /// </summary>
     public string WriteServerList = "127.0.0.1:6379";
     /// <summary>
     /// 可讀的Redis連結位址
     /// format:ip1,ip2
     /// </summary>
     public string ReadServerList = "127.0.0.1:6379";
     /// <summary>
     /// 最大寫連結數
     /// </summary>
     public int MaxWritePoolSize = 60;
     /// <summary>
     /// 最大讀連結數
     /// </summary>
     public int MaxReadPoolSize = 60;
     /// <summary>
     /// 本地緩存到期時間,機關:秒
     /// </summary>
     public int LocalCacheTime = 180;
     /// <summary>
     /// 自動重新開機
     /// </summary>
     public bool AutoStart = true;
     /// <summary>
     /// 是否記錄日志,該設定僅用于排查redis運作時出現的問題,
     /// 如redis工作正常,請關閉該項
     /// </summary>
     public bool RecordeLog = false;
 }


 /// <summary>
 /// Redis管理中心
 /// </summary>
 public class RedisManager
 {
     /// <summary>
     /// redis配置檔案資訊
     /// </summary>
     private static RedisConfigInfo RedisConfigInfo = new RedisConfigInfo();

     /// <summary>
     /// Redis用戶端池化管理
     /// </summary>
     private static PooledRedisClientManager prcManager;

     /// <summary>
     /// 靜态構造方法,初始化連結池管理對象
     /// </summary>
     static RedisManager()
     {
         CreateManager();
     }

     /// <summary>
     /// 建立連結池管理對象
     /// </summary>
     private static void CreateManager()
     {
         string[] WriteServerConStr = RedisConfigInfo.WriteServerList.Split(',');
         string[] ReadServerConStr = RedisConfigInfo.ReadServerList.Split(',');
         prcManager = new PooledRedisClientManager(ReadServerConStr, WriteServerConStr,
                          new RedisClientManagerConfig
                          {
                              MaxWritePoolSize = RedisConfigInfo.MaxWritePoolSize,
                              MaxReadPoolSize = RedisConfigInfo.MaxReadPoolSize,
                              AutoStart = RedisConfigInfo.AutoStart,
                          });
     }

     /// <summary>
     /// 用戶端緩存操作對象
     /// </summary>
     public static IRedisClient GetClient()
     {
         return prcManager.GetClient();
     }
 }



 /// <summary>
 /// RedisBase類,是redis操作的基類,繼承自IDisposable接口,主要用于釋放記憶體
 /// </summary>
 public abstract class RedisBase : IDisposable
 {
     public IRedisClient iClient { get; private set; }
     /// <summary>
     /// 構造時完成連結的打開
     /// </summary>
     public RedisBase()
     {
         iClient = RedisManager.GetClient();
     }

     //public static IRedisClient iClient { get; private set; }
     //static RedisBase()
     //{
     //    iClient = RedisManager.GetClient();
     //}


     private bool _disposed = false;
     protected virtual void Dispose(bool disposing)
     {
         if (!this._disposed)
         {
             if (disposing)
             {
                 iClient.Dispose();
                 iClient = null;
             }
         }
         this._disposed = true;
     }
     public void Dispose()
     {
         Dispose(true);
         GC.SuppressFinalize(this);
     }

     public void Transcation()
     {
         using (IRedisTransaction irt = this.iClient.CreateTransaction())
         {
             try
             {
                 irt.QueueCommand(r => r.Set("key", 20));
                 irt.QueueCommand(r => r.Increment("key", 1));
                 irt.Commit(); // 送出事務
             }
             catch (Exception ex)
             {
                 irt.Rollback();
                 throw ex;
             }
         }
     }


     /// <summary>
     /// 清除全部資料 請小心
     /// </summary>
     public virtual void FlushAll()
     {
         iClient.FlushAll();
     }

     /// <summary>
     /// 儲存資料DB檔案到硬碟
     /// </summary>
     public void Save()
     {
         iClient.Save();//阻塞式save
     }

     /// <summary>
     /// 異步儲存資料DB檔案到硬碟
     /// </summary>
     public void SaveAsync()
     {
         iClient.SaveAsync();//異步save
     }
 }      

View Code

Redis中的五大結構

1、String:

Redis緩存NoSQL

  key-value,緩存,支援過期,value不超過512M。Redis單線程的特性,比如SetAll、AppendToValue、GetAndSetValue、IncrementValue、IncrementValueBy,這些指令,看上去是組合指令,實際上是具體的指令,是一個原則性的操作,不用考慮并發,不可能出現中間狀态,可以應對一些并發情況。

 現在有個場景,就是超賣的問題,超賣,顧名思義,就是訂單數超過商品。

  資料庫:秒殺的時候,10件商品,100個人想買,假定大家一瞬間都來了,A 查詢還有沒有--有---1更新;C 查詢還有沒有--有---1更新;可能會賣出12  12甚至20件商品;微服務也有超賣的問題,異步隊列。Redis原子性操作--保證一個數值隻出現一次--防止一個商品賣給多個人

  Redis是單線程的,程式有怎麼多線程操作Redis呢?打開多個連結,去送出任務,對程式而言,Redis是并發。是以用上了Redis,一方面保證絕對不會超賣,另一方面沒有效率影響,資料庫是可以為成功的人并發的,還有撤單的時候增加庫存,可以繼續秒殺,,限制秒殺的庫存是放在redis,不是資料庫,不會造成資料的不一緻性,Redis能夠攔截無效的請求,如果沒有這一層,所有的請求壓力都到資料庫。

超賣的代碼示例:

/// <summary>
 /// key-value 鍵值對:value可以是序列化的資料
 /// </summary>
 public class RedisStringService : RedisBase
 {
     #region 指派
     /// <summary>
     /// 設定key的value
     /// </summary>
     public bool Set<T>(string key, T value)
     {
         return base.iClient.Set<T>(key, value);
     }
     /// <summary>
     /// 設定key的value并設定過期時間
     /// </summary>
     public bool Set<T>(string key, T value, DateTime dt)
     {
         return base.iClient.Set<T>(key, value, dt);
     }
     /// <summary>
     /// 設定key的value并設定過期時間
     /// </summary>
     public bool Set<T>(string key, T value, TimeSpan sp)
     {
         return base.iClient.Set<T>(key, value, sp);
     }
     /// <summary>
     /// 設定多個key/value
     /// </summary>
     public void Set(Dictionary<string, string> dic)
     {
         base.iClient.SetAll(dic);
     }

     #endregion

     #region 追加
        /// <summary>
        /// 在原有key的value值之後追加value,沒有就新增一項
        /// </summary>
        public long Append(string key, string value)
        {
            return base.iClient.AppendToValue(key, value);
        }
        #endregion

     #region 擷取值
        /// <summary>
        /// 擷取key的value值
        /// </summary>
        public string Get(string key)
        {
            return base.iClient.GetValue(key);
        }
        /// <summary>
        /// 擷取多個key的value值
        /// </summary>
        public List<string> Get(List<string> keys)
        {
            return base.iClient.GetValues(keys);
        }
        /// <summary>
        /// 擷取多個key的value值
        /// </summary>
        public List<T> Get<T>(List<string> keys)
        {
            return base.iClient.GetValues<T>(keys);
        }
        #endregion

     #region 擷取舊值賦上新值
     /// <summary>
     /// 擷取舊值賦上新值
     /// </summary>
     public string GetAndSetValue(string key, string value)
     {
         return base.iClient.GetAndSetValue(key, value);
     }
     #endregion

     #region 輔助方法
     /// <summary>
     /// 擷取值的長度
     /// </summary>
     public long GetLength(string key)
     {
         return base.iClient.GetStringCount(key);
     }
     /// <summary>
     /// 自增1,傳回自增後的值
     /// </summary>
     public long Incr(string key)
     {
         return base.iClient.IncrementValue(key);
     }
     /// <summary>
     /// 自增count,傳回自增後的值
     /// </summary>
     public long IncrBy(string key, int count)
     {
         return base.iClient.IncrementValueBy(key, count);
     }
     /// <summary>
     /// 自減1,傳回自減後的值
     /// </summary>
     public long Decr(string key)
     {
         return base.iClient.DecrementValue(key);
     }
     /// <summary>
     /// 自減count ,傳回自減後的值
     /// </summary>
     /// <param name="key"></param>
     /// <param name="count"></param>
     /// <returns></returns>
     public long DecrBy(string key, int count)
     {
         return base.iClient.DecrementValueBy(key, count);
     }
     #endregion
 }      

View Code

public class OversellTest
 {
     private static bool IsGoOn = true;//秒殺活動是否結束
     public static void Show()
     {
         using (RedisStringService service = new RedisStringService())
         {
             service.Set<int>("Stock", 10);//是庫存
         }

         for (int i = 0; i < 5000; i++)
         {
             int k = i;
             Task.Run(() =>//每個線程就是一個使用者請求
             {
                 using (RedisStringService service = new RedisStringService())
                 {
                     if (IsGoOn)
                     {
                         long index = service.Decr("Stock");//-1并且傳回  
                         if (index >= 0)
                         {
                             Console.WriteLine($"{k.ToString("000")}秒殺成功,秒殺商品索引為{index}");
                             //可以分隊列,去資料庫操作
                         }
                         else
                         {
                             if (IsGoOn)
                             {
                                 IsGoOn = false;
                             }
                             Console.WriteLine($"{k.ToString("000")}秒殺失敗,秒殺商品索引為{index}");
                         }
                     }
                     else
                     {
                         Console.WriteLine($"{k.ToString("000")}秒殺停止......");
                     }
                 }
             });
         }
         Console.Read();
     }
 }


 public class OversellField
 {
     private static bool IsGoOn = true;//秒殺活動是否結束
     private static int Stock = 0;
     public static void Show()
     {
         Stock = 10;

         for (int i = 0; i < 5000; i++)
         {
             int k = i;
             Task.Run(() =>//每個線程就是一個使用者請求
             {
                 if (IsGoOn)
                 {
                     long index = Stock;//-1并且傳回 去資料庫查一下目前的庫存
                     Thread.Sleep(100);

                     if (index >= 1)
                     {
                         Stock = Stock - 1;//更新庫存
                         Console.WriteLine($"{k.ToString("000")}秒殺成功,秒殺商品索引為{index}");
                         //可以分隊列,去資料庫操作
                     }
                     else
                     {
                         if (IsGoOn)
                         {
                             IsGoOn = false;
                         }
                         Console.WriteLine($"{k.ToString("000")}秒殺失敗,秒殺商品索引為{index}");
                     }
                 }
                 else
                 {
                     Console.WriteLine($"{k.ToString("000")}秒殺停止......");
                 }
             });
         }
         Console.Read();
     }
 }      

View Code

2、Hash

  

Redis緩存NoSQL

 key-dictionary

  1、節約空間(zipmap的緊密擺放的存儲模式)

  2、更新/通路友善(hashid+key)

  3、Hash資料結構很想關系型資料庫的一張表的一行資料。但是其實字段是可以随意定制的,沒有嚴格限制。

緩存一個使用者的資訊,用String類型可以嗎?也可以,因為String類型,key-value,先序列化,然後再反序列化,然後存儲:

using (RedisStringService service = new RedisStringService())
 {
     //service.Set<string>($"userinfo_{user.Id}", Newtonsoft.Json.JsonConvert.SerializeObject(user));
     service.Set<UserInfo>($"userinfo_{user.Id}", user);
     var userCacheList = service.Get<UserInfo>(new List<string>() { $"userinfo_{user.Id}" });
     var userCache = userCacheList.FirstOrDefault();
     //string sResult = service.Get($"userinfo_{user.Id}");
     //var userCache = Newtonsoft.Json.JsonConvert.DeserializeObject<UserInfo>(sResult);
     userCache.Account = "Admin";
     service.Set<UserInfo>($"userinfo_{user.Id}", userCache);
 }      

View Code

如果修改需求,就是查詢---反序列化---修改---序列化---存儲。這樣真的太麻煩了。

現在有了Hash類型。

using (RedisHashService service = new RedisHashService())
{
    service.SetEntryInHash("student", "id", "bingle1");
    service.SetEntryInHash("student", "name", "bingle2");
    service.SetEntryInHash("student", "remark", "bingle3");

    var keys = service.GetHashKeys("student");
    var values = service.GetHashValues("student");
    var keyValues = service.GetAllEntriesFromHash("student");
    Console.WriteLine(service.GetValueFromHash("student", "id"));

    service.SetEntryInHashIfNotExists("student", "name", "bingle");
    service.SetEntryInHashIfNotExists("student", "description", "bingle");

    Console.WriteLine(service.GetValueFromHash("student", "name"));
    Console.WriteLine(service.GetValueFromHash("student", "description"));
    service.RemoveEntryFromHash("student", "description");
    Console.WriteLine(service.GetValueFromHash("student", "description"));
}      

View Code

Hash---》Hashid---UserInfo  

多個key,String類型的value,最小是512byte,即使隻儲存一個1,也要占用512byte的空間。而hash是一種zipmap存儲,資料緊密排列,可以節約空間(配置zip兩個屬性,隻要都滿足就可以用zipmap存儲)。

Hash的有點:

  1、節約空間

  2、更新友善

如果實體類型是帶ID的,可以直接實體存儲和讀取。

using (RedisHashService service = new RedisHashService())
 {
     service.FlushAll();
     //反射周遊做一下
     service.SetEntryInHash($"userinfo_{user.Id}", "Account", user.Account);
     service.SetEntryInHash($"userinfo_{user.Id}", "Name", user.Name);
     service.SetEntryInHash($"userinfo_{user.Id}", "Address", user.Address);
     service.SetEntryInHash($"userinfo_{user.Id}", "Email", user.Email);
     service.SetEntryInHash($"userinfo_{user.Id}", "Password", user.Password);
     service.SetEntryInHash($"userinfo_{user.Id}", "Account", "Admin");

     service.StoreAsHash<UserInfo>(user);//含ID才可以的
     var result = service.GetFromHash<UserInfo>(user.Id);

 }      

View Code

3、Set

Redis緩存NoSQL
using (RedisSetService service = new RedisSetService())
 {
     service.FlushAll();//清理全部資料

     service.Add("advanced", "111");
     service.Add("advanced", "112");
     service.Add("advanced", "114");
     service.Add("advanced", "114");
     service.Add("advanced", "115");
     service.Add("advanced", "115");
     service.Add("advanced", "113");

     var result = service.GetAllItemsFromSet("advanced");

     var random = service.GetRandomItemFromSet("advanced");//随機擷取
     service.GetCount("advanced");//獨立的ip數
     service.RemoveItemFromSet("advanced", "114");

     {
         service.Add("begin", "111");
         service.Add("begin", "112");
         service.Add("begin", "115");

         service.Add("end", "111");
         service.Add("end", "114");
         service.Add("end", "113");

         var result1 = service.GetIntersectFromSets("begin", "end");
         var result2 = service.GetDifferencesFromSet("begin", "end");
         var result3 = service.GetUnionFromSets("begin", "end");
         //共同好友   共同關注
     }
 }      

View Code

Redis緩存NoSQL

 好友管理,共同好友,可能認識

去重:IP統計去重;添加好友申請;投票限制;點贊。

4、ZSet:是一個有序集合,去重

  

Redis緩存NoSQL
using (RedisZSetService service = new RedisZSetService())
{
    service.FlushAll();//清理全部資料

    service.Add("advanced", "1");
    service.Add("advanced", "2");
    service.Add("advanced", "5");
    service.Add("advanced", "4");
    service.Add("advanced", "7");
    service.Add("advanced", "5");
    service.Add("advanced", "9");

    var result1 = service.GetAll("advanced");
    var result2 = service.GetAllDesc("advanced");

    service.AddItemToSortedSet("Sort", "bingle1", 123234);
    service.AddItemToSortedSet("Sort", "bingle2", 123);
    service.AddItemToSortedSet("Sort", "bingle3", 45);
    service.AddItemToSortedSet("Sort", "bingle4", 7567);
    service.AddItemToSortedSet("Sort", "bingle5", 9879);
    service.AddRangeToSortedSet("Sort", new List<string>() { "123", "花生", "加菲貓" }, 3232);
    var result3 = service.GetAllWithScoresFromSortedSet("Sort");

    //交叉并
}      

View Code

Redis緩存NoSQL

 最後一個參數,是自己設定的,設定value的分數的。

Redis緩存NoSQL

 實時排行榜:刷個禮物。

次元很多,平台/房間/主播/日/周/年/月

A對B刷個禮物,影響很多。

沒Redis之前,刷個禮物值記錄流水,不影響排行,淩晨24點跑任務更新。

實時排行榜,Redis-IncrementItemInSortedSet,刷禮物增加Redis分數,就可以試試擷取最新的排行,多個次元就是多個ZSet,刷禮物的時候儲存資料庫并更新Redis。

5、List

  

Redis緩存NoSQL

生産者消費者:

using (RedisListService service = new RedisListService())
{
    service.Add("test", "這是一個學生Add1");
    service.Add("test", "這是一個學生Add2");
    service.Add("test", "這是一個學生Add3");

    service.LPush("test", "這是一個學生LPush1");
    service.LPush("test", "這是一個學生LPush2");
    service.LPush("test", "這是一個學生LPush3");
    service.LPush("test", "這是一個學生LPush4");
    service.LPush("test", "這是一個學生LPush5");
    service.LPush("test", "這是一個學生LPush6");

    service.RPush("test", "這是一個學生RPush1");
    service.RPush("test", "這是一個學生RPush2");
    service.RPush("test", "這是一個學生RPush3");
    service.RPush("test", "這是一個學生RPush4");
    service.RPush("test", "這是一個學生RPush5");
    service.RPush("test", "這是一個學生RPush6");

    List<string> stringList = new List<string>();
    for (int i = 0; i < 10; i++)
    {
        stringList.Add(string.Format($"放入任務{i}"));
    }
    service.Add("task", stringList);

    Console.WriteLine(service.Count("test"));
    Console.WriteLine(service.Count("task"));
    var list = service.Get("test");
    list = service.Get("task", 2, 4);

    Action act = new Action(() =>
    {
        while (true)
        {
            Console.WriteLine("************請輸入資料**************");
            string testTask = Console.ReadLine();
            service.LPush("test", testTask);
        }
    });
    act.EndInvoke(act.BeginInvoke(null, null));
}      

View Code

生産者消費者(隊列)一個資料,隻能被一個對象消費,一個程式寫入,一個程式即時讀取消費,還可以多個程式讀取消費,按照時間順序,資料失敗了還可以放回去下次重試,這種東西在項目中有什麼價值呢?和那些MQ差不多,就是隊列。

異步隊列:

  優點:

    1、可以控制并發數量

    2、以前要求立馬處理完,現在可以在一個時段完成

    3、失敗還能重試

    4、流量削峰,降低高峰期的壓力

    5、高可用

    6、可擴充

  缺點:

    1、不能了解處理

    2、事務的一緻性問題。

釋出訂閱,釋出一個資料,全部的訂閱者都能收到。觀察者,一個資料源,多個接受者,隻要訂閱了就可以收到的,能被多個資料源共享。觀察者模式:微信訂閱号---群聊天----資料同步

MSMQ---RabbitMQ---ZeroMQ----RocketMQ---RedisList

分布式緩存,多個伺服器都可以通路到,多個生産者,多個消費者,任何産品隻被消費一次。

using (RedisListService service = new RedisListService())
 {

     service.Add("test", "這是一個學生Add1");
     service.Add("test", "這是一個學生Add2");
     service.Add("test", "這是一個學生Add3");

     service.LPush("test", "這是一個學生LPush1");
     service.LPush("test", "這是一個學生LPush2");
     service.LPush("test", "這是一個學生LPush3");
     service.LPush("test", "這是一個學生LPush4");
     service.LPush("test", "這是一個學生LPush5");
     service.LPush("test", "這是一個學生LPush6");

     service.RPush("test", "這是一個學生RPush1");
     service.RPush("test", "這是一個學生RPush2");
     service.RPush("test", "這是一個學生RPush3");
     service.RPush("test", "這是一個學生RPush4");
     service.RPush("test", "這是一個學生RPush5");
     service.RPush("test", "這是一個學生RPush6");

     List<string> stringList = new List<string>();
     for (int i = 0; i < 10; i++)
     {
         stringList.Add(string.Format($"放入任務{i}"));
     }
     service.Add("task", stringList);

     Console.WriteLine(service.Count("test"));
     Console.WriteLine(service.Count("task"));
     var list = service.Get("test");
     list = service.Get("task", 2, 4);

     //Action act = new Action(() =>
     //{
     //    while (true)
     //    {
     //        Console.WriteLine("************請輸入資料**************");
     //        string testTask = Console.ReadLine();
     //        service.LPush("test", testTask);
     //        Console.ReadLine();
     //    }
     //});
     //act.EndInvoke(act.BeginInvoke(null, null));

     while (true)
     {
         Console.WriteLine("************請輸入資料**************");
         string testTask = Console.ReadLine();
         service.LPush("test", testTask);
     }

 }      

View Code

public class ServiceStackProcessor
 {
     public static void Show()
     {
         string path = AppDomain.CurrentDomain.BaseDirectory;
         string tag = path.Split('/', '\\').Last(s => !string.IsNullOrEmpty(s));
         Console.WriteLine($"這裡是 {tag} 啟動了。。");
         using (RedisListService service = new RedisListService())
         {
             Action act = new Action(() =>
             {
                 while (true)
                 {
                     var result = service.BlockingPopItemFromLists(new string[] { "test", "task" }, TimeSpan.FromHours(3));
                     Thread.Sleep(100);
                     Console.WriteLine($"這裡是 {tag} 隊列擷取的消息 {result.Id} {result.Item}");
                 }
             });
             act.EndInvoke(act.BeginInvoke(null, null));
         }
     }

 }      

View Code

Redis緩存NoSQL

ask項目,問答,一天的問題都是幾萬,表裡面是幾千萬資料,首頁要戰士最新的問題,Ajax動态定時擷取重新整理,還有前20也是很多人通路的。

每次寫入資料庫的時候,把ID_标題寫到RedisList,後面搞個TrimList,隻要最近200個,使用者重新整理頁面的時候就不需要去資料庫了,直接Redis。

還有一種就是水準分表,第一次的時候不管分頁,隻拿資料,存資料的時候可以儲存id+表全名。

主要解決資料量大,變化的資料分頁問題。二八原則,80%的通路集中在20%的資料,List裡面隻用儲存大概的量就夠了。

  

轉載于:https://www.cnblogs.com/taotaozhuanyong/p/11565527.html