Redis泛泛而談(詳細2W字)

coderxz發表於2021-05-24

本文適合於剛接觸redis的,文章內容比較基礎,大佬請繞道。

02.jpg

一、NoSQL入門和概述

Ⅰ-入門概述

1.為什麼用NoSQL

1)單機MySQL的美好年代

在90年代,一個網站的訪問量一般都不大,用單個資料庫完全可以輕鬆應付。

在那個時候,更多的都是靜態網頁,動態互動型別的網站不多。

image-20210515210238076.png

DAL dal是資料訪問層的英文縮寫,即為資料訪問層(Data Access Layer)

上述架構下,我們來看看資料儲存的瓶頸是什麼?

  1. 資料量的總大小一個機器放不下時
  2. 資料的索引(B+ Tree)一個機器的記憶體放不下時
  3. 訪問量(讀寫混合)一個例項不能承受

如果滿足了上述1or3個,進化…

2)Memcached(快取)+MySQL+垂直拆分

後來,隨著訪問量的上升,幾乎大部分使用MySQL架構的網站在資料庫上都開始出現了效能問題,web程式不再僅僅專注在功能上,同時也在追求效能。程式設計師們開始大量的使用快取技術來緩解資料庫的壓力,優化資料庫的結構和索引。開始比較流行的是通過檔案快取來緩解資料庫壓力,但是當訪問量繼續增大的時候,多臺web機器通過檔案快取不能共享,大量的小檔案快取也帶了了比較高的IO壓力。在這個時候,Memcached就自然的成為一個非常時尚的技術產品。MySQL前面擋了一層Cache

image-20210515210250365.png

3)Mysql主從讀寫分離

由於資料庫的寫入壓力增加,Memcached 只能緩解資料庫的讀取壓力。讀寫集中在一個資料庫上讓資料庫不堪重負,大部分網站開始使用主從複製技術來達到讀寫分離,以提高讀寫效能和讀庫的可擴充套件性。Mysql的master-slave模 式成為這個時候的網站標配了。

image-20210515210412446.png

4)分表分庫+水平拆分+mysql叢集

在Memcached的快取記憶體,MySQL的主從複製, 讀寫分離的基礎之上,這時MySQL主庫的寫壓力開始出現瓶頸,而資料量的持續猛增,由於MyISAM使用表鎖,在高併發下會出現嚴重的鎖問題,大量的高併發MySQL應用開始使用InnoDB引擎代替MyISAM

同時,開始流行使用分表分庫來緩解寫壓力和資料增長的擴充套件問題。這個時候,分表分庫成了一個熱門技術,是面試的熱門問題也是業界討論的熱門技術問題。也就在這個時候,MySQL推出了還不太穩定的表分割槽,這也給技術實力一般的公司帶來了希望。雖然MySQL推出了MySQL Cluster叢集,但效能也不能很好滿足網際網路的要求,只是在高可靠性上提供了非常大的保證。

image-20210515210504351.png

5)MySQL的擴充套件性瓶頸

MySQL資料庫也經常儲存一些大文字欄位,導致資料庫表非常的大,在做資料庫恢復的時候就導致非常的慢,不容易快速恢復資料庫。比如1000萬4KB大小的文字就接近40GB的大小, 如果能把這些資料從MySQL省去,MySQL將變得非常的小。關聯式資料庫很強大,但是它並不能很好的應付所有的應用場景。MySQL的擴充套件性差(需要複雜的技術來實現),大資料下IO壓力大,表結構更改困難,正是當前使用MySOL的開發人員面臨的問題。

6)今天是什麼樣子? ?

image-20210515210521017.png

7)為什麼用NoSQL

今天我們可以通過第三方平臺( 如: Google,Facebook等) 可以很容易的訪問和抓取資料。使用者的個人資訊,社交網路,地理位置,使用者生成的資料和使用者操作日誌已經成倍的增加。我們如果要對這些使用者資料進行挖掘,那SQL資料庫已經不適合這些應用了,NoSQL資料庫的發展也卻能很好的處理這些大的資料。

image-20210515210540803.png

2.是什麼

NoSQL(NoSQL = Not Only SQL),意即“不僅僅是SQL”,泛指非關係型的資料庫。隨著網際網路web2.0網站的興起,傳統的關聯式資料庫在應付web2.0網站,特別是超大規模和高併發的SNS型別的web2.0純動態網站已經顯得力不從心,暴露了很多難以克服的問題,而非關係型的資料庫則由於其本身的特點得到了非常迅速的發展。NoSQL 資料庫的產生就是為了解決大規模資料集合多重資料種類帶來的挑戰,尤其是大資料應用難題,包括超大規模資料的儲存。

(例如谷歌或Facebook每天為他們的使用者收集萬億位元的資料)。這些型別的資料儲存不需要固定的模式,無需多餘操作就可以橫向擴充套件。

3.能幹嘛

易擴充套件

NoSQL資料庫種類繁多,但是一個共同的特點都是去掉關聯式資料庫的關係型特性。資料之間無關係,這樣就非常容易擴充套件。也無形之間,在架構的層面上帶來了可擴充套件的能力。(關係型資料庫如MySQL的欄位就不方便隨時擴充套件)

大資料量高效能

NoSQL資料庫都具有非常高的讀寫效能,尤其在大資料量下,同樣表現優秀。
這得益於它的無關係性,資料庫的結構簡單。

一般MySQL使用Query Cache,每次表的更新Cache就失效,是一種大粒度的Cache,在針對web2.0的互動頻繁的應用,Cache效能不高。

而NoSQL的Cache是記錄級的,是一種細粒度的Cache,所以NoSQL在這個層面上來說就要效能高很多了。

多樣靈活的資料模型

NoSQL無需事先為要儲存的資料建立欄位,隨時可以儲存自定義的資料格式。

而在關聯式資料庫裡,增刪欄位是一件非常麻煩的事情。如果是非常大資料量的表,增加欄位簡直就是一個噩夢。

傳統RDBMS VS NOSQL

RDBMS

  • 高度組織化結構化資料
  • 結構化查詢語言(SQL)
  • 資料和關係都儲存在單獨的表中
  • 資料操縱語言,資料定義語言
  • 嚴格的一致性
  • 基礎事務

NoSQL

  • 代表著不僅僅是SQL
  • 沒有宣告性查詢語言
  • 沒有預定義的模式
  • 鍵-值對儲存,列儲存,文件儲存,圖形資料庫
  • 最終一致性,而非ACID屬性
  • 非結構化和不可預知的資料:
  • CAP定理
  • 高效能,高可用性和可伸縮性

4.有哪些NoSQL

  • Redis
  • Memcached
  • MongDB

5.怎麼玩

  • KV
  • Cache
  • Persistence

Ⅱ-3V + 3高

大資料時代的3V:

  1. 海量Volume
  2. 多樣Variety
  3. 實時Velocity

網際網路需求的3高:

  1. 高併發
  2. 高可括
  3. 高效能

Ⅲ-當下NoSQL應用場景簡介

1.Alibaba中文站商品資訊如何存放

看看阿里巴巴中文網站首頁以女裝/女包包為例

架構發展歷程:

  1. 演變過程

image-20210515212822730.png
2. 第5代

image-20210515213137751.png

  1. 第5代架構使命

image-20210515213209774.png

和我們相關的,多資料來源型別的儲存問題

image-20210515213229321.png

2.商品資訊的儲存方案

下面介紹電商系統中的各種資訊資料需要哪些東西去儲存:

  1. 商品基本資訊

    • 名稱、價格,出廠日期,生產廠商等儲存關係型資料庫

    • 關係型資料庫,mysql/oracle目前淘寶在去O化(也即拿掉Oracle),注意,淘寶內部用的Mysql是裡面的大牛自己改造過的

      為什麼去IOE(在IT建設過程中,去除IBM小型機、Oracle資料庫及EMC儲存裝置) 簡而意之,可不用穿腳鏈跳舞。

  2. 商品描述、詳情、評價資訊(多文字類)

    • 多文字資訊描述類,IO讀寫效能變差
    • 文件資料庫MongDB(文件類使用儲存)
  3. 商品的圖片

    • 商品圖片展現類
    • 分散式的檔案系統中
      • 淘寶自家TFS
      • Google的GFS
      • Hadoop的HDFS
  4. 商品的關鍵字

    • 搜尋引擎,淘寶自家
    • ISearch
  5. 商品的波段性的熱點高頻資訊(如,情人節的巧克力)

    • 記憶體資料庫
    • Tair(美團)、Redis、Memcache
  6. 商品的交易、價格計算、積分累計

    • 外部系統,外部第3方支付介面
    • 支付寶、微信

