Redis 數據庫


1.1 Redis簡介

1.1.1 介紹

Redis是一個使用ANSI C編寫的開源、支持網絡、基於內存、可選持久性的鍵值對(key-value)存儲數據庫。從20156月開始,Redis的開發由Redis Labs贊助,而20135月至20156月期間,其開發由Pivotal贊助。在20135月之前,其開發由VMware贊助。根據月度排行網站DB-Engines.com的數據顯示,Redis是最流行的鍵值對存儲數據庫。

 

數據來源:https://db-engines.com/en/ranking

Redis采用內存(In-Memory)數據集(DataSet)

支持多種數據類型。

運行於大多數POSIX系統,如Linux*BSDOS X等。

Redis作者: Salvatore Sanfilippo

作者GitHUB: https://github.com/antirez/redis

1.1.2 軟件獲取和幫助

官方網站:https://redis.io

官方各版本下載地址:http://download.redis.io/releases/

Redis 中文命令參考:http://redisdoc.com

中文網站1http://redis.cn

中文網站2http://www.redis.net.cn

1.1.3 Redis特性

 高速讀寫,數據類型豐富

支持持久化,多種內存分配及回收策略

支持弱事務,消息隊列、消息訂閱

支持高可用,支持分布式分片集群

1.1.4 企業緩存數據庫解決方案對比

Memcached:

優點:高性能讀寫、單一數據類型、支持客戶端式分布式集群、一致性hash多核結構、多線程讀寫性能高。

缺點:無持久化、節點故障可能出現緩存穿透、分布式需要客戶端實現、跨房數據同步困難、架構擴容復雜度高

Redis:

優點:高性能讀寫、多數據類型支持、數據持久化、高可用架構、支持自定義虛擬內存、支持分布式分片集群、單線程讀寫性能極高

缺點:多線程讀寫較Memcached

Tair 官方網站:http://tair.taobao.org

優點:高性能讀寫、支持三種存儲引擎(ddbrdbldb)、支持高可用、支持分布式分片集群、支撐了幾乎所有淘寶業務的緩存。

缺點:單機情況下,讀寫性能較其他兩種產品較慢。

 

1.1.5 Redis應用場景

數據高速緩存,web會話緩存(Session Cache

排行榜應用

消息隊列,發布訂閱

   附錄 - Redis的企業應用

 

1.2 Redis簡單部署

1.2.1 典型安裝-單實例

系統環境說明

[root@Redis ~]# cat /etc/redhat-release 
CentOS release 6.9 (Final)
[root@Redis ~]# uname -r 
2.6.32-696.el6.x86_64
[root@Redis ~]# sestatus 
SELinux status:                 disabled
[root@Redis ~]# /etc/init.d/iptables status
iptables: Firewall is not running.
[root@Redis ~]# hostname -I 
10.0.0.186 172.16.1.186

安裝redis

[root@Redis ~]# cd /usr/local/
[root@Redis local]# wget http://download.redis.io/releases/redis-3.2.10.tar.gz
[root@Redis local]# tar xzf redis-3.2.10.tar.gz
[root@Redis local]# \rm redis-3.2.10.tar.gz 
[root@Redis local]# mv redis-3.2.10 redis
[root@Redis local]# cd redis/
[root@Redis redis]# make

   至此redis就安裝完成

1.2.2 啟動第一個redis實例

創建客戶端軟連接

[root@Redis src]# ln -s /usr/local/redis/src/redis-cli /usr/bin/

簡單啟動方法,都使用默認配置

[root@Redis ~]# cd /usr/local/redis/src
[root@Redis src]# ./redis-server &

編寫配置文件

1、精簡化配置文件

[root@Redis redis]# cp redis.conf{,.bak}
[root@Redis redis]# grep -Ev '^$|#' redis.conf.bak > redis.conf
[root@Redis redis]# cp redis.conf /etc/

2、編輯配置文件

[root@Redis ~]# cat /etc/redis.conf 
bind 127.0.0.1 10.0.0.186
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/var/log/redis_6379.log"
dir /usr/local/redis/data/
# ···

   配置文件說明:https://www.cnblogs.com/zhang-ke/p/5981108.html

   3、編寫啟動腳本(適用於CentOS 6.X

#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
# chkconfig: - 85 15
# url: http://blog.nmtui.com
# user: clsn
### END INIT INFO

REDISPORT=6379
EXEC=/usr/local/redis/src/redis-server
CLIEXEC=/usr/local/redis/src/redis-cli
PIDFILE=/var/run/redis_6379.pid
CONF="/etc/redis.conf"
# source function library
. /etc/rc.d/init.d/functions
rd_start() {
    if [ -f $PIDFILE ]
    then
            action "$PIDFILE exists" /bin/false
    else
        $EXEC $CONF
        if [ $? -eq 0 ]
          then
                action "Starting Redis server..." /bin/true
        else
            action "Starting Redis server..." /bin/false
        fi
    fi
}
rd_stop() {
    if [ ! -f $PIDFILE ]
    then
            action  "$PIDFILE does not exist, process is not running" /bin/false
    else
            PID=$(cat $PIDFILE)
            $CLIEXEC -p $REDISPORT shutdown
            while [ -x /proc/${PID} ]
            do
                echo "Waiting for Redis to shutdown ..."
                sleep 1
            done
            action "Redis stopped" /bin/true
    fi
}
rd_status() {
    if [ -f $PIDFILE ]
    then
            echo "redis server is running....."
    else
            echo "redis is stopped"
    fi
}
rd_restart() {
    rd_stop
    sleep 2 
    rd_start
}
case "$1" in
    start)
    rd_start
        ;;
    stop)
    rd_stop
        ;;
    status)
    rd_status
    ;;
    restart)
    rd_restart
        ;;
    *)
    echo $"Usage: $0 {start|stop|restart|status}"
        ;;
esac
View Code redis管理腳本

   注意:自編寫腳本注意執行權限。

1.2.3 Redis多實例配置

注意:本次多實例配置基於單實例配置完成后

創建並進入程序目錄

[root@Redis redis]# mkdir /application/redis  -p
[root@Redis redis]# cd /application/redis/

   修改配置文件

for i in 0 1 2
  do  
    # 創建多實例(端口命名)目錄
    mkdir -p 638$i
    # 復制啟動程序到各實例
    \cp /usr/local/redis/src/redis-server /application/redis/638$i/ 
    # 復制配置文件。注意:此處基於單實例配置完成
    \cp /etc/redis.conf  /application/redis/638$i/
    # 修改程序存儲目錄
    sed -i  "/dir/s#.*#dir /application/redis/638$i/#g" /application/redis/638$i/redis.conf 
    # 修改其他端口信息
    sed -i  "s#6379#638$i#g" /application/redis/638$i/redis.conf
    # 允許遠程連接redis
    sed -i '/protected-mode/s#yes#no#g' /application/redis/638$i/redis.conf
done

# 啟動實例

for i in 0 1 2 
  do
  /application/redis/638$i/redis-server /application/redis/638$i/redis.conf 
done

   連接redis

[root@Redis redis]# redis-cli -h 10.0.0.186 -p 6379
10.0.0.186:6379>

