Redis基本使用及百億數據量中的使用技巧分享

来源:https://www.cnblogs.com/yilezhu/archive/2018/11/11/9941208.html
-Advertisement-
Play Games

作者:依樂祝 原文地址:https://www.cnblogs.com/yilezhu/p/9941208.html 作者:大石頭 時間:2018 11 10 晚上20:00 地點:釘釘群(組織代碼BKMV7685)QQ群:1600800 內容:Redis基本使用及百億數據量中的使用技巧分享 記錄人 ...


作者:依樂祝
原文地址:https://www.cnblogs.com/yilezhu/p/9941208.html

  • 作者:大石頭
  • 時間:2018-11-10 晚上20:00
  • 地點:釘釘群(組織代碼BKMV7685)QQ群:1600800
  • 內容:Redis基本使用及百億數據量中的使用技巧分享
  • 記錄人:依樂祝

熱場準備

熟悉的開場白,大家晚上好啊,今天給大家分享的是Redis在大數據中的使用,可能真正講的是一些redis的使用技巧,Redis基本的一些東西。

首先給大家個地址,源碼以及實例都在裡面,當然今天的分享也是按照裡面的實例來進行的,大家可以先進行下載。
http://git.newlifex.com/NewLife/NewLife.Redis
當然這裡也附上Redis的下載地址:
windows:https://github.com/MicrosoftArchive/redis/releases
http://x.newlifex.com/Redis-x64-3.2.100.msi
Linux:https://redis.io/download

開始

Redis封裝架構講解

實際上NewLife.Redis是一個完整的Redis協議的功能的實現,但是redis的核心功能並沒有在這裡面,Redis的核心功能的實現是在NewLife.Core裡面。這裡可以打開看一下,NewLife.Core裡面有一個NewLife.Caching的命名空間,裡面有一個Redis類裡面實現了Redis的基本功能,另一個類是RedisClient是Redis的客戶端。Redis的核心功能就是有這兩個類實現。RedisClient代表著Redis客戶端對伺服器的一個連接。Redis真正使用的時候有一個Redis連接池,裡面存放著很多個RedisClient對象。

1541862210472
所以我們Redis的封裝有兩層,一層是NewLife.Core裡面的Redis以及RedisClient。另一層就是NewLife.Redis。這裡面的FullRedis是對Redis的實現了Redis的所有的高級功能。這裡你也可以認為NewLife.Redis是Redis的一個擴展。

Test實例講解Redis的基本使用

實例

打開Program.cs看下代碼

1541862821768

這裡XTrace.UseConsole();是向控制台輸出日誌,方便調試使用查看結果。

