緩存中間件-Redis(一)

来源:https://www.cnblogs.com/yuxl01/archive/2022/04/11/16094209.html
-Advertisement-
Play Games

1.Redis介紹 REmote DIctionary Server(Redis) 是一個由Salvatore Sanfilippo寫的 key-value 存儲系統,是跨平臺的非關係型資料庫,Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協議、支持網路、可基於記憶體、分散式、可 ...


1.Redis介紹

REmote DIctionary Server(Redis) 是一個由Salvatore Sanfilippo寫的 key-value 存儲系統,是跨平臺的非關係型資料庫,Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協議、支持網路、可基於記憶體、分散式、可選持久性的鍵值對(Key-Value)存儲的非關係型資料庫,常被用於分散式緩存,作為進程外的緩存,它具有以下特點:

1.方便擴展

2.大數據量高性能

3.八大數據結構

4.分散式存儲

2.什麼時候使用Redis

1.在分析什麼場景使用Redis時,我們首先看下麵的系統設計圖,我們用戶發起請求到達Nginx,然後由Nginx來負載均衡到不同的服務實例,服務實例去訪問資料庫,正常來看沒什麼問題,但是如果集群的單個實例是一個獨立的系統,如果我們在單個系統中使用了緩存就會出現問題,具體是什麼問題呢?

2.當用戶請求被負載均衡到不同的伺服器時,第一個請求被服務實例1接收,它的執行流程是查詢資料庫返回然後緩存,第二個用戶請求同樣的內容,但是被負載均衡分配到服務實例2,對於服務實例2來說這是一個全新的請求,那麼又會訪問資料庫,對於我們來說這是很浪費的,當然在正常請求比較少造成的影響不大,但是如果請求併發較高,緩存的命中幾率被放大,導致請求直接訪問資料庫造成阻塞,影響系統可用性。

同理我們可以這樣理解,我們為了伺服器更好的承載,加入了更多的服務實例,那麼組成集群的單個實例越多,與緩存命中率是成反比的,當然我們可以在負載均衡時使用一些措施,使用iphash,來將某一客戶端的訪問與固定單個實例綁定,但是比較局限,不夠靈活,那麼應該怎麼去更好的解決這個問題呢?

此時我們嘗試在上述的架構圖中加入Redis,利用Redis的讀寫高性能的特點,來做統一的緩存,用於降低資料庫的壓力以及保證系統高可用,因為從讀寫速度而言CPU > 記憶體 > 磁碟

3.Redis通信原理
1.單線程和多線程對比

1.單線程原子性操,一個線程做一個任務,不需要鎖也不需要線程的上下文的切換。

2.多線程要實現原子性,涉及到各種鎖,上下文的切換性能的消耗。

3.單線程多進程 ,可以根據我們的服務,開啟多個實例。

2.IO多路復用

多路復用的概念就是多個IO復用一個線程處理,簡單的意思是在一個操作里同時監聽多個輸入輸出源,它和我們的非同步區別就是,前者是輪訓等待任務執行完成拿到結果,而後者則是在任務執行的過程中,自己去執行其他的任務,在不同的操作系統對多路復用有不同的實現,例如Windows內核中實現根據Select 而LInux內核中的實現是Epoll接下來我們簡單介紹下他們2種的區別。

Select
用戶請求到達內核,內核將請求封裝成一個句柄描述,放入本地消息隊列,然後迴圈隊列中的所有句柄,判斷是否處理完成,如果完成待所有的迴圈走完後,就將請求轉發到用戶進程,但是會隨著連接數增大,性能下降,處理數據太大的話,性能很差。

Epoll

用戶請求到達內核,內核將請求封裝成一個句柄描述和時間回調,放入本地消息隊列,待處理完畢就會觸發事件,不用去迴圈隊列中的所有消息,內核再將請求轉發到用戶進程,隨著連接數增大,性能基本沒影響,適合併發強度大的場景.

4.基本數據結構