1.2.4 redis.conf配置說明

是否后台運行:

daemonize no/yes

默認端口:

port 6379

AOF日志開關是否打開:

appendonly no/yes

日志文件位置

logfile /var/log/redis.log

RDB持久化數據文件:

dbfilename dump.rdb

指定IP進行監聽

bind 10.0.0.51 ip2 ip3 ip4

禁止protected-mode

protected-mode yes/no (保護模式,是否只允許本地訪問)

增加requirepass {password}

requirepass root

redis-cli中使用

auth {password} 進行認證

1.2.5 在線變更配置

獲取當前配置

CONFIG GET *

變更運行配置

CONFIG SET loglevel "notice"

修改密碼為空

10.0.0.186:6379> config set requirepass ""
10.0.0.186:6379> exit
10.0.0.186:6379> config get dir
1) "dir"
2) "/usr/local/redis/data"

1.3 Redis數據持久化

1.3.1 持久化策略

redis 提供了多種不同級別的持久化方式:一種是RDB,另一種是AOF.

RDB 持久化

可以在指定的時間間隔內生成數據集的時間點快照(point-in-time snapshot)。

AOF 持久化

記錄服務器執行的所有寫操作命令,並在服務器啟動時,通過重新執行這些命令來還原數據集。 AOF 文件中的命令全部以 Redis 協議的格式來保存,新命令會被追加到文件的末尾。

Redis 還可以在后台對 AOF 文件進行重寫(rewrite),使得 AOF 文件的體積不會超出保存數據集狀態所需的實際大小。Redis 還可以同時使用 AOF 持久化和 RDB 持久化。 在這種情況下, Redis 重啟時, 它會優先使用 AOF 文件來還原數據集, 因為 AOF 文件保存的數據集通常比 RDB 文件所保存的數據集更完整。

你甚至可以關閉持久化功能,讓數據只在服務器運行時存在。

1.3.2 RDB 持久化

RDB的優點

RDB 是一個非常緊湊(compact)的文件,它保存了 Redis 在某個時間點上的數據集。 這種文件非常適合用於進行備份: 比如說,你可以在最近的 24 小時內,每小時備份一次 RDB 文件,並且在每個月的每一天,也備份一個 RDB 文件。 這樣的話,即使遇上問題,也可以隨時將數據集還原到不同的版本。

RDB 非常適用於災難恢復(disaster recovery):它只有一個文件,並且內容都非常緊湊,可以(在加密后)將它傳送到別的數據中心,或者亞馬遜 S3 中。

RDB 可以最大化 Redis 的性能:父進程在保存 RDB 文件時唯一要做的就是 fork 出一個子進程,然后這個子進程就會處理接下來的所有保存工作,父進程無須執行任何磁盤 I/O 操作。

RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。

RDB的缺點

如果你需要盡量避免在服務器故障時丟失數據,那么 RDB 不適合你。

雖然 Redis 允許你設置不同的保存點(save point)來控制保存 RDB 文件的頻率, 但是, 因為RDB 文件需要保存整個數據集的狀態, 所以它並不是一個輕松的操作。 因此你可能會至少 5 分鍾才保存一次 RDB 文件。 在這種情況下, 一旦發生故障停機, 你就可能會丟失好幾分鍾的數據

每次保存 RDB 的時候,Redis 都要 fork() 出一個子進程,並由子進程來進行實際的持久化工作。 在數據集比較龐大時, fork() 可能會非常耗時,造成服務器在某某毫秒內停止處理客戶端;如果數據集非常巨大,並且 CPU 時間非常緊張的話,那么這種停止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也需要進行 fork() ,但無論 AOF 重寫的執行間隔有多長,數據的耐久性都不會有任何損失。

1.3.3 AOF 持久化

AOF 優點

使用AOF 會讓你的Redis更加耐久: 你可以使用不同的fsync策略:無fsync,每秒fsync,每次寫的時候fsync.使用默認的每秒fsync策略,Redis的性能依然很好(fsync是由后台線程進行處理的,主線程會盡力處理客戶端請求),一旦出現故障,你最多丟失1秒的數據.

Redis 可以在 AOF 文件體積變得過大時,自動地在后台對 AOF 進行重寫 重寫后的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。 整個重寫操作是絕對安全的,因為 Redis 在創建新 AOF 文件的過程中,會繼續將命令追加到現有的 AOF 文件里面,即使重寫過程中發生停機,現有的 AOF 文件也不會丟失。

一旦新 AOF 文件創建完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,並開始對新 AOF 文件進行追加操作。