3.總結大型網際網路應用

(大資料、高併發、多樣資料型別)的難點和解決方案

  • 難點

    • 資料型別多樣性
    • 資料來源多樣性和變化重構(redis,MySQL,mongodb等等太多了,能不能抽象一個類似介面的模式)
    • 資料來源改造而資料服務平臺不需要大面積重構
  • 解決方法

    • EAI

    • UDSL 統一資料平臺服務層

    • 是什麼 :

image-20210515231108325.png

Ⅳ-NoSQL資料模型簡介

以一個電商客戶、訂單、訂購、地址模型來對比關係型資料庫和非關係型資料庫:

  • 傳統關係型資料庫如何設計

    • ER圖(1:1、1:N、N:N)主外來鍵等

image-20210515232259538.png

  • NOSQL如何設計

    BSON ()是一種類json的一種二進位制形式的儲存格式,簡稱Binary JSON,它和JSON一樣,支援內嵌的文件物件和陣列物件

    {
     "customer":{
       "id":1136,
       "name":"Z3",
       "billingAddress":[{"city":"beijing"}],
       "orders":[
        {
          "id":17,
          "customerId":1136,
          "orderItems":[{"productId":27,"price":77.5,"productName":"thinking in java"}],
          "shippingAddress":[{"city":"beijing"}]
          "orderPayment":[{"ccinfo":"111-222-333","txnid":"asdfadcd334","billingAddress":{"city":"beijing"}}],
          }
        ]
      }
    }
    
  • 兩者對比,問題和難點

    • 問題和難點
      • 為什麼用聚合模型(NoSQL)來處理
        • 高併發的操作是不太建議用關聯查詢的,網際網路公司用冗餘資料來避免關聯查詢
        • 分散式事務是支援不了太多的併發的

聚合模型

  • KV
  • BSON
  • 列族

顧名思義,是按列儲存資料的。最大的特點是方便儲存結構化和半結構化資料,方便做資料壓縮,對針對某一 列或者某幾列的查詢有非常大的IO優勢。

image-20210515231729220.png

  • 圖形

image-20210515231745812.png

Ⅴ-NoSQL資料庫的四大分類

  • KV
    • 新浪:BerkeleyDB + Redis
    • 美團:Redis + tair
    • 阿里、百度:memcache + Redis
  • 文件型資料庫(bson格式比較多)
    • CouchDB
    • MongoDB
      • MongoDB是一個基於分散式檔案儲存的資料庫。由C++語言編寫。旨在為WEB應用提供可擴充套件的高效能資料儲存解決方案。
      • MongoDB是一個介於關聯式資料庫和非關聯式資料庫之間的產品,是非關聯式資料庫當中功能最豐富,最像關聯式資料庫的。
  • 列儲存資料庫
    • Cassandra、HBase
    • 分散式檔案系統
  • 圖關聯式資料庫
    • 它不是放圖形的、放的是關係比如:朋友圈社交網路、廣告推薦系統
    • 社交網路、推薦系統。專注於構建關係圖譜
    • Neo4j、InfoGrid
  • NoSQL的四個維度四者對比

image-20210515234625272.png

Ⅵ-分散式資料庫CAP原理

1.傳統的ACID分別是什麼

  • A (Atomicity) 原子性
  • C (Consistency) 一致性
  • I (Isolation) 獨立性
  • D (Durability) 永續性

關係型資料庫遵循ACID規則,事務在英文中是transaction,和現實世界中的交易很類似,它有如下四個特性:

1、A (Atomicity) 原子性 原子性很容易理解,也就是說事務裡的所有操作要麼全部做完,要麼都不做,事務成功的條件是事務裡的所有操作都成功,只要有一個操作失敗,整個事務就失敗,需要回滾。比如銀行轉賬,從A賬戶轉100元至B賬戶,分為兩個步驟:1)從A賬戶取100元;2)存入100元至B賬戶。這兩步要麼一起完成,要麼一起不完成,如果只完成第一步,第二步失敗,錢會莫名其妙少了100元。

2、C (Consistency) 一致性 一致性也比較容易理解,也就是說資料庫要一直處於一致的狀態,事務的執行不會改變資料庫原本的一致性約束。

3、I (Isolation) 獨立性 所謂的獨立性是指併發的事務之間不會互相影響,如果一個事務要訪問的資料正在被另外一個事務修改,只要另外一個事務未提交,它所訪問的資料就不受未提交事務的影響。比如現有有個交易是從A賬戶轉100元至B賬戶,在這個交易還未完成的情況下,如果此時B查詢自己的賬戶,是看不到新增加的100元的

4、D (Durability) 永續性 永續性是指一旦事務提交後,它所做的修改將會永久的儲存在資料庫上,即使出現當機也不會丟失。

2.CAP

  • C:Consistency(強一致性)
  • A:Availability(可用性)
  • P:Partition tolerance(分割槽容錯性)

CAP理論就是說在分散式儲存系統中,最多隻能實現上面的兩點。

而由於當前的網路硬體肯定會出現延遲丟包等問題,所以分割槽容錯性是我們必須需要實現的。所以我們只能在一致性可用性之間進行權衡,沒有NoSQL系統能同時保證這三點。

C:強一致性 A:高可用性 P:分散式容忍性

  • CA 傳統Oracle資料庫
  • AP 大多數網站架構的選擇
  • CP Redis、Mongodb

注意:分散式架構的時候必須做出取捨。

一致性和可用性之間取一個平衡。多餘大多數web應用,其實並不需要強一致性。因此犧牲C換取P,這是目前分散式資料庫產品的方向。

一致性C與可用性A的決擇

對於web2.0網站來說,關聯式資料庫的很多主要特性卻往往無用武之地

資料庫事務一致性需求

很多web實時系統並不要求嚴格的資料庫事務,對讀一致性的要求很低, 有些場合對寫一致性要求並不高。允許實現最終一致性。

資料庫的寫實時性和讀實時性需求

對關聯式資料庫來說,插入一條資料之後立刻查詢,是肯定可以讀出來這條資料的,但是對於很多web應用來說,並不要求這麼高的實時性,比方說在微博發一條訊息之後,過幾秒乃至十幾秒之後,我的訂閱者才看到這條動態是完全可以接受的。

對複雜的SQL查詢,特別是多表關聯查詢的需求

任何大資料量的web系統,都非常忌諱多個大表的關聯查詢,以及複雜的資料分析型別的報表查詢,特別是SNS型別的網站,從需求以及產品設計角 度,就避免了這種情況的產生。往往更多的只是單表的主鍵查詢,以及單表的簡單條件分頁查詢,SQL的功能被極大的弱化了。

3.經典CAP圖

CAP理論的核心是:一個分散式系統不可能同時很好的滿足一致性,可用性和分割槽容錯性這三個需求,最多隻能同時較好的滿足兩個。

因此,根據 CAP 原理將 NoSQL 資料庫分成了滿足 CA 原則、滿足 CP 原則和滿足 AP 原則三 大類:

  • CA - 單點叢集,滿足一致性,可用性的系統,通常在可擴充套件性上不太強大。
  • CP - 滿足一致性,分割槽容忍必的系統,通常效能不是特別高。
  • AP - 滿足可用性,分割槽容忍性的系統,通常可能對一致性要求低一些。

image-20210516093951068.png

4.BASE

BASE就是為了解決關聯式資料庫強一致性引起的問題而引起的可用性降低而提出的解決方案。

BASE其實是下面三個術語的縮寫:

  • 基本可用(Basically Available)
  • 軟狀態(Soft state)
  • 最終一致(Eventually consistent)