在實際過程中,我們利用Stackexchange.Redis來進行操作.Net與Redis的互操作,當然也可以使用Servicestack.Redis他也同樣可以實現交互。

1.web中安裝和配置環境

1.創建Net6 WebApi項目,並且NuGet下載StackExchange.Redis最新版安裝到項目中。

2.擴展Redis客戶端初始化連接,並且在Startup中添加到IOC容器

//擴展連接客戶端
public static class RedisServiceCollectionExtensions
{
    public static IServiceCollection AddRedisCache(this IServiceCollection services, string connectionString)
    {
        ConfigurationOptions configuration = ConfigurationOptions.Parse(connectionString);
        ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(connectionString);
        services.AddSingleton(connectionMultiplexer);
        return services;
    }
}
//註入容器
services.AddRedisCache("127.0.0.1:6379,password=xxx,connectTimeout=2000");

3.在Api中創建RedisController控制器,並註入ConnectionMultiplexer

public class RedisController : ControllerBase
{
    private readonly ConnectionMultiplexer _connectionMultiplexer;

    private readonly IDatabase db;
    public RedisController(ConnectionMultiplexer connectionMultiplexer)
    {
       _connectionMultiplexer = connectionMultiplexer;
       db = _connectionMultiplexer.GetDatabase(0);
    }
}
2.string類型

1.string類型數據時Redis中最基礎的類型,其他類型在此基礎上構建.

2.string類型不僅僅會開闢占有的空間,還會預留一部分空間,最大能存儲 512MB,可以是簡單的Key,value,也可以是複雜的xml/json的字元串、二進位圖像或者音頻的字元串、以及可以是數字的字元串。

TestData testData = new TestData();
//首先序列化
string json = JsonConvert.SerializeObject(entity);
//設置30秒後失效
db.StringSet("TestData", demojson,TimeSpan.FromSeconds(30));
3.Set 集合

1.redis集合(set)類型和list列表類型類似,都可以用來存儲多個字元串元素的集合

2.和list不同的是set集合當中不允許重覆的元素。而且set集合當中元素是沒有順序的,不存在元素下標,intzset 最大存儲2的64次方,或者內容超過512個位元組就使用HashTable

3.Redis中的Set數據結構它由數組HashTable組成,每一個數組值都經過hash計算,支持集合內的增刪改查,並且支持多個集合間的交集、並集、差集操作

RedisValue[] values = db.SetMembers("testdatas");
List<TestData> data = new List<TestData>();
if (values.Length == 0)
{
    // 2、從資料庫中查詢
    data = testData.Add();
    // 3、存儲到redis中
    List<RedisValue> redisValues = new List<RedisValue>();
    foreach (var item in data)
    {
        string json = JsonConvert.SerializeObject(item);//序列化
        redisValues.Add(json);
    }
    db.SetAdd("testdatas", redisValues.ToArray());
    return data;
}

// 4、序列化,反序列化
foreach (var redisValue in values)
{
    TestData t = JsonConvert.DeserializeObject<TestData>(redisValue);//反序列化
    data.Add(t);
}

4.hash

1.Redis hash數據結構 是一個鍵值對(key-value)集合,它是一個 string 類型的 field 和 value 的映射表。

2.hash數據結構相當於在value中又套了一層key-value型數據。

 //根據HashKey獲取欄位為AccessTime 的值
 string time =db.HashGet("HashKey", "AccessTime");
 if (string.IsNullOrEmpty(time))
 {
      test = data.FirstOrDefault(s => s.Id == 1);
      //設置HashKey為AccessTime欄位的值
      db.HashSet("HashKey", "AccessTime", test.AccessTime);
 }
 // 次數加1
 db.HashIncrement("HashKey", "AccessTime");
5.ZSet (有序集合)

1.它的實現是由Zskiplist+HashTable

2.redis有序集合也是集合類型的一部分,它保留了集合中元素不能重覆的特性,但是不同的是,有序集合給每個元素多設置了一個分數,利用該分數作為排序的依據。