AOF 文件有序地保存了對數據庫執行的所有寫入操作, 這些寫入操作以 Redis 協議的格式保存, 因此 AOF 文件的內容非常容易被人讀懂 對文件進行分析(parse)也很輕松。 導出(export AOF 文件也非常簡單: 舉個例子, 如果你不小心執行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那么只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 並重啟 Redis 就可以將數據集恢復到 FLUSHALL 執行之前的狀態。

AOF 缺點

對於相同的數據集來說,AOF 文件的體積通常要大於 RDB 文件的體積。根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB

在一般情況下, 每秒 fsync 的性能依然非常高, 關閉 fsync 可以讓 AOF 的速度和 RDB 一樣快 即使在高負荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(latency)。

AOF 在過去曾經發生過這樣的 bug :因為個別命令的原因,導致 AOF 文件在重新載入時,無法將數據集恢復成保存時的原樣。 (舉個例子,阻塞命令 BRPOPLPUSH 就曾經引起過這樣的 bug 。) 測試套件里為這種情況添加了測試: 它們會自動生成隨機的、復雜的數據集, 並通過重新載入這些數據來確保一切正常。

雖然這種 bug AOF 文件中並不常見, 但是對比來說, RDB 幾乎是不可能出現這種 bug 的。

1.3.4 如何選擇使用哪種持久化方式

一般來說, 如果想達到足以媲美 PostgreSQL 的數據安全性, 你應該同時使用兩種持久化功能。

如果你非常關心你的數據, 但仍然可以承受數分鍾以內的數據丟失, 那么你可以只使用 RDB 持久化。

有很多用戶都只使用 AOF 持久化, 但我們並不推薦這種方式: 因為定時生成 RDB 快照(snapshot)非常便於進行數據庫備份, 並且 RDB 恢復數據集的速度也要比 AOF 恢復的速度要快, 除此之外, 使用 RDB 還可以避免之前提到的 AOF 程序的 bug

Note: 因為以上提到的種種原因, 未來redis可能會將 AOF RDB 整合成單個持久化模型(這是一個長期計划)。

1.3.5 快照實現持久化

在默認情況下, Redis 將數據庫快照保存在名字為 dump.rdb的二進制文件中。你可以對 Redis 進行設置, 讓它在“ N 秒內數據集至少有 M 個改動”這一條件被滿足時, 自動保存一次數據集。

你也可以通過調用 SAVE或者 BGSAVE 手動讓 Redis 進行數據集保存操作。

   比如說, 以下設置會讓 Redis 在滿足“ 60 秒內有至少有 1000 個鍵被改動”這一條件時, 自動保存一次數據集save 60 1000 

   這種持久化方式被稱為快照 snapshotting.

Redis 需要保存 dump.rdb 文件時, 服務器執行以下操作:

🎣 Redis 調用forks. 同時擁有父進程和子進程。

🎣 子進程將數據集寫入到一個臨時 RDB 文件中。

🎣 當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。

這種工作方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益。

1.3.6 AOF持久化

只進行追加操作的文件(append-only fileAOF

快照功能並不是非常耐久:如果 Redis 因為某些原因而造成故障停機,那么服務器將丟失最近寫入、且仍未保存到快照中的那些數據。盡管對於某些程序來說,數據的耐久性並不是最重要的考慮因素,但是對於那些追求完全耐久能力的程序員來說,快照功能就不太適用了。

1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。

你可以通過修改配置文件來打開 AOF 功能: appendonly yes 

從現在開始,每當 Redis 執行一個改變數據集的命令式(比如 SET),這個命令就會被追加到 AOF 文件的末尾。

這樣的話,當redis重新啟動時,程序就可以通過重新執行 AOF 文件中的命令來達到重建數據集的目的

1.3.7 AOF日志重寫

因為 AOF 的運作方式是不斷地將命令追加到文件的末尾, 所以隨着寫入命令的不斷增加, AOF 文件的體積也會變得越來越大

舉個例子, 如果你對一個計數器調用了 100 INCR 那么僅僅是為了保存這個計數器的當前值, AOF 文件就需要使用 100 條記錄(entry)。然而在實際上, 只使用一條 SET 命令已經足以保存計數器的當前值了, 其余 99 條記錄實際上都是多余的。

為了處理這種情況, Redis 支持一種有趣的特性: 可以在不打斷服務客戶端的情況下, AOF 文件進行重建(rebuild)。執行 BGREWRITEAOF 命令, Redis 將生成一個新的 AOF 文件, 這個文件包含重建當前數據集所需的最少命令Redis 2.2 需要自己手動執行 BGREWRITEAOF 命令.

1.3.8 AOF有多耐用?

你可以配置 Redis 多久才將數據 fsync 到磁盤一次。有三種方式:

👽 每次有新命令追加到 AOF 文件時就執行一次 fsync :非常慢,也非常安全

👽 每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多),並且在故障時只會丟失 1 秒鍾的數據。

👽 從不 fsync :將數據交給操作系統來處理。更快,也更不安全的選擇。

👽 推薦(並且也是默認)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。

1.3.9 如果AOF文件損壞了怎么辦?

服務器可能在程序正在對 AOF 文件進行寫入時停機, 如果停機造成了 AOF 文件出錯(corrupt), 那么 Redis 在重啟時會拒絕載入這個 AOF 文件, 從而確保數據的一致性不會被破壞。當發生這種情況時, 可以用以下方法來修復出錯的 AOF 文件:

🎑 為現有的 AOF 文件創建一個備份。

🎑 使用 Redis 附帶的 redis-check-aof 程序,對原來的 AOF 文件進行修復$ redis-check-aof –fix 

🎑 使用 diff -u 對比修復后的 AOF 文件和原始 AOF 文件的備份,查看兩個文件之間的不同之處。(可選)

🎑 重啟 Redis 服務器,等待服務器載入修復后的 AOF 文件,並進行數據恢復。

1.3.10 AOFRDB之間的相互作用

在版本號大於等於 2.4 Redis 中,BGSAVE 執行的過程中, 不可以執行 BGREWRITEAOF

反過來說, BGREWRITEAOF 執行的過程中, 也不可以執行 BGSAVE。這可以防止兩個 Redis 后台進程同時對磁盤進行大量的 I/O 操作。

如果 BGSAVE 正在執行, 並且用戶顯示地調用 BGREWRITEAOF 命令, 那么服務器將向用戶回復一個 OK 狀態, 並告知用戶, BGREWRITEAOF 已經被預定執行: 一旦 BGSAVE 執行完畢, BGREWRITEAOF 就會正式開始。

Redis 啟動時, 如果 RDB 持久化和 AOF 持久化都被打開了, 那么程序會優先使用 AOF 文件來恢復數據集 因為 AOF 文件所保存的數據通常是最完整的。

1.3.11 備份redis數據

Redis 對於數據備份是非常友好的, 因為你可以在服務器運行的時候對 RDB 文件進行復制:

RDB 文件一旦被創建, 就不會進行任何修改。 當服務器要創建一個新的 RDB 文件時, 它先將文件的內容保存在一個臨時文件里面, 當臨時文件寫入完畢時, 程序才使用 rename(2) 原子地用臨時文件替換原來的 RDB 文件。

   這也就是說, 無論何時, 復制 RDB 文件都是絕對安全的。

🎍 創建一個定期任務(cron job), 每小時將一個 RDB 文件備份到一個文件夾, 並且每天將一個 RDB 文件備份到另一個文件夾。

🎍 確保快照的備份都帶有相應的日期和時間信息, 每次執行定期任務腳本時, 使用 find 命令來刪除過期的快照: 比如說, 你可以保留最近 48 小時內的每小時快照, 還可以保留最近一兩個月的每日快照。

🎍 至少每天一次, RDB 備份到你的數據中心之外, 或者至少是備份到你運行 Redis 服務器的物理機器之外。

1.3.12 RDB持久化配置

RDB持久化基本配置

修改配置文件

save 900 1
save 300 10
save 60 10000

配置分別表示:

• 900秒(15分鍾)內有1個更改

• 300秒(5分鍾)內有10個更改
• 60秒內有10000個更改    
• 當達到以上定義的配置時間時,就將內存數據持久化到磁盤。

RDB持久化高級配置

stop-writes-on-bgsave-error yes
rdbcompression yes 
rdbchecksum yes
dbfilename dump.rdb
dir ./clsn/redis/data/6379

以上配置分別表示:

• 后台備份進程出錯時,主進程停不停止寫入? 主進程不停止容易造成數據不一致
• 導出的rdb文件是否壓縮 如果rdb的大小很大的話建議這么做
• 導入rbd恢復時數據時,要不要檢驗rdb的完整性 驗證版本是不是一致
• 導出來的rdb文件名
• rdb的放置路徑

1.3.13 AOF持久化配置

AOF持久化基本配置

appendonly yes/no
appendfsync always
appendfsync everysec
appendfsync no

配置分別表示:

 

• 是否打開aof日志功能

• 每1個命令,都立即同步到aof

• 每秒寫1次

• 寫入工作交給操作系統,由操作系統判斷緩沖區大小,統一寫入到aof.

 

AOF持久化高級配置

no-appendfsync-on-rewrite yes/no
auto-aof-rewrite-percentage 100 
auto-aof-rewrite-min-size 64mb

配置分別表示:

• 正在導出rdb快照的過程中,要不要停止同步aof

• aof文件大小比起上次重寫時的大小,增長率100%時重寫,缺點:業務開始的時候,會重復重寫多次。

• aof文件,至少超過64M時,重寫

1.3.14 RDBAOF切換

Redis 2.2 或以上版本,可以在不重啟的情況下,從 RDB 切換到 AOF

1、為最新的 dump.rdb 文件創建一個備份。

2、將備份放到一個安全的地方。

3、執行以下兩條命令:

redis-cli config set appendonly yes
redis-cli config set save “”

4、確保寫命令會被正確地追加到 AOF 文件的末尾。

執行說明

  執行的第一條命令開啟了 AOF 功能: Redis 會阻塞直到初始 AOF 文件創建完成為止, 之后 Redis 會繼續處理命令請求, 並開始將寫入命令追加到 AOF 文件末尾。

  執行的第二條命令用於關閉 RDB 功能。 這一步是可選的, 如果你願意的話, 也可以同時使用 RDB 和 AOF 這兩種持久化功能。

注意:別忘了在 redis.conf 中打開 AOF 功能! 否則的話, 服務器重啟之后, 之前通過 CONFIG SET 設置的配置不會生效, 程序會按原來的配置來啟動服務器。

1.4 Redis管理實戰

1.4.1 基本數據類型

類型

說明

String  字符串

Redis 字符串數據類型的相關命令用於管理 redis 字符串值

Hash  哈希

Redis hash 是一個string類型的fieldvalue的映射表,hash特別適合用於存儲對象。

Redis 中每個 hash 可以存儲 232 - 1 鍵值對(40多億)。

List  列表

Redis列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)

 