它的思想是通過讓系統放鬆對某一時刻資料一致性的要求來換取系統整體伸縮性和效能上改觀。為什麼這麼說呢,緣由就在於大型系統往往由於地域分佈和極高效能的要求,不可能採用分散式事務來完成這些指標,要想獲得這些指標,我們必須採用另外一種方式來完成,這裡BASE就是解決這個問題的辦法

5.分散式+叢集簡介

分散式系統(distributed system)

由多臺計算機和通訊的軟體元件通過計算機網路連線(本地網路或廣域網)組成。分散式系統是建立在網路之上的軟體系統。正是因為軟體的特性,所以分散式系統具有高度的內聚性和透明性。因此,網路和分散式系統之間的區別更多的在於高層軟體(特別是作業系統),而不是硬體。分散式系統可以應用在在不同的平臺上如:PC、工作站、區域網和廣域網上等。

簡單來講:

  1. 分散式:不同的多臺伺服器上面部署不同的服務模組(工程),他們之間通過RPC/RMI之間通訊和呼叫,對外提供服務和組內協作。
  2. 叢集:不同的多臺伺服器上面部署相同的服務模組,通過分散式排程軟體進行統一的排程,對外提供服務和訪問。

二、Redis入門介紹

Ⅰ-入門概述

是什麼

Redis:REmote DIctionary Server(遠端字典伺服器)是完全開源免費的,用C語言編寫的,遵守BSD協議,是一個高效能的(key/value)分散式記憶體資料庫基於記憶體執行 並支援持久化的NoSQL資料庫,是當前最熱門的NoSql資料庫之一,也被人們稱為資料結構伺服器。

Redis 與其他 key - value 快取產品有以下三個特點:

  • Redis支援資料的持久化,可以將記憶體中的資料保持在磁碟中,重啟的時候可以再次載入進行使用
  • Redis不僅僅支援簡單的key-value型別的資料,同時還提供list,set,zset,hash等資料結構的儲存
  • Redis支援資料的備份,即master-slave模式的資料備份

能幹嘛

  • 記憶體儲存和持久化:redis支援非同步將記憶體中的資料寫到硬碟上,同時不影響繼續服務
  • 取最新N個資料的操作,如:可以將最新的10條評論的ID放在Redis的List集合裡面
  • 模擬類似於HttpSession這種需要設定過期時間的功能
  • 釋出、訂閱訊息系統
  • 定時器、計數器

去哪下

怎麼玩

  • 資料型別、基本操作和配置
  • 持久化和複製,RDB/AOF
  • 事務的控制
  • 複製(主從關係)

Ⅱ-Redis的安裝

略(見伺服器配置)

Ⅲ-HelloWorld

在前面make install後指定安裝目錄後:

image-20210516112533092.png

# -p是指定埠  -a是輸入密碼 (前面在redis.conf中設定了密碼,如果未設定可省略)
[root@localhost bin]# redis-cli -p 6379 -a coderxz
-bash: redis-cli: 未找到命令
[root@localhost bin]# ./redis-cli -p 6379 -a coderxz
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set k1 hello
OK
127.0.0.1:6379> get k1
"hello"
127.0.0.1:6379>

Ⅳ-啟動後雜項基礎知識

  • redis-benchmark 可測試redis在機器執行的效能
[root@localhost bin]# ./redis-benchmark
====== PING_INLINE ======
  100000 requests completed in 0.59 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.96% <= 4 milliseconds
99.99% <= 5 milliseconds
100.00% <= 5 milliseconds
168634.06 requests per second

====== PING_BULK ======
  100000 requests completed in 0.63 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.85% <= 1 milliseconds
99.92% <= 2 milliseconds
99.95% <= 4 milliseconds
99.98% <= 5 milliseconds
100.00% <= 5 milliseconds
158227.84 requests per second #每秒鐘15W

====== SET ======
  100000 requests completed in 0.57 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
175746.92 requests per second

====== GET ======
  100000 requests completed in 0.57 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
175131.36 requests per second
。。。。。。略
  • 單程式

    • 單程式模型來處理客戶端的請求。對讀寫等事件的響應 是通過對epoll函式的包裝來做到的。Redis的實際處理速度完全依靠主程式的執行效率
    • Epoll是Linux核心為處理大批量檔案描述符而作了改進的epoll,是Linux下多路複用IO介面select/poll的增強版本, 它能顯著提高程式在大量併發連線中只有少量活躍的情況下的系統CPU利用率。
  • 預設16個資料庫,類似陣列下表從零開始,初始預設使用零號庫,可在配置檔案配置

    設定資料庫的數量,預設資料庫為0,可以使用SELECT < dbid >命令在連線上指定資料庫iddatabases 16

    127.0.0.1:6379> select 2
    OK
    127.0.0.1:6379[2]>
    
  • select 命令切換資料庫

  • dbsize 檢視當前資料庫的key的數量 keys *檢視所有的key

  • flushdb:清空當前庫

  • flushall;通殺全部庫

  • 統一密碼管理,16個庫都是同樣密碼,要麼都OK要麼一個也連線不上

  • Redis索引都是從零開始

  • 為什麼預設埠是6379 (有個竅門,Redis埠號6379是電話鍵盤上的MERZ)

三、Redis常用資料型別

Ⅰ-Redis的五大資料型別

  • String(字串)
    • string是redis最基本的型別,你可以理解成與Memcached一模一樣的型別,一個key對應一個value。
    • string型別是二進位制安全的。意思是redis的string可以包含任何資料。比如jpg圖片或者序列化的物件 。
    • string型別是Redis最基本的資料型別,一個redis中字串value最多可以是512M
  • Hash(雜湊,類似java裡的Map)
    • Redis hash 是一個鍵值對集合。
    • Redis hash是一個string型別的field和value的對映表,hash特別適合用於儲存物件。
    • 類似Java裡面的Map<String,Object>
  • List(列表)
    • Redis 列表是簡單的字串列表,按照插入順序排序。你可以新增一個元素導列表的頭部(左邊)或者尾部(右邊)。
    • 它的底層實際是個連結串列
  • Set(集合)
    • Redis的Set是string型別的無序集合。它是通過HashTable實現實現的
  • Zset(sorted set:有序集合)
    • Redis zset 和 set 一樣也是string型別元素的集合,且不允許重複的成員。
    • 不同的是每個元素都會關聯一個double型別的分數。
    • redis正是通過分數來為集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。
  • 哪裡去獲得redis常見資料型別操作命令

Ⅱ-Key關鍵字

常用的

命令 描述
DEL key 該命令用於在 key 存在時刪除 key。
DUMP key 序列化給定 key ,並返回被序列化的值。
EXISTS key 檢查給定 key 是否存在。
EXPIRE key seconds 為給定 key 設定過期時間,以秒計。
EXPIREAT key timestamp EXPIREAT 的作用和 EXPIRE 類似,都用於為 key 設定過期時間。 不同在於 EXPIREAT 命令接受的時間引數是 UNIX 時間戳(unix timestamp)。
PEXPIRE key milliseconds 設定 key 的過期時間以毫秒計。
PEXPIREAT key milliseconds-timestamp 設定 key 過期時間的時間戳(unix timestamp) 以毫秒計
KEYS pattern 查詢所有符合給定模式( pattern)的 key 。
MOVE key db 將當前資料庫的 key 移動到給定的資料庫 db 當中。
PERSIST key 移除 key 的過期時間,key 將持久保持。
PTTL key 以毫秒為單位返回 key 的剩餘的過期時間。
TTL key 以秒為單位,返回給定 key 的剩餘生存時間(TTL, time to live)。
RANDOMKEY 從當前資料庫中隨機返回一個 key 。
RENAME key newkey 修改 key 的名稱
RENAMENX key newkey 僅當 newkey 不存在時,將 key 改名為 newkey 。
SCAN cursor [MATCH pattern] [COUNT count] 迭代資料庫中的資料庫鍵。
TYPE key 返回 key 所儲存的值的型別。

案例

  • keys *
  • exists key的名字,判斷某個key是否存在
  • move key db —>當前庫就沒有了,被移除了
  • expire key 秒鐘:為給定的key設定過期時間
  • ttl key 檢視還有多少秒過期,-1表示永不過期,-2表示已過期
  • type key 檢視你的key是什麼型別

Ⅲ-String