6.List

1.list類型是用來存儲多個有序的字元串的,列表當中的每一個字元看做一個元素.

2.一個列表當中可以存儲有一個或者多個元素,redis的list支持存儲2^32次方-1個元素。

3.redis可以從列表的兩端進行插入(pubsh)和彈出(pop)元素,支持讀取指定範圍的元素集,
或者讀取指定下標的元素等操作。redis列表是一種比較靈活的鏈表數據結構,它可以充當隊列或者棧的角色

4.reids的鏈表結構,可以輕鬆實現阻塞隊列,可以使用左進右出的命令組成來完成隊列的設計。比如:數據的生產者可以通過Lpush命令從左邊插入數據,多個數據消費者,可以使用BRpop命令阻塞的“搶”列表尾部的數據。

7.事務操作

1.Redis中不支持事務回滾

2.在sqlserver中如果開啟事務,修改數據,如果新的會話去同時操作會等待釋放鎖,而Redis中,在開啟事務前首先監聽了Key的版本號,如果在事務期間,新的會話可以修改目標Key,但是會影響當前事務提交不成功。

ITransaction transaction = db.CreateTransaction();
//執行操作
transaction.HashSetAsync("HashKey", "AccessTime", test.AccessTime);
bool commit = transaction.Execute();
if (commit)
{
    Console.WriteLine("提交成功");
}
else
{
    Console.WriteLine("提交失敗");
}

5.Redis持久化
1.RDB 快照

RDB是Redis用來進行持久化的一種方式,是把當前記憶體中的數據集快照寫入磁碟,恢復時是將快照文件直接讀到記憶體里,持久化的RDB文件可以拷貝到不通過的服務,將數據
載入。

  • 1.bgsave :父進程啟動一個子進程,由子進程將記憶體保存在硬碟文件,期間不會影響其他的指令操作.

  • 2.save:將記憶體數據鏡像保存為RDB文件,由於redis是單線程模型期間會阻塞redis服務進程,redis服務不再處理任何指令,直到RDB文件創建完成.

  • 無論是bgsave還是save,其過程如下:

1.生成臨時rdb文件,並寫入數據.

2.完成數據寫入,用臨時文代替代正式rdb文件.

3.刪除原來的db文件

save 900 1 #15分鐘內有一條數據被修改則保存
save 300 10 #300秒有10條修改則保存
save 60 10000 #60秒內有10000條數據修改則保存

# 是否壓縮rdb文件
rdbcompression yes

# rdb文件的名稱
dbfilename redis-6379.rdb

# rdb文件保存目錄
dir ~/redis

自動觸發備份原理

1.Redis有一個周期性操作函數,預設每隔100ms執行一次,它的其中一項工作就是檢查自動觸發Bgsave命令的條件是否成立.

2.計數器記錄了在上一次成功的持久化後,redis進行了多少次寫操作,其值在每次寫操作之後都加1,在成功完成持久化後清零.

RDB的優點

  1. 與AOF方式相比,通過rdb文件恢複數據比較快。
  2. rdb文件非常緊湊,適合於數據備份。
  3. 通過RDB進行數據備,由於使用子進程生成,所以對Redis伺服器性能影響較小。
2.AOF 文件追加

Redis服務每次結束一個事件迴圈之前,都會調用flushAppendOnly函數,其中調用write函數將aof_buf寫入文件,aof文件可以被修改。

1.開啟AOF配置

# 開啟aof機制
appendonly yes

# aof文件名
appendfilename "appendonly.aof"

# 寫入策略,always表示每個寫操作都保存到aof文件中,也可以是everysec或no
appendfsync always

# 預設不重寫aof文件
no-appendfsync-on-rewrite no

# 保存目錄
dir ~/redis

1.在配置文件開啟將appendonly設為yes

2.設置文件路徑dir,可以使用預設在當前目錄下