一個列表最多可以包含 232 - 1 個元素 (4294967295, 每個列表超過40億個元素)

Set   集合

Redis Set String 類型的無序集合。集合成員是唯一的,這就意味着集合中不能出現重復的數據。

Sorted set  有序集合

Redis 有序集合和集合一樣也是string類型元素的集合,且不允許重復的成員。

1.4.2 全局Key操作

命令

含義

KEYS *

查看KEY支持通配符

DEL

刪除給定的一個或多個key

EXISTS

檢查是否存在

RENAME

變更KEY

SORT

鍵值排序,有非數字時報錯

TYPE

返回鍵所存儲值的類型

DUMP RESTORE

序例化與反序列化

EXPIRE\ PEXPIRE

以秒\毫秒設定生存時間

TTL\ PTTL

以秒\毫秒為單位返回生存時間

PERSIST

取消生存實現設置

RANDOMKEY

返回數據庫中的任意鍵

1.4.3 String(字符串)

stringredis最基本的類型,一個key對應一個value。一個鍵最大能存儲512MB

命令

描述

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 decrementkey

所儲存的值減去給定的減量值(decrement

APPEND key value

如果 key 已經存在並且是一個字符串, APPEND 命令將 指定value 追加到改 key 原來的值(value)的末尾。

應用場景

常規計數:微博數,粉絲數等。

1.4.4 Hash(字典)

我們可以將Redis中的Hashes類型看成具有String KeyString Valuemap容器。

所以該類型非常適合於存儲值對象的信息。如UsernamePasswordAge等。如果Hash中包含很少的字段,那么該類型的數據也將僅占用很少的磁盤空間。每一個Hash可以存儲995701749 個鍵值對。

命令

描述

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]

迭代哈希表中的鍵值對。

應用場景:

存儲部分變更的數據,如用戶信息等。

1.4.5 LIST(列表)

List類型是按照插入順序排序的字符串鏈表。和數據結構中的普通鏈表一樣,我們可以在其頭部(left)和尾部(right)添加新的元素。

在插入時,如果該鍵並不存在,Redis將為該鍵創建一個新的鏈表。與此相反,如果鏈表中所有的元素均被移除,那么該鍵也將會被從數據庫中刪除。

List中可以包含的最大元素數量是4294967295

命令

描述

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

為已存在的列表添加值

應用場景

消息隊列系統,比如sina微博

Redis中我們的最新微博ID使用了常駐緩存,這是一直更新的。但是做了限制不能超過5000ID,因此獲取ID的函數會一直詢問Redis。只有在start/count參數超出了這個范圍的時候,才需要去訪問數據庫。

系統不會像傳統方式那樣“刷新”緩存,Redis實例中的信息永遠是一致的。SQL數據庫(或是硬盤上的其他類型數據庫)只是在用戶需要獲取“很遠”的數據時才會被觸發,而主頁或第一個評論頁是不會麻煩到硬盤上的數據庫了。

1.4.6 SET(集合)

Set類型看作為沒有排序的字符集合。Set可包含的最大元素數量是4294967295。如果多次添加相同元素,Set中將僅保留該元素的一份拷貝。

命令

描述

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]

迭代集合中的元素

應用場景:

  在微博應用中,可以將一個用戶所有的關注人存在一個集合中,將其所有粉絲存在一個集合。

  Redis還為集合提供了求交集、並集、差集等操作,可以非常方便的實現如共同關注、共同喜好、二度好友等功能,對上面的所有集合操作,你還可以使用不同的命令選擇將結果返回給客戶端還是存集到一個新的集合中。

1.4.7 SortedSet(有序集合)

Sorted-Sets中的每一個成員都會有一個分數(score)與之關聯,Redis正是通過分數來為集合中的成員進行從小到大的排序。成員是唯一的,但是分數(score)卻是可以重復的。

集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是O(1) 集合中最大的成員數為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)

命令

描述

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]

迭代有序集合中的元素(包括元素成員和元素分值)

應用場景:

  排行榜應用,取TOP N操作這個需求與上面需求的不同之處在於,前面操作以時間為權重,這個是以某個條件為權重,比如按頂的次數排序,這時候就需要我們的sorted set出馬了,將你要排序的值設置成sorted set的score,將具體的數據設置成相應的value,每次只需要執行一條ZADD命令即可。

1.4.8 消息模式

Redis發布消息通常有兩種模式:

• 隊列模式(queuing)

• 發布-訂閱模式(publish-subscribe)

任務隊列:

顧名思義,就是“傳遞消息的隊列”。與任務隊列進行交互的實體有兩類,一類是生產者(producer),另一類則是消費者(consumer)。生產者將需要處理的任務放入任務隊列中,而消費者則不斷地從任務獨立中讀入任務信息並執行。

任務隊列的好處:

松耦合。

生產者和消費者只需按照約定的任務描述格式,進行編寫代碼。

易於擴展。

多消費者模式下,消費者可以分布在多個不同的服務器中,由此降低單台服務器的負載。

1.4.9 Redis 發布訂閱

其實從Pub/Sub的機制來看,它更像是一個廣播系統,多個Subscriber可以訂閱多個Channel,多個Publisher可以往多個Channel中發布消息。可以這么簡單的理解:

• Subscriber:收音機,可以收到多個頻道,並以隊列方式顯示

• Publisher:電台,可以往不同的FM頻道中發消息

• Channel:不同頻率的FM頻道

1.4.9.1 發布訂閱模型

一個Publisher,多個Subscriber模型

   如下圖所示,可以作為消息隊列或者消息管道。

主要應用:通知、公告。

 

多個Publisher,一個Subscriber模型

   可以將PubSub做成獨立的HTTP接口,各應用程序作為PublisherChannel中發送消息,Subscriber端收到消息后執行相應的業務邏輯,比如寫數據庫,顯示等等。