單值單value

常用

命令 描述
SET key value 設定指定 key 的值
GET key 獲取指定 key 的值。
GETRANGE key start end 返回 key 中字串值的子字元
GETSET key value 將給定 key 的值設為 value ,並返回 key 的舊值(old value)。
GETBIT key offset 對 key 所儲存的字串值,獲取指定偏移量上的位(bit)。
MGET key1 [key2…] 獲取所有(一個或多個)給定 key 的值。
SETBIT key offset value 對 key 所儲存的字串值,設定或清除指定偏移量上的位(bit)。
SETEX key seconds value 將值 value 關聯到 key ,並將 key 的過期時間設為 seconds (以秒為單位)。
SETNX key value 只有在 key 不存在時設定 key 的值。
SETRANGE key offset value 用 value 引數覆寫給定 key 所儲存的字串值,從偏移量 offset 開始。
STRLEN key 返回 key 所儲存的字串值的長度。
MSET key value [key value …] 同時設定一個或多個 key-value 對。
MSETNX key value [key value …] 同時設定一個或多個 key-value 對,當且僅當所有給定 key 都不存在。
PSETEX key milliseconds value 這個命令和 SETEX 命令相似,但它以毫秒為單位設定 key 的生存時間,而不是像 SETEX 命令那樣,以秒為單位。
INCR key 將 key 中儲存的數字值增一。
INCRBY key increment 將 key 所儲存的值加上給定的增量值(increment) 。
INCRBYFLOAT key increment 將 key 所儲存的值加上給定的浮點增量值(increment) 。
DECR key 將 key 中儲存的數字值減一。
DECRBY key decrement key 所儲存的值減去給定的減量值(decrement) 。
APPEND key value 如果 key 已經存在並且是一個字串, APPEND 命令將指定的 value 追加到該 key 原來值(value)的末尾。

案例

  • set/get/del/append/strlen(末尾新增、求長度)
  • Incr/decr/incrby/decrby(+1、-1、+n、-n),一定要是數字才能進行加減
  • getrange/setrange (返回/設定從start-end之間的內容 注意下表從0開始計數
  • setex(set with expire)( 建立keyValue的時候並設定過期時間,動態設定
  • setnx(set if not exist)( 只有在 key 不存在時設定 key 的值。
  • mset/mget/msetnx( 同時設定/獲取一個或多個 key-value 對。
  • getset(先get再set)

Ⅳ-List

單值多value

常用

命令 描述
BLPOP key1 [key2 ] timeout 移出並獲取列表的第一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。
BRPOP key1 [key2 ] timeout 移出並獲取列表的最後一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。
BRPOPLPUSH source destination timeout 從列表中彈出一個值,將彈出的元素插入到另外一個列表中並返回它; 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。
LINDEX key index 通過索引獲取列表中的元素
LINSERT key BEFORE/AFTER pivot value 在列表的元素前或者後插入元素
LLEN key 獲取列表長度
LPOP key 移出並獲取列表的第一個元素
LPUSH key value1 [value2] 將一個或多個值插入到列表頭部
LPUSHX key value 將一個值插入到已存在的列表頭部
LRANGE key start stop 獲取列表指定範圍內的元素
LREM key count value 移除列表元素
LSET key index value 通過索引設定列表元素的值
LTRIM key start stop 對一個列表進行修剪(trim),就是說,讓列表只保留指定區間內的元素,不在指定區間之內的元素都將被刪除。
RPOP key 移除列表的最後一個元素,返回值為移除的元素。
RPOPLPUSH source destination 移除列表的最後一個元素,並將該元素新增到另一個列表並返回
RPUSH key value1 [value2] 在列表中新增一個或多個值
RPUSHX key value 為已存在的列表新增值

案例

  • lpush/rpush/lrange (lrange key 0 -1 表示獲取所有的元素)
# 左邊的LPUSH 正著進反著出;右邊RPUSH怎麼進就怎麼出
127.0.0.1:6379> LPUSH list01 1 2 3 4 5
(integer) 5
127.0.0.1:6379> keys *
1) "k3"
2) "list01"
3) "k2"
4) "k1"
127.0.0.1:6379> LRANGE list01 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> RPUSH list02 1 2 3 4 5
(integer) 5
127.0.0.1:6379> LRANGE list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
  • lpop/rpop
  • lindex,按照索引下標獲得元素(從上到下)
127.0.0.1:6379> LPOP list01
"5"
127.0.0.1:6379> LPOP list02
"1"
127.0.0.1:6379> lindex list01 0 #上面list01中最上面的5已經出了
"4"
127.0.0.1:6379> lindex list02 0 #上面list02中最上面的1已經出了
"2"
127.0.0.1:6379>
  • llen
  • lrem key 刪N個value (rem->remove 有可能有多個key的value是相同的,刪除N個值為value)

image-20210516193104236.png

  • ltrim key 開始index 結束index,擷取指定範圍的值後再賦值給key

image-20210517001950585.png

  • rpoplpush 源列表 目的列表

image-20210517002240191.png

  • lset key index value 修改指定下班下的值

image-20210517002317819.png

  • linsert key before/after 值1 值2

image-20210517002502385.png

效能總結:

  • 它是一個字串連結串列,left、right都可以插入新增;
  • 如果鍵不存在,建立新的連結串列;
  • 如果鍵已存在,新增內容;
  • 如果值全移除,對應的鍵也就消失了。
  • 連結串列的操作無論是頭和尾效率都極高,但假如是對中間元素進行操作,效率就很慘淡了。

Ⅴ-Set

單值多value

常用

命令 描述
SADD key member1 [member2] 向集合新增一個或多個成員
SCARD key 獲取集合的成員數
SDIFF key1 [key2] 返回給定所有集合的差集
SDIFFSTORE destination key1 [key2] 返回給定所有集合的差集並儲存在 destination 中
SINTER key1 [key2] 返回給定所有集合的交集
SINTERSTORE destination key1 [key2] 返回給定所有集合的交集並儲存在 destination 中
SISMEMBER key member 判斷 member 元素是否是集合 key 的成員
SMEMBERS key 返回集合中的所有成員
SMOVE source destination member 將 member 元素從 source 集合移動到 destination 集合
SPOP key 移除並返回集合中的一個隨機元素
SRANDMEMBER key [count] 返回集合中一個或多個隨機數
SREM key member1 [member2] 移除集合中一個或多個成員
SUNION key1 [key2] 返回所有給定集合的並集
SUNIONSTORE destination key1 [key2] 所有給定集合的並集儲存在 destination 集合中
SSCAN key cursor [MATCH pattern] [COUNT count] 迭代集合中的元素

案例

  • sadd/smembers/sismember

image-20210517002822475.png

  • scard,獲取集合裡面的元素個數

  • srem key value 刪除集合中元素

image-20210517003007244.png

  • srandmember key 某個整數(隨機出幾個數)

image-20210517003129507.png

  • spop key 隨機出棧

image-20210517003258172.png

  • smove key1 key2 在key1裡某個值 作用是將key1裡的某個值賦給key2

image-20210517003556939.png

  • 數學集合類
    • 差集:sdiff
    • 交集:sinter
    • 並集:sunion
127.0.0.1:6379> SMEMBERS set01
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> SMEMBERS set02
1) "2"
2) "1"
3) "c"
4) "e"
5) "a"
6) "b"
7) "d"
8) "f"
9) "5"
127.0.0.1:6379> sdiff set01 set02
1) "3"
2) "4"
127.0.0.1:6379> SINTER set01 set02
1) "1"
2) "2"
3) "5"
127.0.0.1:6379> SUNION set01 set02
 1) "1"
 2) "3"
 3) "a"
 4) "f"
 5) "d"
 6) "b"
 7) "2"
 8) "c"
 9) "e"
10) "4"
11) "5"
127.0.0.1:6379>

Ⅵ-Hash

KV模式不變,但V是一個鍵值對 (類比於key-(HashMap)Value)

常用

