讀書筆記——《redis入門指南(第2版)》第四章 進階——4.1-5

来源:https://www.cnblogs.com/apeway/archive/2019/04/19/10735893.html
-Advertisement-
Play Games

.1事務 redis中事務是一組命令的集合。 事務同命令一樣都是redis的最小執行單位,Redis保證一個事務中的命令要麼都執行,要麼都不執行。如果redisClient在發送EXEC命令前掉線,則redis會清空事務隊列,事務中的所有命令都不會執行;如果redisClient在發送EXEC命令後 ...


.1事務

         redis中事務是一組命令的集合

事務同命令一樣都是redis的最小執行單位,Redis保證一個事務中的命令要麼都執行,要麼都不執行。如果redisClient在發送EXEC命令前掉線,則redis會清空事務隊列,事務中的所有命令都不會執行;如果redisClient在發送EXEC命令後掉線,所有的命令依然會被執行,因為redis中已經記錄了所有要執行的命令了。

另外,Redis保證一個事務從開始執行到執行結束期間,不會穿插的執行其它的命令或事務

redis事務舉例

 

4.1.2 redis事務的錯誤處理

命令執行出錯的兩種情況介紹:

 
 

        註意:redis事務沒有回滾功能。對於剛纔提到的會導致事務執行失敗的兩種錯誤,語法錯誤完全可以在開發時找出並解決;運行錯誤可以通過做好規劃鍵名規範等來杜絕(這樣就不會出現命令與鍵類型不匹配的情況了)。

4.1.3 Watch與UnWatch

Watch場景

         場景:在事務中,有時候需要先獲得一條命令的返回值,然後再根據這個值執行下一條命令;例如用事務來實現incr函數以防止竟態條件。

         思路:要保證從get獲得鍵值開始到incr函數執行結束為止,該鍵值不會被其它客戶端修改,這樣也可以防止竟態條件。

         WATCH命令:用於監控一個或多個鍵,一旦其中有一個鍵被修改或者刪除,之後的事務就不會執行(EXEC返回空結果nil);監控一直持續到EXEC命令(因為事務中的命令是在EXEC之後執行的,所以在事務中可以修改WATCH監控的鍵值)

 

存在竟態條件的原始偽碼

用事務改造以防止竟態條件

def incr($key)

         $value = GET $key

         if not $value

                  $value = 0

         $value = $value + 1

         set $key, $value

         return $value

def incr($key)

         WATCH $key

         $value = GET $key

         if not $value

                  $value = 0

         $value = $value + 1

         MULTI

                  set $key, $value

         result = EXEC

    // TODO result為nil則遞歸調用incr,否則返回結果

         return result[0]

UnWatch場景

 

4.2 過期時間

expire      key seconds

>> 設置(更新)一個鍵的過期時間,到期後redis會自動刪除。

1表示設置成功;

0表示鍵不存在或設置失敗。

pexpire    key mseconds

毫秒

ttl             key

>> 返回一個鍵還有多久到期(秒);

如果鍵不存在則返回-2;

如果鍵是永久的(即沒有為鍵設置過期時間)則返回-1。

pttl           key

毫秒

persist    key

>> 取消鍵的過期時間設置;

1表示過期時間被成功清除;

否則返回0(鍵不存在或鍵本身就是永久的)

註意:set和getset為鍵賦值也會同時清除鍵的過期時間。

expireAt   key utcSeconds

pexpireAt key utlMSeconds

兩個不常用的命令,設置鍵的過期時刻

 

實踐

1、實現訪問頻率限制之方案1

 

         此方案的問題: 極端情況下,一個ip在第1分鐘的第1秒訪問了1次博客,建了一個鍵並設置60秒到期時間,然後在第1分鐘最後一秒又訪問80次,這樣第一分鐘內總共訪問81次,是可以通過訪問頻率限制的,此時該鍵到期被刪除。然後在第2分鐘第一秒又訪問了1次,會再建同名鍵並設置60秒的到期時間,第二分鐘第2秒又訪問了80次,依然可以通過訪問頻率限制。但是問題是從第1分鐘最後1秒到第2分鐘第2秒這3秒時間內訪問次數是超過了100次的,我們需要粒度更小的控制方案

2、實現訪問頻率限制之方案2(解決方案1的問題)

         如果要精確的保證每個分鐘最多訪問100次,需要記錄下用戶每次訪問的時間。對每個ip,使用一個列表類型鍵來保存他最近100次訪問博客的時間。

 

3、實現緩存

         當伺服器記憶體有限時,如果大量使用緩存鍵且過期時間設置過長就會導致redis占滿記憶體,而如果擔心redis占用記憶體過大就將緩存鍵的過期時間設置過短就會導致緩存命中率過低。實際開發中一般會限制redis的最大記憶體,並讓redis按照一定規則淘汰不需要的鍵。

         具體設置方法為,修改配置文件的maxmemory參數,以限制redis最大可用記憶體大小(位元組),當超過這個限制時,redis會根據maxmemory-policy參數指定的策略來刪除不需要的鍵直到redis占用記憶體小於指定記憶體大小。

 