主要應用:排行榜、投票、計數。

 

多個Publisher,多個Subscriber模型

故名思議,就是可以向不同的Channel中發送消息,由不同的Subscriber接收。

主要應用:群聊、聊天。

1.4.9.2 實踐發布訂閱

發布訂閱實踐命令

命令

描述

PUBLISH channel msg

將信息 message 發送到指定的頻道 channel

SUBSCRIBE channel [channel ...]

訂閱頻道,可以同時訂閱多個頻道

UNSUBSCRIBE [channel ...]

取消訂閱指定的頻道, 如果不指定頻道,則會取消訂閱所有頻道

PSUBSCRIBE pattern [pattern ...]

訂閱一個或多個符合給定模式的頻道,每個模式以 * 作為匹配符,比如 it* 匹配所有以 it 開頭的頻道( it.news it.blog it.tweets 等等) news.* 匹配所有以 news. 開頭的頻道( news.it news.global.today 等等),諸如此類

PUNSUBSCRIBE [pattern [pattern ...]]

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

PUBSUB subcommand [argument [argument ...]]

查看訂閱與發布系統狀態

注意:使用發布訂閱模式實現的消息隊列,當有客戶端訂閱channel后只能收到后續發布到該頻道的消息,之前發送的不會緩存,必須ProviderConsumer同時在線。

1.4.9.3 消息隊列系統對比

客戶端在執行訂閱命令之后進入了訂閱狀態,只能接收 SUBSCRIBE PSUBSCRIBE UNSUBSCRIBE PUNSUBSCRIBE 四個命令。

 開啟的訂閱客戶端,無法收到該頻道之前的消息,因為 Redis 不會對發布的消息進行持久化。

和很多專業的消息隊列系統(例如KafkaRocketMQ)相比,Redis的發布訂閱略顯粗糙,例如無法實現消息堆積和回溯。但勝在足夠簡單,如果當前場景可以容忍的這些缺點,也不失為一個不錯的選擇。

1.4.10 Redis事務管理

redis中的事務跟關系型數據庫中的事務是一個相似的概念,但是有不同之處。

關系型數據庫事務執行失敗后面的sql語句不在執行,而redis中的一條命令執行失敗,其余的命令照常執行。

redis中開啟一個事務是使用multi,相當於begin\start transactionexec提交事務,discard取消隊列命令(非回滾操作)。

   redismysql對比

 

MySQL

Redis

開啟

start transaction/begin

multi

語句

普通SQL

普通命令

失敗

rollback 回滾

discard 取消(不叫回滾,是隊列里面的命令不執行,隊列里面的任務根本就沒有執行。而不是執行了也可以撤回來)

成功

commit

exec

1.4.10.1     Redis 事務命令

命令

描述

DISCARD

取消事務,放棄執行事務塊內的所有命令。

EXEC

執行所有事務塊內的命令。

MULTI

標記一個事務塊的開始。

UNWATCH

取消 WATCH 命令對所有 key 的監視。

WATCH key [key ...]

監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那么事務將被打斷。

事務執行舉例

 

ZADD salary 2000 user1
ZADD salary 3000 user2
ZRANGE salary 0 -1 WITHSCORES
MULTI
ZINCRBY salary 1000 user1
ZINCRBY salary -1000 user2
EXEC

1.4.10.2     Redis中事務中的鎖機制

舉例:我正在買票 Ticket -1 , money -100 

而票只有1, 如果在我multi之后,exec之前, 票被別人買了,即ticket變成0了。

我該如何觀察這種情景,並不再提交:

悲觀的想法:

世界充滿危險,肯定有人和我搶, ticket上鎖, 只有我能操作. [悲觀鎖]

樂觀的想法:

沒有那么人和我搶,因此,我只需要注意,有沒有人更改ticket的值就可以了 [樂觀鎖]

Redis的事務中,啟用的是樂觀鎖,只負責監測key沒有被改動.

1.4.10.3     Redis服務管理命令

命令

描述

BGREWRITEAOF

異步執行一個 AOFAppendOnly File 文件重寫操作

BGSAVE

在后台異步保存當前數據庫的數據到磁盤

CLIENT KILL [ip:port] [ID client-id]

關閉客戶端連接

CLIENT LIST

獲取連接到服務器的客戶端連接列表

CLIENT GETNAME

獲取連接的名稱

CLIENT PAUSE timeout

在指定時間內終止運行來自客戶端的命令

CLIENT SETNAME connection-name

設置當前連接的名稱

CLUSTER SLOTS

獲取集群節點的映射數組

COMMAND

獲取 Redis 命令詳情數組

COMMAND COUNT

獲取 Redis 命令總數

COMMAND GETKEYS

獲取給定命令的所有鍵

TIME

返回當前服務器時間

COMMAND INFO command-name [command-name ...]

獲取指定 Redis 命令描述的數組

CONFIG GET parameter

獲取指定配置參數的值

CONFIG REWRITE

對啟動 Redis 服務器時所指定的 redis.conf 配置文件進行改寫

CONFIG SET parameter value

修改 redis 配置參數,無需重啟

CONFIG RESETSTAT

重置 INFO 命令中的某些統計數據

DBSIZE

返回當前數據庫的 key 的數量

DEBUG OBJECT key

獲取 key 的調試信息

DEBUG SEGFAULT

Redis 服務崩潰

FLUSHALL

刪除所有數據庫的所有key

FLUSHDB

刪除當前數據庫的所有key

INFO [section]

獲取 Redis 服務器的各種信息和統計數值

LASTSAVE

返回最近一次 Redis 成功將數據保存到磁盤上的時間,以 UNIX 時間戳格式表示

MONITOR

實時打印出 Redis 服務器接收到的命令,調試用

ROLE

返回主從實例所屬的角色

SAVE

異步保存數據到硬盤

SHUTDOWN [NOSAVE] [SAVE]

異步保存數據到硬盤,並關閉服務器

SLAVEOF host port

將當前服務器轉變為指定服務器的從屬服務器(slave server)

SLOWLOG subcommand [argument]

管理 redis 的慢日志

SYNC

用於復制功能(replication)的內部命令

1.4.11 redis慢日志查詢

Slow log Redis 用來記錄查詢執行時間的日志系統。

slow log 保存在內存里面,讀寫速度非常快

可以通過改寫 redis.conf 文件或者用 CONFIG GET CONFIG SET 命令對它們動態地進行修改

slowlog-log-slower-than 10000 超過多少微秒
CONFIG SET slowlog-log-slower-than 100
CONFIG SET slowlog-max-len 1000 保存多少條慢日志
CONFIG GET slow*
SLOWLOG GET
SLOWLOG RESET

1.5 Redis主從復制

1.5.1 redis復制特性

使用異步復制。

一個主服務器可以有多個從服務器。

從服務器也可以有自己的從服務器。

復制功能不會阻塞主服務器。

可以通過復制功能來讓主服務器免於執行持久化操作,由從服務器去執行持久化操作即可。

關閉主服務器持久化時,復制功能的數據安全