接下來看第一個例子Test1。具體的我都在代碼中進行了註釋,大家可以看下

 static void Test1()
        {
            var ic = Redis.Create("127.0.0.1:6379", 3);//創建Redis實例,得到FullRedis對象
            //var ic = new FullRedis();//另一種實例化的方式
            //ic.Server = "127.0.0.1:6379";
            //ic.Db = 3;//Redis中資料庫
            ic.Log = XTrace.Log;//顯示日誌,進行Redis操作把日誌輸出,生產環境不用輸出日誌

            // 簡單操作
            Console.WriteLine("共有緩存對象 {0} 個", ic.Count);//緩存對象數量

            ic.Set("name", "大石頭");//Set K-V結構,Set第二個參數可以是任何類型
            Console.WriteLine(ic.Get<String>("name"));//Get泛型,指定獲取的類型

            ic.Set("time", DateTime.Now, 1);//過期時間秒
            Console.WriteLine(ic.Get<DateTime>("time").ToFullString());
            Thread.Sleep(1100);
            Console.WriteLine(ic.Get<DateTime>("time").ToFullString());

            // 列表
            var list = ic.GetList<DateTime>("list");
            list.Add(DateTime.Now);
            list.Add(DateTime.Now.Date);
            list.RemoveAt(1);
            Console.WriteLine(list[list.Count - 1].ToFullString());

            // 字典
            var dic = ic.GetDictionary<DateTime>("dic");
            dic.Add("xxx", DateTime.Now);
            Console.WriteLine(dic["xxx"].ToFullString());

            // 隊列
            var mq = ic.GetQueue<String>("queue");
            mq.Add(new[] { "abc", "g", "e", "m" });
            var arr = mq.Take(3);
            Console.WriteLine(arr.Join(","));

            // 集合
            var set = ic.GetSet<String>("181110_1234");
            set.Add("xx1");
            set.Add("xx2");
            set.Add("xx3");
            Console.WriteLine(set.Count);
            Console.WriteLine(set.Contains("xx2"));

            Console.WriteLine("共有緩存對象 {0} 個", ic.Count);
        }
  1. Set的時候如果是字元串或者字元數據的話Redis會直接保存起來(字元串內部機制也是保存二進位),如果是其他類型會預設進行json序列化然後再保存起來

  2. Get的時候如果是字元串或者字元數據會直接獲取,如果是其他類型會進行json反序列化

  3. Set第三個參數過期時間單位是秒。

  4. vs調試小技巧,按F5或者直接工具欄“啟動”會編譯整個解決方案會很慢(VS預設),可以選中項目然後右鍵菜單選擇調試->啟動新實例。會只編譯將會用到的項目,這樣對調試來說會快很多。

  5. 大家運行調試後可以看到控制台輸出的內容:向右的箭頭=》是ic.Log=XTrace.Log輸出的日誌

    1541865736212

  6. 字典的使用:對象的話需要把json全部取出來然後轉換成對象,而字典的話就可以直接取某個欄位。

  7. 隊列是List結構實現的,使用場景可以上游數據太多,下游處理不過來的時候,那麼就可以使用這個隊列。上游的數據發到隊列,然後下游慢慢的消費。另一個應用,跨語言的協同工作,比方說其他語言實現的程式往隊列裡面塞數據,然後另一種語言來進行消費處理。哈,這種方式類似mq的概念,雖然有點low,但是也很好用。

  8. 集合,用的比較多的是用在一個需要精確判斷的去重功能。像我們每天有三千萬訂單,這三千萬訂單可以有重覆,這時候我想統計下一共有訂單,這時候直接資料庫group by是不大可能的,因為資料庫中分了十幾張表,這裡分享個實戰經驗:比方說攬收,商家發貨了,網點要把件收回來,但是收回來之前網點不知道自己有多少貨啊,這時候我們做了一個功能,也就是訂單會發送到我們公司來,我們會建一個time_site的key的集合,而且集合本身有去重的功能,而且我們可以很方便的通過set.Count功能來統計數量,當件被攬收以後,我們後臺把這個件從集合中Remove掉.然後這個Set中存在的就是網點還沒有攬收的件,這時候通過Count就會知道這個網點今天還有多少件沒有攬收。實際使用中這個數量比較大,因為有幾萬個網點。

  9. Redis中布隆過濾器,去重的,面試的時候問的比較多

  10. 小經驗分享:

    • 資料庫中不合法的時間處理:判斷時間中的年份,是否大於2000年。如果小於2000就認為不合法。習慣大於小於號不習慣用等於號,這樣可以處理很多意外的數據
    • Set的時候最好指定過期時間防止有些需要刪除的數據,我們忘記刪了
    • Redis非同步儘量不用,因為Redis延遲本身很小,大概在100us-200us,再一個就是Redis本身是單線程的,非同步任務切換的耗時比網路耗時還要大。
    • List用法:物聯網中數據上傳,量比較大時,我們可以把這些數據先放在Redis的List中,比如說一秒鐘1萬條,然後再批量取出來然後批量插入資料庫中。這時候要設置好key,可以首碼+時間,對於已經處理的List可以進行remove移除。

壓力測試

接下來看第四個例子,我們直接做壓力測試,代碼如下:

 static void Main(String[] args)
        {
            XTrace.UseConsole();

            // 激活FullRedis,否則Redis.Create會得到預設的Redis對象
            FullRedis.Register();

            Test4();

            Console.ReadKey();
        }
 static void Test4()
        {
            var ic = Redis.Create("127.0.0.1:6379", 5);
            //var ic = new MemoryCache();
            ic.Bench();
        }

運行的結果如下圖所示:

1541867419541