4.3 排序

         問題:在3.5中我們提到,我們是使用集合類型來存儲一個標簽下所有文章id的,由於集合類型是無序的,所以查看一個標簽下的文章列表時,文章不是按照時間排序的。考慮換成有序集合類型,但是zset支持的集合操作又不如set類型強大,比如說實現獲取同屬於多個標簽下的文章列表,由於zset沒有zInter命令,只有zInterStore命令,用zInterStore來實現zInter的效果就有點麻煩,偽代碼如下。

MULTI

zInterStore tempKey …

zRange tempKey …

del tempKey

EXEC

         至於為何,zset不提供zInter,zUnion命令,解釋如下圖:

 

4.3.2-5 SORT命令

sort key [ALPHA] [DESC] [LIMIT offset count]

1、sort命令可用於對列表類型鍵、集合類型鍵、有序集合類型鍵進行排序,並且可以完成類似連接查詢的功能。

2、在對有序集合類型排序時會忽略元素的分數,只針對元素自身的值進行排序。

3、sort命令預設是對數值元素進行排序的,它會嘗試將所有元素轉換成double來比較,如果不能轉換則報錯,通過加ALPHA參數可以實現按照字典順序排列非數字元素。

4、預設是從小到大排序,指定DESC參數就是從大到小排序。

5、如果需要分頁還可以指定[LIMIT offset count]參數

BY參數

 

         格式為[BY 參考鍵] ,參考鍵可以是字元串類型鍵,或者散列類型鍵的某個欄位(散列鍵名->欄位名)

         如果提供了BY參數,SORT命令將不再按照元素自身值來進行排序,而是對每個元素依次獲取相應參考鍵的值,然後依據這些參考鍵的值來進行排序。對每個元素,通過使用元素的值替換參考鍵中的第一個”*”來決定相應的參考鍵是什麼

         如果幾個元素的對應參考鍵值相同,則SORT命令會再比較元素本身的值來決定元素的順序。當某個元素對應的參考鍵不存在時,會預設參考鍵的值為0。

         若參考鍵名不包含”*”(即常量參考鍵名),則所有要比較的值都是一樣的,SORT命令將不會執行排序。在不需要排序,但需要藉助SORT命令獲得與元素相關聯的數據時,常量參考鍵名很有用。

========================================================================

         例如,可通過“sort TAG:java:articleIds BY article:*->articleTime DESC”來對java標簽下的文章按文章發佈時間進行排序(這裡假設每篇文章都對應了一個散列類型鍵article:articleId用於存儲該文章對象含有的欄位,包括發佈時間欄位articleTime)。

         再例如,可通過“sort TAG:java:articleIds BY article:*: articleTime DESC”來對java標簽下的文章按照文章發佈時間進行排序(這裡假設每篇文章都對應了一個字元串類型鍵article:articleId:articleTime用於存儲該文章的發佈時間);

 

GET參數

         GET參數不影響排序,用於使SORT命令的返回結果不再是元素自身的值,而是GET參數中指定的參數鍵值。

         格式為[GET 參數鍵]GET參數的規則和上面介紹的BY參數一樣。要註意:在一個SORT命令中可以有多個GET參數,但只能由一個BY參數。

========================================================================

         要實現在排序後直接返迴文章標題以及發佈時間列表而不是文章id列表,可通過在之前命令的基礎上加上GET參數,例如”sort TAG:java:articleIds BY article:*->articleTime DESC GET article:*->articletITLE GET article:*->articletIME GET #”,其中”GET #”用於返回元素自身的值。

STORE參數

         預設情況下,SORT命令會直接返回排序結果,如果希望保存排序結果,可以使用STORE參數,格式為[STORE 目標鍵名],保存後的鍵的類型為列表類型,如果目標鍵已存在則會被覆蓋,加上STORE參數後SORT命令的返回值為目標列表類型鍵中元素個數。例如”sort TAG:java:articleIds BY article:*->articleTime DESC STORE resultkey”。

 

4.3.6 SORT性能分析

  

4.4 消息通知

 

         解決方案:定義一個任務隊列,作為生產者的頁面進程負責添加任務到隊列中,而作為消費者的郵件發送進程負責不斷的從隊列中獲取任務進行處理。

任務隊列的好處:

1、  松耦合。生產者和消費者無需知道彼此的實現細節,只需要約定好任務對象的描述格式。

2、  易於擴展。可增加多個分佈在不同伺服器上的消費者來降低單台伺服器的負載。

4.4.2 通過redis列表類型實現任務隊列

思路:定義一個列表類型鍵作為任務隊列,生產者通過LPush命令添加任務到隊列中,消費者不斷的使用Rpop命令從隊列中取出任務來處理。消費者偽碼如下:

 

BRPop list [list2 …] timeout

BLPop ……

         描述:同時檢測多個列表類型鍵,移出並獲取列表的最後一個元素,如果列表中沒有元素則會阻塞列表直到等待超時或發現可彈出元素為止;如果多個鍵都有元素則按照從左到右的順序取第一個鍵中的第一個元素。timeout設置為”0”表示不限制等待時間。

         返回值:假如在指定時間內沒有任何元素被彈出,則返回一個 nil 和等待時長。 反之,返回一個含有兩個元素的列表,第一個元素是被彈出元素所屬的 key ,第二個元素是被彈出元素的值。