當配置Redis復制功能時,強烈建議打開主服務器的持久化功能。 否則的話,由於延遲等問題,部署的服務應該要避免自動拉起。

為了幫助理解主服務器關閉持久化時自動拉起的危險性,參考一下以下會導致主從服務器數據全部丟失的例子:

1. 假設節點A為主服務器,並且關閉了持久化。 並且節點B和節點C從節點A復制數據

2. 節點A崩潰,然后由自動拉起服務重啟了節點A. 由於節點A的持久化被關閉了,所以重啟之后沒有任何數據

3. 節點B和節點C將從節點A復制數據,但是A的數據是空的, 於是就把自身保存的數據副本刪除。

在關閉主服務器上的持久化,並同時開啟自動拉起進程的情況下,即便使用Sentinel來實現Redis的高可用性,也是非常危險的。 因為主服務器可能拉起得非常快,以至於Sentinel在配置的心跳時間間隔內沒有檢測到主服務器已被重啟,然后還是會執行上面的數據丟失的流程。

無論何時,數據安全都是極其重要的,所以應該禁止主服務器關閉持久化的同時自動拉起

1.5.2 主從復制原理

redis 主從同步有兩種方式(或者所兩個階段):全同步和部分同步。

主從剛剛連接的時候,進行全同步;全同步結束后,進行部分同步。當然,如果有需要,slave 在任何時候都可以發起全同步。

redis 策略是,無論如何,首先會嘗試進行部分同步,如不成功,要求從機進行全同步,並啟動 BGSAVE……BGSAVE 結束后,傳輸 RDB 文件;如果成功,允許從機進行部分同步,並傳輸積壓空間中的數據。

下面這幅圖,總結了主從同步的機制:

 

主從復制原理:

1. 從服務器向主服務器發送 SYNC 命令。

2. 接到 SYNC 命令的主服務器會調用BGSAVE 命令,創建一個 RDB 文件,並使用緩沖區記錄接下來執行的所有寫命令。

3. 當主服務器執行完 BGSAVE 命令時,它會向從服務器發送 RDB 文件,而從服務器則會接收並載入這個文件。

4. 主服務器將緩沖區儲存的所有寫命令發送給從服務器執行。

命令的傳播

在主從服務器完成同步之后,主服務器每執行一個寫命令,它都會將被執行的寫命令發送給從服務器執行,這個操作被稱為“命令傳播”(command propagate)。

 

命令傳播是一個持續的過程:只要復制仍在繼續,命令傳播就會一直進行,使得主從服務器的狀態可以一直保持一致。

1.5.3 復制中的SYNCPSYNC

Redis 2.8 版本之前, 斷線之后重連的從服務器總要執行一次完整重同步(full resynchronization)操作。

Redis 2.8 開始,Redis 使用 PSYNC命令代替 SYNC 命令。PSYNC 比起 SYNC 的最大改進在於 PSYNC 實現了部分重同步(partial resync)特性:在主從服務器斷線並且重新連接的時候,只要條件允許,PSYNC 可以讓主服務器只向從服務器同步斷線期間缺失的數據,而不用重新向從服務器同步整個數據庫。

1.5.4 復制的一致性問題

 

在讀寫分離環境下,客戶端向主服務器發送寫命令 SET n 10086,主服務器在執行這個寫命令之后,向客戶端返回回復,並將這個寫命令傳播給從服務器。

接到回復的客戶端繼續向從服務器發送讀命令 GET n ,並且因為網絡狀態的原因,客戶端的 GET命令比主服務器傳播的 SET 命令更快到達了從服務器。

因為從服務器鍵 n 的值還未被更新,所以客戶端在從服務器讀取到的將是一個錯誤(過期)的 n值。

1.5.5 復制安全性提升

主服務器只在有至少 N 個從服務器的情況下,才執行寫操作從 Redis 2.8 開始, 為了保證數據的安全性, 可以通過配置, 讓主服務器只在有至少 N 個當前已連接從服務器的情況下, 才執行寫命令。

不過, 因為 Redis 使用異步復制, 所以主服務器發送的寫數據並不一定會被從服務器接收到, 因此, 數據丟失的可能性仍然是存在的。

通過以下兩個參數保證數據的安全:

min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>

1.5.6 Redis主從復制實踐

在安裝redis時就進行了多實例的配置

准備兩個或兩個以上redis實例
6380/redis-server
6380/redis.conf
6381/redis-server
6381/redis.conf
6382/redis-server
6382/redis.conf

配置文件示例:

bind 127.0.0.1 10.0.0.186
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
loglevel notice
logfile "/var/log/redis_6380.log"
dbfilename dump.rdb
dir /application/redis/6380/
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
slowlog-log-slower-than 10000
slowlog-max-len 128
protected-mode no

啟動:

./6380/redis-server ./6380/redis.conf
./6381/redis-server ./6381/redis.conf
./6382/redis-server ./6382/redis.conf

復制環境說明

主節點:6380
從節點:6381、6382

開啟主從(在6381 6382實例中執行)

redis-cli -p 6381/6382
SLAVEOF 127.0.0.1 6380

   至此redis主從復制完成

1.5.7 Redis主從復制管理

主從復制狀態監控:info replication

主從切換: slaveof no one

1.6 Redis HA 實踐Redis Sentinel

官方文檔:https://redis.io/topics/sentinel

Redis-SentinelRedis官方推薦的高可用性(HA)解決方案,當用RedisMaster-slave的高可用方案時,假如master宕機了,Redis本身(包括它的很多客戶端)都沒有實現自動進行主備切換,而Redis-sentinel本身也是一個獨立運行的進程,它能監控多個master-slave集群,發現master宕機后能進行自動切換。

 

Sentinel 是一個監視器,它可以根據被監視實例的身份和狀態來判斷應該執行何種動作。

1.6.1 Redis Sentinel 功能

📣監控Monitoring):

Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。

📣 提醒Notification):

當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。

📣 自動故障遷移Automatic failover):

當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中一個從服務器升級為新的主服務器, 並讓失效主服務器的其他從服務器改為復制新的主服務器; 當客戶端試圖連接失效的主服務器時, 集群也會向客戶端返回新主服務器的地址, 使得集群可以使用新主服務器代替失效服務器。

1.6.2 服務器連接

發現並連接主服務器

Sentinel 通過用戶給定的配置文件來發現主服務器。

Sentinel 會與被監視的主服務器創建

兩個網絡連接:

🐱🏍 命令連接用於向主服務器發送命令。

🐱🏍 訂閱連接用於訂閱指定的頻道,從而發現

監視同一主服務器的其他 Sentinel

發現並連接從服務器

   Sentinel 通過向主服務器發送 INFO 命令來自動獲得所有從服務器的地址。

   跟主服務器一樣,Sentinel 會與每個被發現的從服務器創建命令連接和訂閱連接。

 

發現其他 Sentinel

   Sentinel 會通過命令連接向被監視的主從服務器發送 HELLO 信息,該消息包含Sentinel IP、端口號、ID 等內容,以此來向其他 Sentinel 宣告自己的存在。與此同時Sentinel 會通過訂閱連接接收其他 Sentinel 的“HELLO 信息,以此來發現監視同一個主服務器的其他 Sentinel

 