測試就是進行get,set remove,累加等的操作。大家可以看到在我本機上輕輕鬆松的到了六十萬,多線程的時候甚至到了一百多萬。為什麼會達到這麼高的ops呢,下麵給大家說一下。

  • Bench 會分根據線程數分多組進行添刪改壓力測試。
  • rand 參數,是否隨機產生key/value。
  • batch 批大小,分批執行讀寫操作,藉助GetAll/SetAll進行優化。

Redis中NB的函數來提升性能

上面的操作如果大家都掌握的基本算Redis入門了,接下來進行進階。會了基本比別人更勝一籌了。

  1. GetAll()與SetAll()

GetAll:比方說我要取是個key,這個時候可以用getall。這時候redis就執行了一次命令。比方說我要取10個key那麼用get的話要取10次,如果用getall的話要用1次。一次getall時間大概是get的一點幾倍,但是10次get的話就是10倍的時間,這個賬你應該會算吧。強烈推薦大家用getall。

setall 跟getall相似。批量設置K-V.

setall與getall性能很恐怖,官方公佈的ops也就10萬左右,為什麼我們的測試輕輕鬆松到五十萬甚至上百萬,因為我們就用了setall,getall。

如果get,set兩次以上,建議用getall,setall

  1. Redis管道Pipeline

比如執行10次命令會打包成一個包集體發過去執行,這裡實現的方式是StartPipeline()開始,StopPipeline()結束中間的代碼就會以管道的形式執行。這裡推薦使用我們的更強的武器,AutoPipeline自動管道屬性。管道操作到一定數量時,自動提交,預設0.使用了不需要使用AutoPipeline,就不需要StartPipeline,StopPipeline指定開始結束了!

  1. Add與Replace
  • Add:Redis中沒有這個Key就添加,有了就不要添加,返回false
  • Replace:有則替換,還會返回原來的值,沒有則不進行操作

Add跟Replace就是實現Redis分散式鎖的關鍵

Redis使用技巧,經驗分享

在項目的Readme中,這裡摘錄下:

特性

  • 在ZTO大數據實時計算廣泛應用,200多個Redis實例穩定工作一年多,每天處理近1億包裹數據,日均調用量80億次
  • 低延遲,Get/Set操作平均耗時200~600us(含往返網路通信)
  • 大吞吐,自帶連接池,最大支持1000併發
  • 高性能,支持二進位序列化(預設用的json,json很低效,轉成二進位性能會提升很多)

Redis經驗分享

  • 在Linux上多實例部署,實例個數等於處理器個數,各實例最大記憶體直接為本機物理記憶體,避免單個實例記憶體撐爆(比方說8核心處理器,那麼就部署8個實例)
  • 把海量數據(10億+)根據key哈希(Crc16/Crc32)存放在多個實例上,讀寫性能成倍增長
  • 採用二進位序列化,而非常見的Json序列化
  • 合理設計每一對Key的Value大小,包括但不限於使用批量獲取,原則是讓每次網路包控制在1.4k位元組附近,減少通信次數(實際經驗幾十k,幾百k也是沒問題的)
  • Redis客戶端的Get/Set操作平均耗時200~600us(含往返網路通信),以此為參考評估網路環境和Redis客戶端組件(達不到就看一下網路,序列化方式等等)
  • 使用管道Pipeline合併一批命令
  • Redis的主要性能瓶頸是序列化、網路帶寬和記憶體大小,濫用時處理器也會達到瓶頸
  • 其它可查優化技巧
    以上經驗,源自於300多個實例4T以上空間一年多穩定工作的經驗,並按照重要程度排了先後順序,可根據場景需要酌情採用!

緩存Redis的兄弟姐妹

Redis實現ICache介面,它的孿生兄弟MemoryCache,記憶體緩存,千萬級吞吐率。
各應用強烈建議使用ICache介面編碼設計,小數據時使用MemoryCache實現;
數據增大(10萬)以後,改用Redis實現,不需要修改業務代碼。