命令 描述
HDEL key field1 [field2] 刪除一個或多個雜湊表欄位
HEXISTS key field 檢視雜湊表 key 中,指定的欄位是否存在。
HGET key field 獲取儲存在雜湊表中指定欄位的值。
HGETALL key 獲取在雜湊表中指定 key 的所有欄位和值
HINCRBY key field increment 為雜湊表 key 中的指定欄位的整數值加上增量 increment 。
HINCRBYFLOAT key field increment 為雜湊表 key 中的指定欄位的浮點數值加上增量 increment 。
HKEYS key 獲取所有雜湊表中的欄位
HLEN key 獲取雜湊表中欄位的數量
HMGET key field1 [field2] 獲取所有給定欄位的值
HMSET key field1 value1 [field2 value2 ] 同時將多個 field-value (域-值)對設定到雜湊表 key 中。
HSET key field value 將雜湊表 key 中的欄位 field 的值設為 value 。
HSETNX key field value 只有在欄位 field 不存在時,設定雜湊表欄位的值。
HVALS key 獲取雜湊表中所有值。
HSCAN key cursor [MATCH pattern] [COUNT count] 迭代雜湊表中的鍵值對。

案例

  • hset/hget/hmset/hmget/hgetall/hdel幾乎天天用的
127.0.0.1:6379> hset user id 11  #這裡key是user value是 id 11
(integer) 1
127.0.0.1:6379> hget user id
"11"
127.0.0.1:6379> hset user name z3
(integer) 1
127.0.0.1:6379> hget user name
"z3"
127.0.0.1:6379> hmset customer id 11 name lisi age 26 #一次性新增多個
OK
127.0.0.1:6379> hmget customer id name age #一次性獲取多個,被獲取之後的資料依舊存在
1) "11"
2) "lisi"
3) "26"
127.0.0.1:6379> HGETALL customer  #獲取所有的value(這裡的value就已經包括了key-value)
1) "id"
2) "11"
3) "name"
4) "lisi"
5) "age"
6) "26"
  • hlen
  • hexists key 在key裡面的某個值的key
127.0.0.1:6379> hdel user name
(integer) 1
127.0.0.1:6379> hlen user
(integer) 1
127.0.0.1:6379> hlen customer
(integer) 3
127.0.0.1:6379> HEXISTS user id
(integer) 1
127.0.0.1:6379> HEXISTS user email
  • hkeys/hvals
127.0.0.1:6379> hkeys customer
1) "id"
2) "name"
3) "age"
127.0.0.1:6379> hvals customer
1) "11"
2) "lisi"
3) "26"
  • hincrby/hincrbyfloat
  • hsetnx
127.0.0.1:6379> HINCRBY customer age 3
(integer) 29
127.0.0.1:6379> HINCRBY customer age 3 #新增 key對應的key-value中的value的值
(integer) 32
127.0.0.1:6379> hset customer score 91.5
(integer) 1
127.0.0.1:6379> HINCRBYFLOAT customer score 0.6 #新增 key對應的key-value中的value的值
"92.1"
127.0.0.1:6379> HSETNX customer age 22
(integer) 0
127.0.0.1:6379> HSETNX customer email abc@qq.com
(integer) 1

Ⅶ-ZSet

在set基礎上,加一個score值。 之前set是k1 v1 v2 v3, 現在zset是k1 score1 v1 score2 v2 (score1 v1就是一個鍵值對

常用

命令 描述
ZADD key score1 member1 [score2 member2] 向有序集合新增一個或多個成員,或者更新已存在成員的分數
ZCARD key 獲取有序集合的成員數
ZCOUNT key min max 計算在有序集合中指定區間分數的成員數
ZINCRBY key increment member 有序集合中對指定成員的分數加上增量 increment
ZINTERSTORE destination numkeys key [key …] 計算給定的一個或多個有序集的交集並將結果集儲存在新的有序集合 key 中
ZLEXCOUNT key min max 在有序集合中計算指定字典區間內成員數量
ZRANGE key start stop [WITHSCORES] 通過索引區間返回有序集合指定區間內的成員
ZRANGEBYLEX key min max [LIMIT offset count] 通過字典區間返回有序集合的成員
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 通過分數返回有序集合指定區間內的成員
ZRANK key member 返回有序集合中指定成員的索引
ZREM key member [member …] 移除有序集合中的一個或多個成員
ZREMRANGEBYLEX key min max 移除有序集合中給定的字典區間的所有成員
ZREMRANGEBYRANK key start stop 移除有序集合中給定的排名區間的所有成員
ZREMRANGEBYSCORE key min max 移除有序集合中給定的分數區間的所有成員
ZREVRANGE key start stop [WITHSCORES] 返回有序集中指定區間內的成員,通過索引,分數從高到低
ZREVRANGEBYSCORE key max min [WITHSCORES] 返回有序集中指定分數區間內的成員,分數從高到低排序
ZREVRANK key member 返回有序集合中指定成員的排名,有序整合員按分數值遞減(從大到小)排序
ZSCORE key member 返回有序集中,成員的分數值
ZUNIONSTORE destination numkeys key [key …] 計算給定的一個或多個有序集的並集,並儲存在新的 key 中
ZSCAN key cursor [MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成員和元素分值)

案例

  • zadd/zrange
    • Withscores

image-20210517092201569.png

  • zrangebyscore key 開始score 結束score
    • withscores
    • ( 不包含
    • Limit 作用是返回限制
      • limit 開始下標步 多少步

image-20210517092538009.png

  • zrem key 某score下對應的value值,作用是刪除元素
  • zcard/zcount key score區間/zrank key values值,作用是獲得下標值/zscore key 對應值,獲得分數
  • zrevrank key values值,作用是逆序獲得下標值
  • zrevrange
  • zrevrangebyscore key 結束score 開始score
127.0.0.1:6379> ZCARD zset01  #統計個數
(integer) 4
127.0.0.1:6379> zcount zset01 60 80 #統計[60,80]之間的個數
(integer) 3
127.0.0.1:6379> ZRANK zset01 v4 #獲取對應的下標
(integer) 3
127.0.0.1:6379> zscore zset01 v4 #返回分數
"90"
127.0.0.1:6379> ZREVRANK zset01 v4 #作用是逆序獲得下標值
(integer) 0
127.0.0.1:6379> ZREVRANGE zset01 0 -1#分數從高到低
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> ZRANGE zset01 0 -1 #分數從低到高
1) "v1"
2) "v2"
3) "v3"
4) "v4"
127.0.0.1:6379> ZREVRANGEBYSCORE zset01 90 60 #分數從高到低的擷取區間[90,60]
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> zadd zset01 60 coderxz
(integer) 1
127.0.0.1:6379> ZRANGE zset01 0 -1 withscores #存在score相同的好像也可以
 1) "coderxz"
 2) "60"
 3) "v1"
 4) "60"
 5) "v2"
 6) "70"
 7) "v3"
 8) "80"
 9) "v4"
10) "90"

四、配置檔案介紹

Redis 的配置檔案位於 Redis 安裝目錄下,檔名為 redis.conf(Windows 名為 redis.windows.conf)。

image-20210517094132781.png

你可以通過 CONFIG 命令檢視或設定配置項。

語法

Redis CONFIG 命令格式如下:

redis 127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME

例項

redis 127.0.0.1:6379> CONFIG GET loglevel1) "loglevel"2) "notice"

引數說明

redis.conf 配置項說明如下:

--------------redis.conf中GENERAL的部分配置:--------------------

  • daemonize no

Redis 預設不是以守護程式的方式執行,可以通過該配置項修改,使用 yes 啟用守護程式(Windows 不支援守護執行緒的配置為 no )

  • pidfile /var/run/redis.pid

當 Redis 以守護程式方式執行時,Redis 預設會把 pid 寫入 /var/run/redis.pid 檔案,可以通過 pidfile 指定

  • port 6379

指定 Redis 監聽埠,預設埠為 6379,作者在自己的一篇博文中解釋了為什麼選用 6379 作為預設埠,因為 6379 在手機按鍵上 MERZ 對應的號碼,而 MERZ 取自義大利歌女 Alessia Merz 的名字

  • bind 127.0.0.1

繫結的主機地址

  • timeout 300

當客戶端閒置多長秒後關閉連線,如果指定為 0 ,表示關閉該功能

  • loglevel notice

指定日誌記錄級別,Redis 總共支援四個級別:debug、verbose、notice、warning,預設為 notice

  • logfile stdout