sentinel1 通過發送HELLO 信息來讓sentinel2 sentinel3發現自己,其他兩個sentinel 也會進行類似的操作。

多個Sentienl之間的鏈接

   Sentinel 之間只會互相創建命令連接,用於進行通信。因為已經有主從服務器作為發送和接收 HELLO 信息的中介,所以 Sentinel之間不會創建訂閱連接。

 

1.6.3 檢測實例的狀態

Sentinel 使用 PING 命令來檢測實例的狀態:如果實例在指定的時間內沒有返回回復,或者返回錯誤的回復,那么該實例會被 Sentinel 判斷為下線。

 

Redis Sentinel 中關於下線(down)有兩個不同的概念:

🥓 主觀下線(Subjectively Down 簡稱 SDOWN指的是單個Sentinel 實例對服務器做出的下線判斷。

🥓客觀下線(Objectively Down 簡稱 ODOWN指的是多個Sentinel 實例在對同一個服務器做出 SDOWN 判斷, 並且通過 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服務器下線判斷。 (一個 Sentinel 可以通過向另一個 Sentinel 發送 SENTINEL is-master-down-by-addr 命令來詢問對方是否認為給定的服務器已下線。)

如果一個服務器沒有在 master-down-after-milliseconds 選項所指定的時間內, 對向它發送 PING 命令的 Sentinel 返回一個有效回復(valid reply), 那么 Sentinel 就會將這個服務器標記為主觀下線。

1.6.4 故障轉移FAILOVER

一次故障轉移操作由以下步驟組成:

1.   發現主服務器已經進入客觀下線狀態。

2.   基於Raft leader election 協議 , 進行投票選舉

3.   如果當選失敗,那么在設定的故障遷移超時時間的兩倍之后,重新嘗試當選。 如果當選成功, 那么執行以下步驟。

4.   選出一個從服務器,並將它升級為主服務器。

5.   向被選中的從服務器發送 SLAVEOF NO ONE 命令,讓它轉變為主服務器。

6.   通過發布與訂閱功能, 將更新后的配置傳播給所有其他 Sentinel ,其他 Sentinel 對它們自己的配置進行更新。

7.   向已下線主服務器的從服務器發送 SLAVEOF 命令,讓它們去復制新的主服務器。

8.   當所有從服務器都已經開始復制新的主服務器時, leader Sentinel 終止這次故障遷移操作。

1.6.5 配置sentinel

創建程序目錄

cd /application
mkdir 26380
cp /usr/local/redis/src/redis-sentinel ./26380/
cd  26380

   編輯配置文件

vim sentinel.conf
port 26380
dir "/tmp"
sentinel monitor mymaster 127.0.0.1 6380 2
sentinel down-after-milliseconds mymaster 60000
sentinel config-epoch mymaster 0

啟動sentinel

./redis-sentinel ./sentinel.conf

配置文件說明

# 指定監控master
sentinel monitor mymaster 127.0.0.1 6370 2 
# {2表示多少個sentinel同意}
# 安全信息
sentinel auth-pass mymaster root
# 超過15000毫秒后認為主機宕機
sentinel down-after-milliseconds mymaster 15000 
# 當主從切換多久后認為主從切換失敗
sentinel failover-timeout mymaster 900000
# 這兩個配置后面的數量主從機需要一樣,epoch為master的版本
sentinel leader-epoch mymaster 1
sentinel config-epoch mymaster 1

1.6.6 Sentinel命令操作

命令

描述

PING

返回 PONG

SENTINEL masters

列出所有被監視的主服務器

SENTINEL slaves <master name>

 

SENTINEL get-master-addr-by-name <master name>

返回給定名字的主服務器的 IP 地址和端口號。

SENTINEL reset <pattern>

重置所有名字和給定模式 pattern 相匹配的主服務器

SENTINEL failover <master name>

當主服務器失效時, 在不詢問其他 Sentinel 意見的情況下, 強制開始一次自動故障遷移。

1.6.7 Sentinel發布與訂閱信息

客戶端可以將 Sentinel 看作是一個只提供了訂閱功能的 Redis 服務器: 你不可以使用 PUBLISH 命令向這個服務器發送信息, 但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通過訂閱給定的頻道來獲取相應的事件提醒。

一個頻道能夠接收和這個頻道的名字相同的事件。 比如說, 名為 +sdown 的頻道就可以接收所有實例進入主觀下線(SDOWN)狀態的事件。

通過執行 PSUBSCRIBE * 命令可以接收所有事件信息。

以下列出的是客戶端可以通過訂閱來獲得的頻道和信息的格式:

 第一個英文單詞是頻道/事件的名字,其余的是數據的格式。

注意, 當格式中包含 instance details 字樣時, 表示頻道所返回的信息中包

含了以下用於識別目標實例的內容:

<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
@ 字符之后的內容用於指定主服務器, 這些內容是可選的, 它們僅在 @ 字符之前的內容指定的實例不是主服務器時使用。

1.7 Redis cluster

1.7.1 Redis集群

Redis 集群是一個可以在多個 Redis 節點之間進行數據共享的設施(installation)。

Redis 集群不支持那些需要同時處理多個鍵的 Redis 命令, 因為執行這些命令需要在多個 Redis 節點之間移動數據, 並且在高負載的情況下,這些命令將降低 Redis 集群的性能, 並導致不可預測的行為。

Redis 集群通過分區(partition)來提供一定程度的可用性(availability): 即使集群中有一部分節點失效或者無法進行通訊,集群也可以繼續處理命令請求。將數據自動切分(split)到多個節點的能力。

當集群中的一部分節點失效或者無法進行通訊時, 仍然可以繼續處理命令請求的能力。

1.7.2 Redis 集群數據共享

Redis 集群使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集群包含 16384 個哈希槽(hash slot),數據庫中的每個鍵都屬於這 16384 個哈希槽的其中一個, 集群使用公式CRC16(key) % 16384 來計算鍵 key 屬於哪個槽, 其中 CRC16(key) 語句用於計算鍵 key CRC16 校驗和

節點 A 負責處理 0 號至 5500 號哈希槽。

節點 B 負責處理 5501 號至 11000 號哈希槽。

 

節點 C 負責處理 11001 號至 16384 號哈希槽。

槽的計算公式

集群使用公式 CRC16(key) & 16383 計算鍵 key屬於哪個槽。

 

1.7.3 集群運行機制

所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.

節點的fail是通過集群中超過半數的master節點檢測失效時才失效。

客戶端與redis節點直連,不需要中間proxy.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可

把所有的物理節點映射到[0-16383]slot,cluster 負責維護node<->slot<->key

 

為了使得集群在一部分節點下線或者無法與集群的大多數(majority)節點進行通訊的情況下, 仍然可以正常運作, Redis 集群對節點使用了主從復制功能: 集群中的每個節點都有 1 個至 N 個復制品(replica), 其中一個復制品為主節點(master), 而其余的 N-1 個復制品為從節點(slave)。

在之前列舉的節點 A 的例子中, 如果節點 B 下線了, 那么集群將無法正常運行, 因為集群找不到節點來處理 5501 號至 11000  號的哈希

槽。

假如在創建集群的時候(或者至少在節點 B 下線之前), 我們為主節點  B添加了從節點 B1  那么當主節點 B 下線的時候, 集群就會將 B1  設置為新的主節點, 並讓它代替下線的主節點 B  繼續處理 5501 號至  11000 號的哈希槽, 這樣集群就不會因為主節點 B  的下線而無法正常運作了。

 

不過如果節點 B  B1 都下線的話, Redis 集群還是會停止運作。

集群的復制特性重用了 SLAVEOF 命令的代碼,所以集群節點的復制行為和SLAVEOF 命令的復制行為完全相同。

1.7.4 集群的故障轉移

1. 在集群里面,節點會對其他節點進行下線檢測。

2. 當一個主節點下線時,集群里面的其他主節點負責對下線主節點進行故障移。

3. 換句話說,集群的節點集成了下線檢測和故障轉移等類似 Sentinel 的功能。

4. 因為 Sentinel 是一個獨立運行的監控程序,而集群的下線檢測和故障轉移等功能是集成在節點里面的,它們的運行模式非常地不同,所以盡管這兩者的功能很相似,但集群的實現沒有重用 Sentinel 的代碼。

在集群里面執行命令的兩種情況

命令發送到了正確的節點:

命令要處理的鍵所在的槽正好是由接收命令的節點負責,那么該節點執行命令,就像單機 Redis 服務器一樣。

 

槽位說明:

7000:  0~5000

7001:槽 5001~10000

 

7002:槽 10001~16383

鍵 date 位於 2022 槽,該槽由節點 7000 負責,命令會直接執行。

命令發送到了錯誤的節點

接收到命令的節點並非處理鍵所在槽的節點,那么節點將向客戶端返回一個轉向(redirection)錯誤,告知客戶端應該到哪個節點去執行這個命令,客戶端會根據錯誤提示的信息,重新向正確的節點發送命令。

鍵 date 位於 2022 槽,該槽由節點 7000 負責,但錯誤發送到了7001節點,7001向客戶返回轉向錯誤。

客戶端根據轉向錯誤的指引,轉向到節點7000,並重新發送命令

1.7.5 關於轉向錯誤

在集群中的節點會互相告知對方,自己負責處理哪些槽。

集群中的每個節點都會記錄 16384 個槽分別由哪個節點負責,從而形成一個“槽表”(slot table)。

節點在接收到命令請求時,會通過槽表檢查鍵所在的槽是否由本節點處理:

如果是的話,那么節點直接執行命令;

如果不是的話,那么節點就從槽表里面提取出正確節點的地址信息,然后返回轉向錯誤。

 

1.7.6 配置集群

前期准備

# EPEL源安裝ruby支持

yum install ruby rubygems -y

使用國內源

gem source -a http://mirrors.aliyun.com/rubygems/  -remove https://rubygems.org/
# gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
# 安裝redis支持
gem install redis -v 3.3.3
gem sources -l

配置文件

Redis 集群由多個運行在集群模式(cluster mode)下的 Redis 實例組成, 實例的集群模式需要通過配置來開啟, 開啟集群模式的實例將可以使用集群特有的功能和命令。

以下是一個包含了最少選項的集群配置文件示例:

 

port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

創建程序目錄

cd /application/redis
mkdir 7000 7001 7002 7003 7004 7005

拷貝應用

for i in 0 1 2 3 4 5 
    do
    cp /usr/local/redis/src/redis-server  ./700$i
done

創建配置文件

for i in 7000 7001 7002 7003 7004 7005
do
echo "port $i
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes" > $i/redis.conf
done

啟動redis集群

for i in 7000 7001 7002 7003 7004 7005
do
    cd $i 
    ./redis-server ./redis.conf & 
    cd ../
done

創建集群

cd /usr/local/redis/src/
./redis-trib.rb --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

給定 redis-trib.rb 程序的命令是 create 這表示我們希望創建一個新的集群。

選項 --replicas 1 表示我們希望為集群中的每個主節點創建一個從節點。

1.7.7 集群管理

寫數據,查看集群狀態

redis-cli -c -p 7000
set foo bar
get foo

重新分片實踐

cd /usr/local/redis/src/
./redis-trib.rb reshard 127.0.0.1:7000

集群狀態

redis-cli -p 7000 cluster nodes | grep master

故障轉移

redis-cli -p 7002 debug segfault

查看狀態

redis-cli -p 7000 cluster nodes | grep master

增加新的節點

./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000

刪除一個節點

redis-trib del-node ip:port '<node-id>'

刪除master節點之前首先要使用reshard移除master的全部slot,然后再刪除當前節點

添加一個從節點

./redis-trib.rb add-node --slave --master-id $[nodeid] 127.0.0.1:7008 127.0.0.1:7000

1.7.8 狀態說明

集群最近一次向節點發送 PING 命令之后, 過去了多長時間還沒接到回復。

節點最近一次返回 PONG 回復的時間。

節點的配置節點(configuration epoch):詳細信息請參考Redis 集群規范

本節點的網絡連接情況:例如 connected

節點目前包含的槽:例如 127.0.0.1:7001 目前包含號碼為 5960 10921 的哈希槽。

1.8 Redis API

1.8.1 PHP使用redis

tar zxvf 2.2.7.tar.gz
cd phpredis-2.2.7
/application/php/bin/phpize
./configure --with-php-config=/application/php/bin/php-config
make && make install
echo 'extension="redis.so"' >> /application/php/lib/php.ini
service php-fpm restart
service nginx restart

連接測試代碼

[root@clsn ~]# cat /application/nginx/html/check.php
<?php
//連接本地的 Redis 服務
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
echo "Connection to server sucessfully";
//查看服務是否運行
echo "Server is running: " . $redis->ping();
?>

字符串操作

<?php
//連接本地的 Redis 服務
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
echo "Connection to server sucessfully";
//設置 redis 字符串數據
$redis->set("tutorial-name", "Redis tutorial");
// 獲取存儲的數據並輸出
echo "Stored string in redis:: " . $redis-
>get("tutorial-name");
?>

1.8.2 Python連接redis

安裝軟件包

[root@Redis ~]# yum install python-pip ipython -y  
[root@Redis ~]# pip install redis

測試

[root@Redis ~]# ipython
In [1]: import redis

In [2]: clsn = redis.StrictRedis(host='localhost', port=6379, db=0)

In [3]: clsn.set('blog','blog.nmtui.com')
Out[3]: True

In [4]: clsn.get('blog')
Out[4]: 'blog.nmtui.com'

1.9 參考文獻

[1] http://blog.csdn.net/oanqoanq/article/details/50992535

[2] http://www.redis.cn/topics/persistence.html

[3] http://www.runoob.com/redis/redis-tutorial.html

[4] http://blog.csdn.net/hechurui/article/details/49508813

[5] https://www.cnblogs.com/lukexwang/p/4711977.html

[6] https://www.cnblogs.com/daoluanxiaozi/p/3724299.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM