1.1 Redis簡介

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

數據來源:https://db-engines.com/en/ranking
Redis采用內存(In-Memory)數據集(DataSet) 。
支持多種數據類型。
運行於大多數POSIX系統,如Linux、*BSD、OS 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
中文網站1:http://redis.cn
中文網站2:http://www.redis.net.cn
1.1.3 Redis特性
高速讀寫,數據類型豐富
支持持久化,多種內存分配及回收策略
支持弱事務,消息隊列、消息訂閱
支持高可用,支持分布式分片集群
1.1.4 企業緩存數據庫解決方案對比
Memcached:
優點:高性能讀寫、單一數據類型、支持客戶端式分布式集群、一致性hash多核結構、多線程讀寫性能高。
缺點:無持久化、節點故障可能出現緩存穿透、分布式需要客戶端實現、跨房數據同步困難、架構擴容復雜度高
Redis:
優點:高性能讀寫、多數據類型支持、數據持久化、高可用架構、支持自定義虛擬內存、支持分布式分片集群、單線程讀寫性能極高
缺點:多線程讀寫較Memcached慢
Tair: 官方網站:http://tair.taobao.org
優點:高性能讀寫、支持三種存儲引擎(ddb、rdb、ldb)、支持高可用、支持分布式分片集群、支撐了幾乎所有淘寶業務的緩存。
缺點:單機情況下,讀寫性能較其他兩種產品較慢。




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
注意:自編寫腳本注意執行權限。
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 file,AOF)
快照功能並不是非常耐久:如果 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 AOF和RDB之間的相互作用
在版本號大於等於 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 RDB到AOF切換
在 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類型的field和value的映射表,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(字符串)
string是redis最基本的類型,一個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 Key和String Value的map容器。
所以該類型非常適合於存儲值對象的信息。如Username、Password和Age等。如果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使用了常駐緩存,這是一直更新的。但是做了限制不能超過5000個ID,因此獲取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接口,各應用程序作為Publisher向Channel中發送消息,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后只能收到后續發布到該頻道的消息,之前發送的不會緩存,必須Provider和Consumer同時在線。
1.4.9.3 消息隊列系統對比
客戶端在執行訂閱命令之后進入了訂閱狀態,只能接收 SUBSCRIBE 、PSUBSCRIBE、 UNSUBSCRIBE 、PUNSUBSCRIBE 四個命令。
開啟的訂閱客戶端,無法收到該頻道之前的消息,因為 Redis 不會對發布的消息進行持久化。
和很多專業的消息隊列系統(例如Kafka、RocketMQ)相比,Redis的發布訂閱略顯粗糙,例如無法實現消息堆積和回溯。但勝在足夠簡單,如果當前場景可以容忍的這些缺點,也不失為一個不錯的選擇。
1.4.10 Redis事務管理
redis中的事務跟關系型數據庫中的事務是一個相似的概念,但是有不同之處。
關系型數據庫事務執行失敗后面的sql語句不在執行,而redis中的一條命令執行失敗,其余的命令照常執行。
redis中開啟一個事務是使用multi,相當於begin\start transaction,exec提交事務,discard取消隊列命令(非回滾操作)。
redis於mysql對比
|
|
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 |
異步執行一個 AOF(AppendOnly 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 復制中的SYNC與PSYNC
在 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-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis做Master-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 、C 的例子中, 如果節點 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