日誌記錄方式,預設為標準輸出,如果配置 Redis 為守護程式方式執行,而這裡又配置為日誌記錄方式為標準輸出,則日誌將會傳送給 /dev/null

  • databases 16

設定資料庫的數量,預設資料庫為0,可以使用SELECT 命令在連線上指定資料庫id

-------------redis.conf的SNAPSHOTTING快照配置------------------------

  • save < seconds> < changes>

Redis 預設配置檔案中提供了三個條件(以下三者出其一就會觸發):

save 900 1 900秒以內有1次修改

save 300 10

save 60 10000

分別表示 900 秒(15 分鐘)內有 1 個更改,300 秒(5 分鐘)內有 10 個更改以及 60 秒內有 10000 個更改。

指定在多長時間內,有多少次更新操作,就將資料同步到資料檔案,可以多個條件配合

  • rdbcompression yes

指定儲存至本地資料庫時是否壓縮資料,預設為 yes,Redis 採用 LZF 壓縮,如果為了節省 CPU 時間,可以關閉該選項,但會導致資料庫檔案變的巨大

  • dbfilename dump.rdb

指定本地資料庫檔名,預設值為 dump.rdb

  • dir ./

指定本地資料庫存放目錄

  • slaveof < masterip> < masterport>

設定當本機為 slave 服務時,設定 master 服務的 IP 地址及埠,在 Redis 啟動時,它會自動從 master 進行資料同步

  • masterauth < master-password>

當 master 服務設定了密碼保護時,slav 服務連線 master 的密碼

-----------------redis.conf的SECURITY部分配置------------------------

  • requirepass foobared

設定 Redis 連線密碼,如果配置了連線密碼,客戶端在連線 Redis 時需要通過 AUTH 命令提供密碼,預設關閉

image-20210517105959134.png

-----------------redis.conf中LIMITS的部分配置------------------

  • maxclients 128

設定同一時間最大客戶端連線數,預設無限制,Redis 可以同時開啟的客戶端連線數為 Redis 程式可以開啟的最大檔案描述符數,如果設定 maxclients 0,表示不作限制。當客戶端連線數到達限制時,Redis 會關閉新的連線並向客戶端返回 max number of clients reached 錯誤資訊

  • maxmemory < bytes>

指定 Redis 最大記憶體限制,Redis 在啟動時會把資料載入到記憶體中,達到最大記憶體後,Redis 會先嚐試清除已到期或即將到期的 Key,當此方法處理 後,仍然到達最大記憶體設定,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis 新的 vm 機制,會把 Key 存放記憶體,Value 會存放在 swap 區

  • Maxmemory-policy noeviction(預設) 快取清除策略,生產環境上肯定得改

(1)volatile-lru:使用LRU演算法移除key,只對設定了過期時間的鍵 (最近最少使用)
(2)allkeys-lru:使用LRU演算法移除key
(3)volatile-random:在過期集合中移除隨機的key,只對設定了過期時間的鍵
(4)allkeys-random:移除隨機的key
(5)volatile-ttl:移除那些TTL值最小的key,即那些最近要過期的key
(6)noeviction:不進行移除。針對寫操作,只是返回錯誤資訊

--------------redis.conf中 APPEND ONLY MODE的部分配置-----------

  • appendonly no

AOF啟動,指定是否在每次更新操作後進行日誌記錄,Redis 在預設情況下是非同步的把資料寫入磁碟,如果不開啟,可能會在斷電時導致一段時間內的資料丟失。因為 redis 本身同步資料檔案是按上面 save 條件來同步的,所以有的資料會在一段時間內只存在於記憶體中。預設為 no

  • appendfilename appendonly.aof

指定更新日誌檔名,預設為 appendonly.aof

  • appendfsync everysec

指定更新日誌條件,共有 3 個可選值:

no:表示等作業系統進行資料快取同步到磁碟(快)

always:表示每次更新操作後手動呼叫 fsync() 將資料寫到磁碟(慢,安全)

everysec:表示每秒同步一次(折中,預設值)

  • vm-enabled no

指定是否啟用虛擬記憶體機制,預設值為 no,簡單的介紹一下,VM 機制將資料分頁存放,由 Redis 將訪問量較少的頁即冷資料 swap 到磁碟上,訪問多的頁面由磁碟自動換出到記憶體中(在後面的文章我會仔細分析 Redis 的 VM 機制)

  • vm-swap-file /tmp/redis.swap

虛擬記憶體檔案路徑,預設值為 /tmp/redis.swap,不可多個 Redis 例項共享

  • vm-max-memory 0

將所有大於 vm-max-memory 的資料存入虛擬記憶體,無論 vm-max-memory 設定多小,所有索引資料都是記憶體儲存的(Redis 的索引資料 就是 keys),也就是說,當 vm-max-memory 設定為 0 的時候,其實是所有 value 都存在於磁碟。預設值為 0

  • vm-page-size 32

Redis swap 檔案分成了很多的 page,一個物件可以儲存在多個 page 上面,但一個 page 上不能被多個物件共享,vm-page-size 是要根據儲存的 資料大小來設定的,作者建議如果儲存很多小物件,page 大小最好設定為 32 或者 64bytes;如果儲存很大大物件,則可以使用更大的 page,如果不確定,就使用預設值

  • vm-pages 134217728

設定 swap 檔案中的 page 數量,由於頁表(一種表示頁面空閒或使用的 bitmap)是在放在記憶體中的,,在磁碟上每 8 個 pages 將消耗 1byte 的記憶體。

  • vm-max-threads 4

設定訪問swap檔案的執行緒數,最好不要超過機器的核數,如果設定為0,那麼所有對swap檔案的操作都是序列的,可能會造成比較長時間的延遲。預設值為4

  • glueoutputbuf yes

設定在向客戶端應答時,是否把較小的包合併為一個包傳送,預設為開啟

hash-max-zipmap-entries 64

hash-max-zipmap-value 512

指定在超過一定的數量或者最大的元素超過某一臨界值時,採用一種特殊的雜湊演算法

  • activerehashing yes

指定是否啟用重置雜湊,預設為開啟(後面在介紹 Redis 的雜湊演算法時具體介紹)

  • include /path/to/local.conf

指定包含其它的配置檔案,可以在同一主機上多個Redis例項之間使用同一份配置檔案,而同時各個例項又擁有自己的特定配置檔案

五、Redis的持久化

Ⅰ-持久化之RDB

RDB(Redis DataBase)

image-20210517121148606.png

1.是什麼

  • 在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,也就是行話講的Snapshot快照,它恢復時是將快照檔案直接讀到記憶體裡

  • Redis會單獨建立(fork)一個子程式來進行持久化,會先將資料寫入到 一個臨時檔案中,待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。 整個過程中,主程式是不進行任何IO操作的(類似於垃圾回收中的STW),這就確保了極高的效能。如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化後的資料可能丟失。

  • rdb 儲存的是dump.rdb檔案

  • 相關配置在配置檔案的位置 - 在redis.conf搜尋### SNAPSHOTTING ###

2.如何觸發RDB快照

  • 配置檔案中預設的快照配置redis.conf中 dbfilename dump.rdb 也就是說它只會這個檔案
    • 冷拷貝後重新使用
      • 可以cp dump.rdb dump_new.rdb 主機和備份機是不同的
  • 立即進行備份命令save或者是bgsave
    • Save:save時只管儲存,其它不管,全部阻塞
    • BGSAVE:Redis會在後臺非同步進行快照操作, 快照同時還可以響應客戶端請求。可以通過lastsave 命令獲取最後一次成功執行快照的時間
  • 執行FLUSHALL命令,也會產生dump.rdb檔案,但裡面是空的,無意義

