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

本文適合於剛接觸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 [email protected]
(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

Tags: