Redis緩存NoSQL

下面是一些關於Redis比較好的文章,由於篇幅較大,我就將其摺疊起來了。不太喜歡分不一樣的筆記去記載,除非真的不少不少。因此本文不只要對Redis作簡單的介紹,還要分別介紹Redis中的五種結構,並會貼上一些示例代碼,由於篇幅比較大,因此示例代碼都是摺疊起來的,有須要看代碼的請自行點開,還請諒解。這裏只附上了不分示例代碼。php

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

本地緩存,當前進程的內存,把數據存起來,下次直接使用,能夠提高效率。html

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

  二、多服務器直接須要緩存共享,須要分佈式緩存,遠程服務器內存管理數據,提供讀寫接口,效率高。git

分佈式緩存:github

  一、Memcached,最先流行的web

  二、Redis(NoSQL)如今的主流方案redis

爲何如今都升級到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,封裝了鏈接+命令。

 

 

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

管理員模式打開控制檯(配置成本身的路徑)

能夠打開redis-cli.exe嘗試使用,
輸入:set key value 
結果:OK
輸入:get key 
結果:value

 Redis安裝與啓動,以及可視化管理工具,請參考:http://www.javashuo.com/article/p-mqurzecg-cs.html

用cli,能夠簡單的對Redis數據新增和獲取

 

 

 

 

 

   基於內存管理,速度快,不能當作數據庫。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中的五大結構

一、String:

  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

二、Hash

  

 

 

 key-dictionary

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

  二、更新/訪問方便(hashid+key)

  三、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的有點:

  一、節約空間

  二、更新方便

若是實體類型是帶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

三、Set

 

 

 

 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

 

 

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

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

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

  

 

 

 

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

 

 

 最後一個參數,是本身設定的,設定value的分數的。

 

 

 實時排行榜:刷個禮物。

維度不少,平臺/房間/主播/日/周/年/月

A對B刷個禮物,影響不少。

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

實時排行榜,Redis-IncrementItemInSortedSet,刷禮物增長Redis分數,就能夠試試獲取最新的排行,多個維度就是多個ZSet,刷禮物的時候保存數據庫並更新Redis。

五、List

  

生產者消費者:

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差很少,就是隊列。

異步隊列:

  優勢:

    一、能夠控制併發數量

    二、之前要求立馬處理完,如今能夠在一個時段完成

    三、失敗還能重試

    四、流量削峯,下降高峯期的壓力

    五、高可用

    六、可擴展

  缺點:

    一、不能理解處理

    二、事務的一致性問題。

發佈訂閱,發佈一個數據,所有的訂閱者都能收到。觀察者,一個數據源,多個接受者,只要訂閱了就能夠收到的,能被多個數據源共享。觀察者模式:微信訂閱號---羣聊天----數據同步

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

ask項目,問答,一天的問題都是幾萬,表裏面是幾千萬數據,首頁要戰士最新的問題,Ajax動態定時獲取刷新,還有前20也是不少人訪問的。

每次寫入數據庫的時候,把ID_標題寫到RedisList,後面搞個TrimList,只要最近200個,用戶刷新頁面的時候就不須要去數據庫了,直接Redis。

還有一種就是水平分表,第一次的時候無論分頁,只拿數據,存數據的時候能夠保存id+表全名。

主要解決數據量大,變化的數據分頁問題。二八原則,80%的訪問集中在20%的數據,List裏面只用保存大概的量就夠了。

相關文章
相關標籤/搜索