3.如何恢復

  • 將備份檔案 (dump.rdb) 移動到 redis 安裝目錄並啟動服務即可 (redis重新啟動的時候會自動讀取dump.rdb去恢復
  • CONFIG GET dir獲取目錄

4.優勢與劣勢

  • 優勢
    • 適合大規模的資料恢復
    • 對資料完整性和一致性要求不高
  • 劣勢
    • 在一定間隔時間做一次備份,所以如果redis意外down掉的話,就會丟失最後一次快照後的所有修改(因為儲存一次有時間間隔)
    • Fork的時候,記憶體中的資料被克隆了一份,大致2倍的膨脹性需要考慮

5.如何停止

動態所有停止RDB儲存規則的方法:redis-cli config set save ""

6.小結

  • RDB是一個非常緊湊的檔案。
  • RDB在儲存RDB檔案時父程式唯一需要做的就是fork出一個子程式,接下來的工作全部由子程式來做,父程式不需要再做其他I0操作,所以RDB持久化方式可以最大化redis的效能。
  • 與AOF相比,在恢復大的資料集的時候,RDB方式會更快一一些。
  • 資料丟失風險大。
  • RDB需要經常fork子程式來儲存資料集到硬碟上,當資料集比較大的時候fork的過程是非常耗時的,可能會導致Redis在一些毫秒級不能回應客戶端請求。

Ⅱ-持久化之AOF

AOF(Append Only File)

在Redis重啟的時候;AOF和dump同時存在的時候,先找誰?

先找AOF檔案,如果AOF有問題,Redis是啟動不了的。

1.是什麼

以日誌的形式來記錄每個寫操作,將Redis執行過的所有寫指令記錄下來(讀操作不記錄), 只許追加檔案但不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,換言之,redis 重啟的話就根據日誌檔案的內容將寫指令從前到後執行一次以完成資料的恢復工作

2.AOF配置

  • 相關配置在配置檔案的位置 - 在redis.conf搜尋### APPEND ONLY MODE ###
  • aof儲存的是appendonly.aof檔案(在配置檔案可修改檔名)

3.AOF啟動/修復/恢復

  • 正常恢復

    • 啟動:設定Yes
      • 修改預設的appendonly no,改為yes
    • 將有資料的aof檔案複製一份儲存到對應目錄(config get dir)
    • 恢復:重啟redis然後重新載入 (注意:如果之前最後的命令有FLASHALL,得先手動刪除,不然FLASHALL也會被再次執行一次,那就又沒得了)
  • 異常恢復(如果aof檔案有問題怎麼辦?因為先找的是aof

    • 啟動:設定Yes

      • 修改預設的appendonly no,改為yes
    • 備份被寫壞的AOF檔案

    • 修復:

      • Redis-check-aof --fix appendonly.aof 會把不符合語法的都刪掉,自動修復aof檔案

        (比如網路通訊會丟包檔案有損失)Redis-check-dump--fix檔案是一樣的

    • 恢復:重啟redis然後重新載入

4.rewrite

  • 是什麼:
    • AOF採用檔案追加方式,檔案會越來越大。為避免出現此種情況,新增了重寫機制, 當AOF檔案的大小超過所設定的閾值時,Redis就會啟動AOF檔案的內容壓縮, 只保留可以恢復資料的最小指令集。可以使用命令bgrewriteaof
  • 重寫原理
    • AOF檔案持續增長而過大時,會fork出一條新程式來將檔案重寫(也是先寫臨時檔案最後再rename), 遍歷新程式的記憶體中資料,每條記錄有一條的Set語句。重寫aof檔案的操作,並沒有讀取舊的aof檔案, 而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的aof檔案,這點和快照有點類似
  • 觸發機制
    • Redis會記錄上次重寫時的AOF大小,預設配置是當AOF檔案大小是上次rewrite後大小的一倍且檔案大於64M時觸發 (在redis.conf中的auto-aof-rewrite-min-size 64mb配置)

5.優勢與劣勢

  • 優勢
    • 每修改同步:appendfsync always 同步持久化 每次發生資料變更會被立即記錄到磁碟 效能較差但資料完整性比較好
    • 每秒同步:appendfsync everysec 非同步操作,每秒記錄 如果一秒內當機,有資料丟失
    • 不同步:appendfsync no 從不同步
  • 劣勢
    • 相同資料集的資料而言aof檔案要遠大於rdb檔案,恢復速度慢於rdb
    • Aof執行效率要慢於rdb,每秒同步策略效率較好,不同步效率和rdb相同

6.小結

  • AOF檔案時一個只進行追加的日誌檔案
  • Redis可以在AOF檔案體積變得過大時,自動地在後臺對AOF進行重寫
  • AOF檔案有序地儲存了對資料庫執行的所有寫入操作,這些寫入操作以Redis協議的格式儲存,因此AOF檔案的內容非常容易被人讀懂,對檔案進行分析也很輕鬆
  • 對於相同的資料集來說,AOF檔案的體積通常要大於RDB檔案的體積
  • 根據所使用的fsync 策略,AOF的速度可能會慢於RDB

Ⅲ-總結

1.官網建議

image-20210518002515204.png

  • RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照儲存
  • AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到檔案末尾.
  • Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大
  • 我只是做快取:如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化方式.

2.同時開啟兩種

  • 在這種情況下,當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要完整.
  • RDB的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案。那要不要只使用AOF呢?作者建議不要,因為RDB更適合用於備份資料庫(AOF在不斷變化不好備份),快速重啟,而且不會有AOF可能潛在的bug,留著作為一個萬一的手段。

3.效能建議

因為RDB檔案只用作後備用途,建議只在Slave上持久化RDB檔案,而且只要15分鐘備份一次就夠了,只保留save 900 1這條規則。

如果Enalbe AOF,好處是在最惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單隻load自己的AOF檔案就可以了。代價一是帶來了持續的IO,二是AOF rewrite的最後將rewrite過程中產生的新資料寫到新檔案造成的阻塞幾乎是不可避免的。只要硬碟許可,應該儘量減少AOF rewrite的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上。預設超過原大小100%大小時重寫可以改到適當的數值。

如果不Enable AOF ,僅靠Master-Slave Replication 實現高可用性也可以。能省掉一大筆IO也減少了rewrite時帶來的系統波動。代價是如果Master/Slave同時倒掉,會丟失十幾分鐘的資料,啟動指令碼也要比較兩個Master/Slave中的RDB檔案,載入較新的那個。新浪微博就選用了這種架構

六、Redis事務

事務官方文件

1.是什麼

可以一次執行多個命令,本質是一組命令的集合。一個事務中的所有命令都會序列化,按順序地序列化執行而不會被其它命令插入,不許加塞。

2.能幹嘛

一個佇列中,一次性、順序性、排他性的執行一系列命令。

3.怎麼玩

1)常用命令

image-20210518092030250.png

2)正常執行

  • MULTI & EXEC

image-20210518121603362.png

3)放棄事務

  • MULTI & discard

image-20210518122542020.png

4)全體連坐

  • MULTI & 執行的redis質量有錯誤 & exec 類似於語法錯誤 類似Java編譯異常

image-20210518122551488.png

5)冤頭債主

類似於語義執行的有問題 這個沒有直接報錯 類似Java執行異常

沒有強一致性,把對的放行,語義執行錯誤的就執行失敗。

image-20210518122600754.png

6)watch監控

WATCH 使得 EXEC 命令需要有條件地執行: 事務只能在所有被監視鍵都沒有被修改的前提下執行, 如果這個前提不能滿足的話,事務就不會被執行。link

悲觀鎖/樂觀鎖/CAS(Check And Set)

  • 悲觀鎖
    • 悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會block直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖
  • 樂觀鎖
    • 樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,可以使用版本號等機制。樂觀鎖適用於多讀的應用型別,這樣可以提高吞吐量。
    • 樂觀鎖策略:提交版本必須大於記錄當前版本才能執行更新
  • CAS