提問環節聊聊大數據中Redis使用的經驗,問題

  1. 一條數據多個key怎麼設置比較合理?
    如果對性能要求不是很高直接用json序列化實體就好,沒必要使用字典進行存儲。

  2. 隊列跟List有什麼區別?左進右出的話用List還是用隊列比較好?
    隊列其實就是用List實現的,也是基於List封裝的。左進右出的話直接隊列就好。Redis的List結構比較有意思,既可以左進右出,也能右進左出。所以它既可以實現列表結構,也能隊列,也能實現棧

  3. 存放多個欄位的類性能一樣嗎?
    大部分場景都不會有偏差,可能對於大公司數據量比較大的場景會有些偏差

  4. 可否介紹一下使用Redis進行數據計算、統計的場景?
    略。自己看視頻吧!o(∩_∩)o 哈哈!(因為我沒聽清!)

  5. 大數據寫入到資料庫之後 比如數據到億以上的時候 統計分析這塊 查詢這塊 能不能分享些經驗。
    分表分庫,拆分到一千萬以內。

  6. CPU為何暴漲?

程式員終極理念:CPU達到百分百,然後性能達到最優,儘量不要浪費。最痛恨的是:如果cpu不到百分百,性能沒法提升了,說明代碼有問題!

總結

雖然Redis會用,但是沒有像大石頭這樣的大數據使用場景。今天的視頻收穫頗豐,可能大部分人跟我一樣,沒有大石頭的使用場景,但是值得借鑒的經驗還是很豐富的!期待下一次的精彩分享。同時附上QQ群:1600800。可以共同交流使用經驗!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 負荷權重 1.1 負荷權重結構struct load_weight 負荷權重用struct load_weight數據結構來表示, 保存著進程權重值weight。其定義在 "/include/linux/sched.h, v=4.6, L1195" , 如下所示 1.2 調度實體的負荷權重lo ...
  • 我使用的xampp 1、修改C:\Windows\System32\drivers\etc中的hosts文件,添加127.0.0.1 www.feiquan.com 2、修改D:\xampp\apache\conf\extra中的httpd-vhosts.conf,添加 3. 配置D:\xampp\ ...
  • 文章的格式也許不是很好看,也沒有什麼合理的順序 完全是想到什麼寫一些什麼,但各個方面都涵蓋到了 能耐下心看的朋友歡迎一起學習,大牛和杠精們請繞道 Arachni不同於上次介紹的nikto和skipfish 是一個Web界面的一個Web掃描器 Arachni的強大不必多說: 國際知名黑客組織匿名者,在 ...
  • 集群結構 特點: 1 所有redis節點(包括主和從)彼此互聯(兩兩通信),底層使用內部的二進位傳輸協議,優化傳輸速度;(所有功能特點的基礎) 2 集群中也有主從,也有高可用的邏輯,但是沒有哨兵進程,整合到主節點的功能里了;集群中的事件被主節點(大部分主節點);通過主節點的過半選舉實現哨兵以前的邏輯 ...
  • 我們經常在linux要查找某個文件,但不知道放在哪裡了,可以使用下麵的一些命令來搜索: which 查看可執行文件的位置。 whereis 查看文件的位置。 locate 配合資料庫查看文件位置。 find 實際搜尋硬碟查詢文件名稱。 which命令的作用是,在PATH變數指定的路徑中,搜索某個系統 ...
  • 第一部分 ES安裝環境的準備和初始化 現在交心的版本Elasticsearch 5.6.3 官方建議安裝Oracle的JDK8,安裝前先檢查機器是否已安裝JDK。 Step 1 檢查環境機器是否已安裝JDK rpm -qa | grep -E '^open[jre|jdk]|j[re|dk]' 如果 ...
  • SQL Server 資料庫中表一旦創建,我們不建議擅自調整列的順序,特別是對應的應用系統已經上線,因為部分開發人員,不一定在代碼中指明瞭列名。表是否可以調整列的順序,其實可以自主設置,我們建議在安裝後設置為禁止。 那麼,如果確實需要調整某一列的順序,我們是怎麼操作的呢? 下麵,我們就要演示一下怎麼 ...
  • 好的表結構分的比較細緻,個人理解大概主要分為主表、明細、歷史記錄表、中間表,輔助表結構應該分為:類型表、狀態表、統計表、統計明細表等。為了一個功能加那麼多表實在是多餘,如果寫一個非常複雜的業務邏輯還是很有必要的,因為要做到物帳聯動。這可能不是一個明智的選擇,還有一種方案是儘可能的壓縮表結構,少分一些 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...