4.4.3 優先順序隊列

         需求:博客系統存在兩種任務,即新郵箱請求訂閱時發送確認郵件的任務,以及發佈新文章後發送通知郵件給所有已訂閱郵箱的任務。現在需要實現優先順序隊列,當發送確認郵件任務和發送通知郵件任務同時存在時,優先執行前者。

 

4.4.4 “發佈/訂閱”模式

publish            channel msg

         描述:發佈者給指定頻道發佈消息,發出去的消息不會被持久化,客戶端訂閱一個頻道後只能收到後續發佈到該頻道的消息,之前發送的就收不到了。

         返回值:接收到這條消息的訂閱者數量

subscribe                  channel [channel2 …]

         描述:subscribe用於訂閱者訂閱指定頻道,執行subscribe命令後客戶端會進入訂閱狀態,處於此狀態下的客戶端不能使用除了subscribe、unsubscribe、psubscribe、unsubscribe這4個屬於”發佈/訂閱”模式的命令之外的命令,否則會報錯。

 

unsubscribe   [channel channel2 …]

用於訂閱者取消訂閱指定頻道,如果不指定則會取消訂閱所有頻道。

4.4.5 按照規則訂閱 

PSUBSCRIBE      pattern [pattern ...]

         PSUBSCRIBE命令用於訂閱者訂閱一個或多個符合給定模式的頻道。用psubscribe命令進入訂閱模式後,如果收到消息,返回值會包含4個值;第一個值為”pmessge”,表示這條消息是通過psubscribe命令訂閱頻道而收到的;第二個值表示訂閱時使用的pattern;第三個值表示實際收到消息的頻道名稱,第四個值即為消息內容。

 

 

pUNsubscribe          [pattern pattern2 …]

         PSUBSCRIBE用於退訂指定的規則,如果沒有指定參數,則會退訂所有規則。

 


4.5管道

往返時延:redisClient向redis發送命令耗時 + redis向redisClient返回命令執行結果耗時

         redis底層對管道提供了支持,通過管道可以一次性發送多條命令併在執行完後一次性將結果返回,管道通過減少redisClient與redis的通信次數來實現降低往返時延累計值的目的。當一組命令中所有命令都不依賴於之前命令的執行結果時,就可以將這組命令一起通過管道發出。

 

         

 


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

-Advertisement-
Play Games
更多相關文章
  • 編輯器之神-vim,在Linux下編輯代碼的vim的使用,基本上包括了vim的常用各種命令,vi的三種模式,編輯保存,複製粘貼,查找替換,移動跳轉,撤銷反撤銷等等 ...
  • 刪除原有的yum源: 重新下載阿裡雲的yum源: wget -O 可自行百度 列出yum各軟體包: 清除緩存: 如果沒安裝wget ,yum也還沒配置好,可以直接瀏覽器下載後上傳至/etc/yum.repos.d 並改名為 CentOS-Base.repo ...
  • 1.啟動虛擬機,出現下麵倒計時界面時,按e鍵。進入啟動前編輯。 2.進入如下界面,再按e鍵。 3.進入如下頁面後,選中第二項kernel開頭的項,選中後再按e鍵。 4.進入如下界面後,在最後面輸入空格和s,然後回車。 5.回到如下界面後,按b鍵(boot啟動的意思) 進入如下頁面。 7.在最後的位置 ...
  • 一. Percona XtraBackup 的優點。 (1)無需停止資料庫進行InnoDB熱備; (2)增量備份MySQL; (3)流壓縮傳輸到其它伺服器; (4)線上移動表; (5)能夠比較容易地創建主從同步; (6)備份MySQL時不會增大伺服器負載。 二. Percona XtraBackup ...
  • 背景 從mysql.slow_log 獲取慢查詢日誌很慢,該表是csv表,沒有索引。 想添加索引來加速訪問,而csv引擎不能添加索引(csv引擎存儲是以逗號分割的文本來存儲的),只能改存儲引擎來添加索引了 MySQL 中日誌表slow_log和general_log主要特點 日誌表只能是CSV和MY ...
  • DMLinsert關鍵字作用:往表中插入一條(多條)數據語法1:元祖值式的插入語法1: insert into tablename(column1,column2,...,columnN) values(value1,value2,...,valueN); insert into 表名 (列1 ,列 ...
  • 前言 關於索引,這是一個非常重要的知識點,同樣,在面試的時候也會被經常的問到; 本文描述了索引的結構,介紹了InnoDB的索引方案等知識點,感興趣的可以看一下; 引入 本文參考文章:MySQL的索引 回顧 在上篇文章中我們說到 InnoDB的數據頁結構 ,瞭解到了 數據頁的 7 個組成部分,知道了各 ...
  • 存儲過程的建立和調用 --1.1準備測試需要的資料庫:test,數據表:物料表,採購表if not exists (select * from master.dbo.sysdatabases where name='test')create database testgouse testgoif o ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...