自旋鎖(見Java併發篇

信用卡可用餘額和欠額

  • 初始化信用卡可用餘額和欠額

image-20210518123912043.png

  • 無加塞篡改,先監控再開啟multi, 保證兩筆金額變動在同一個事務內

image-20210518123946302.png

  • 有加塞篡改
    • 監控了key,如果key被修改了,後面一個事務的執行失效

新增監控,保證這個變數沒有被修改過;如果被修改過,那麼這個事務會返回null 執行失敗。

image-20210518124512971.png

  • unwatch

image-20210518124926001.png

  • 一旦執行了exec之前加的監控鎖都會被取消掉了(一次性)
小結
  • Watch指令,類似樂觀鎖,事務提交時,如果Key的值已被別的客戶端改變, 比如某個list已被別的客戶端push/pop過了,整個事務佇列都不會被執行
  • 通過WATCH命令在事務執行之前監控了多個Keys,倘若在WATCH之後有任何Key的值發生了變化, EXEC命令執行的事務都將被放棄,同時返回Nullmulti-bulk應答以通知呼叫者事務執行失敗

4.階段

  • 開啟:以MULTI開始一個事務
  • 入隊:將多個命令入隊到事務中,接到這些命令並不會立即執行,而是放到等待執行的事務佇列裡面
  • 執行:由EXEC命令觸發事務

5.特性

  • 單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷。
  • 沒有隔離級別的概念:佇列中的命令沒有提交之前都不會實際的被執行,因為事務提交前任何指令都不會被實際執行, 也就不存在”事務內的查詢要看到事務裡的更新,在事務外查詢不能看到”這個讓人萬分頭痛的問題
  • 不保證原子性redis同一個事務中如果有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾不遵循傳統的ACID中的AI

七、Redis釋出訂閱

**用觀察者模式理解學習 ** (雖然支援訊息中介軟體部分功能,但是很少有人會這麼幹)

程式間的一種訊息通訊模式:傳送者(pub)傳送訊息,訂閱者(sub)接收訊息。

下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關係:

image-20210518125313842.png

當有新訊息通過 PUBLISH 命令傳送給頻道 channel1 時, 這個訊息就會被髮送給訂閱它的三個客戶端:

image-20210518125328506.png

1.常用命令

image-20210518093059601.png

2.例項

以下例項演示了釋出訂閱是如何工作的。在我們例項中我們建立了訂閱頻道名為 redisChat:

redis 127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1

現在,我們先重新開啟個 redis 客戶端,然後在同一個頻道 redisChat 釋出兩次訊息,訂閱者就能接收到訊息。

redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"

(integer) 1

redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"

(integer) 1

# 訂閱者的客戶端會顯示如下訊息
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by runoob.com"

訂閱多個萬用字元 *

PSUBSCRIBE new*

收取訊息,

PUBLISH new1 redis2015

八、Redis主從複製

1.是什麼

image-20210518093213152.png

行話:也就是我們所說的主從複製,主機資料更新後根據配置和策略, 自動同步到備機的master/slaver機制,Master以寫為主,Slave以讀為主

2.能幹嘛

  • 讀寫分離
  • 容災恢復

3.怎麼玩

1)準備工作

  • 配從(庫)不配主(庫)

  • 從庫配置命令:

    config set masterauth master-password (如果你主庫設定了連線密碼,得先把密碼加上去)

    slaveof 主庫IP 主庫埠

    • 每次與master斷開之後,都需要重新連線,除非你配置進redis.conf檔案(具體位置:redis.conf搜尋#### REPLICATION ####
    • info replication 檢視節點資訊
  • 修改配置檔案細節操作

    • 拷貝多個redis.conf檔案,按’redis[port].conf’重新命名
    • 開啟daemonize yes
    • pid檔名字
    • 指定埠
    • log檔名字
    • dump.rdb名字
################################ GENERAL  ####################################
#daemonize yespidfile /var/run/redis6379.pid 
#為了區別加一個埠號字尾port 6379  
#port 6380 port 6381logfile "6379.log" 
#為每個機器區分
################################ SNAPSHOTTING  ###############################
#dbfilename dump6379.rdb
#啟動
./redis-server redis6379.conf
./redis-server redis6380.conf
./redis-server redis6381.conf
#連線
./redis-cli -p 6379 -a coderxz
./redis-cli -p 6380 -a coderxz
./redis-cli -p 6381 -a coderxz

一臺機器,三個中段,根據三個不同的配置檔案,每個終端個啟動一次。

image-20210518142045739.png

image-20210518142501701.png

4.常用3招

一主二僕
  • Init 都是master

image-20210518152251579-1621826456985.png

config set masterauth master-password (如果你主庫設定了連線密碼,得先把密碼加上去)

SLAVEOF IP:埠 儲存

  • 一個Master兩個Slave

image-20210518152305556.png

檢視從機狀態:

image-20210518150007707.png

  • 日誌檢視

    • 主機日誌

image-20210518152325972.png

  • 備機日誌

image-20210518152336169.png

  • info replication

image-20210518152347795.png

主從問題演示

  1. 切入點問題?slave1、slave2是從頭開始複製還是從切入點開始複製?比如從k4進來,那之前的123是否也可以複製?
    • 答:從頭開始複製;123也可以複製
  2. 從機是否可以寫?set可否?
    • 答:從機不可寫,不可set,主機可寫
  3. 主機shutdown後情況如何?從機是上位還是原地待命
    • 答:從機還是原地待命(鹹魚翻身,還是鹹魚)
  4. 主機又回來了後,主機新增記錄,從機還能否順利複製?
    • 答:能
  5. 其中一臺從機掛了後情況如何?依照原有它能跟上大部隊嗎?
    • 答:不能跟上,每次與master斷開之後,都需要重新連線,除非你配置進redis.conf檔案(具體位置:redis.conf搜尋#### REPLICATION ####
薪火相傳
  • 上一個Slave可以是下一個slave的Master,Slave同樣可以接收其他 slaves的連線和同步請求,那麼該slave作為了鏈條中下一個的master, 可以有效減輕master的寫壓力(奴隸的奴隸還是奴隸) 老闆->小老闆->打工人
  • 中途變更轉向:會清除之前的資料,重新建立拷貝最新的
  • slaveof 新主庫IP 新主庫埠

目前的master掛著兩個打工人:

image-20210518150923227.png

我希望的是我只負責一個,由另一個去負責下一個:

image-20210518151336235.png

image-20210518151732248.png

image-20210518151516850.png

反客為主

希望當主機掛了的時候,從機從新選一個主機出來

  • SLAVEOF no one

使當前資料庫停止與其他資料庫的同步,轉成主資料庫

複製原理

  • slave啟動成功連線到master後會傳送一個sync命令 (同步命令)
  • master接到命令啟動後臺的存檔程式,同時收集所有接收到的用於修改資料集命令, 在後臺程式執行完畢之後,master將傳送整個資料檔案到slave,以完成一次完全同步
  • 全量複製:而slave服務在接收到資料庫檔案資料後,將其存檔並載入到記憶體中。
  • 增量複製:Master繼續將新的所有收集到的修改命令依次傳給slave,完成同步
  • 但是隻要是重新連線master,一次完全同步(全量複製)將被自動執行

哨兵模式(sentinel)

一組sentinel能同時監控多個master

是什麼

反客為主的自動版,能夠後臺監控主機是否故障,如果故障了根據投票數自動將從庫轉換為主庫

怎麼玩(使用步驟)

  1. 調整結構,6379帶著6380、6381

  2. 新建sentinel.conf檔案,名字絕不能錯

  3. 配置哨兵,填寫內容

    • sentinel auth-pass < master-IP> < password>如果主機設定了密碼

    • sentinel monitor 被監控資料庫名字(自己起名字) 127.0.0.1 6379 1 such:sentinel monitor host6379 127.0.0.1 6379 1

    • 上面最後一個數字1,表示主機掛掉後salve投票看讓誰接替成為主機,得票數多少後成為主機(PS. 跟官網的描述有出入,下面有官方文件說明)

      sentinel monitor host6379 127.0.0.1 6379 1sentinel auth-pass 127.0.0.1 coderxz
      
  4. 啟動哨兵

    1. redis-sentinel /sentinel.conf(上述目錄依照各自的實際情況配置,可能目錄不同)
  5. 正常主從演示

  6. 原有的master掛了

  7. 投票新選

  8. 重新主從繼續開工,info replication查檢視

問題:如果之前掛了的master重啟回來,會不會雙master衝突?

答: 不會,原master,變成slave

複製的缺點

複製延時

由於所有的寫操作都是先在Master上操作,然後同步更新到slave上,所以從Master同步到Slave機器有一定的延遲,當系統很繁忙的時候,延遲問題會更加嚴重,Slave機器數量的增加也會使這個問題更加嚴重。

思維導圖

Redis.jpg

相關文章