3.設置追加方式一共有三種,一般選用第二種方式

  • 1.appendfsync always 只要有讀寫,性能最低但是安全性最高
  • 2.appendfsync everysec 1s鐘的周期
  • 3.appendfsync no 等業務不繁忙的時候,這種操作最不可靠 性能最高但是安全性最低

2.AOF文件解讀

1.打開追加的持久化文件

  • 第一個指令*2代表有2個參數,$6第一個參數6個位元組為select, $1代表第二個參數0個位元組
  • 第二個指令*3代表有3個參數,$3第一個參數3個位元組為set,$4第2個參數4個位元組為name,$3第3個參數3個位元組為lll
3.Redis持久化載入

上面我們介紹了Redis支持2種持久化的方式,那我們需要判斷在載入時選擇哪種方式,因為不可能同時選擇2種,其實在Redis載入時會判斷是否開啟了AOF,如果開啟了AOF就會載入AOF文件,如果沒有開啟,那麼就會選擇載入RDB文件。


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

-Advertisement-
Play Games
更多相關文章
  • 在日常開發中,一個優雅的API,必須提供簡單明瞭的響應值,然後根據狀態碼就可以大概知道問題的所在。這裡主要整理一下HTTP狀態碼和自定義狀態碼。 1、HTTP狀態碼 當瀏覽者訪問一個網頁時,瀏覽者的瀏覽器會向網頁所在伺服器發出請求。當瀏覽器接收並顯示網頁前,此網頁所在的伺服器會返回一個包含 HTTP ...
  • 在Word插入分頁符可以在指定段落後插入,也可以在特定文本位置處插入。本文,將以Java代碼來操作以上兩種文檔分頁需求。下麵是詳細方法及步驟。 【程式環境】 在程式中導入jar,如下兩種方法: 方法1:手動引入。將 Free Spire.Doc for Java 下載到本地,解壓,找到lib文件夾下 ...
  • 來源:juejin.cn/post/6844904142960328718 前言 剛剛與同事開了一個分享會,筆者分享了一些了代碼設計模式相關的內容。 以及復盤了一下項目中有些複雜的業務場景,為什麼沒有很好的應用到設計模式。 業務雖然肯定保密的,但是拋開項目,業務層面,縱觀回顧了一下筆者以往的項目, ...
  • 基於docker搭建laravel項目 公司PHP項目是Laravel框架寫的,目前環境需要通過docker來部署一下。網上學習了一下相關知識。整理後做一個筆記。用到定時任務crontab與進程管理supervisor。 主要參考項目: 《docker完美搭建laravel運行環境》參考1 項目時間 ...
  • 今天給大家分享一個數據平均值的吧,好像從來沒有分享過這個內容。 以問題為導向利用Python幫助我們解決在科研中遇到的問題。最近有同學在處理TRMM降水數據的時候,說是要提取每個月的均 值出來。數據格式是tif柵格,目的也是非常明確的:提取多個tif的降水柵格均值出來。 剛纔看了一下TRMM的計劃說 ...
  • 在學習python之前我們可以先學習一些Linux的簡單語法,幫助我們對python語句的編譯和執行有一個更好的理解,同時如果我們以後開發的python程式需要用到伺服器,可以直接用Linux搭建。 接下來我們就可以開始學習python了,python、Java和PHP等語言被稱為高級語言,C語言和 ...
  • 1,打包項目 把項目打成jar 2,配置idea遠程調試 我設置的是本地調試,遠程伺服器設置為遠程的伺服器和埠即可。 3, 伺服器啟動項目 啟動項目: java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 - ...
  • 原文鏈接:https://www.cnblogs.com/ysmc/p/16133351.html 在 Bootstrap 中,柵格相信大家都很熟悉,簡直就是佈局神器啊,Bootstrap Blazor 組件庫當然毫無意外地支持該功能,並且封裝成了組件,使用更加方便,下麵我們一起來看看吧! 首先,這 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...