【實踐】REDIS緩存數據庫從安裝到入門

1.摘要

Redis(REmote DIctionary Server) 是一個開源的使用ANSI C語言編寫、遵守BSD協議、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API。
對一個產品,技術的認知,從基本的安裝和使用開始最容易獲得直觀認知。
本文包括REDIS在UBUNTU的安裝,基本命令的操作使用和不錯的參考文檔。

具體目錄結構如下:

  1. 安裝
  2. 命令
    3.1 REDIS配置
    3.2 設置密碼和驗證
    3.3 REDIS支持的類型
    <1> String(字符串)
    <2>Hash(哈希)
    <3> List(列表)
    <4> Set(集合)
    <5> zset(sorted set:有序集合)
    3.4 Redis 發布訂閱
  3. REDIS常見問題
    5.Redis面試題
    6.參考

2. 安裝

在 Ubuntu 系統安裝 Redis 可以使用以下命令:

sudo apt-get update
sudo apt-get install redis-server

啟動 Redis:

redis-server

查看 redis 是否啟動:

redis-cli

以上命令將打開以下終端:
redis 127.0.0.1:6379>
127.0.0.1 是本機 IP ,6379 是 redis 服務端口。現在我們輸入 PING 命令,能返回PONG表示成功了。

3. 命令

3.1 REDIS配置

Redis 的配置文件位于 Redis 安裝目錄下(ubuntu系統下,默認為/etc/redis/redis.conf),文件名為 redis.conf(Windows 名為 redis.windows.conf)。
你可以通過 CONFIG 命令查看或設置配置項。

redis 127.0.0.1:6379> CONFIG GET *

redis.conf 配置項說明如下:

序號 配置項 說明
1 daemonize no Redis 默認不是以守護進程的方式運行,可以通過該配置項修改,使用 yes 啟用守護進程(Windows 不支持守護線程的配置為 no )
2 pidfile /var/run/redis.pid 當 Redis 以守護進程方式運行時,Redis 默認會把 pid 寫入 /var/run/redis.pid 文件,可以通過 pidfile 指定
3 port 6379 指定 Redis 監聽端口,默認端口為 6379,作者在自己的一篇博文中解釋了為什么選用 6379 作為默認端口,因為 6379 在手機按鍵上 MERZ 對應的號碼,而 MERZ 取自意大利歌女 Alessia Merz 的名字
4 bind 127.0.0.1 綁定的主機地址
5 timeout 300 當客戶端閑置多長時間后關閉連接,如果指定為 0,表示關閉該功能
6 loglevel notice 指定日志記錄級別,Redis 總共支持四個級別:debug、verbose、notice、warning,默認為 notice
7 logfile stdout 日志記錄方式,默認為標準輸出,如果配置 Redis 為守護進程方式運行,而這里又配置為日志記錄方式為標準輸出,則日志將會發送給 /dev/null
8 databases 16 設置數據庫的數量,默認數據庫為0,可以使用SELECT 命令在連接上指定數據庫id
9 save <seconds> <changes> Redis 默認配置文件中提供了三個條件:save 900 1 save 300 10 save 60 10000 分別表示 900 秒(15 分鐘)內有 1 個更改,300 秒(5 分鐘)內有 10 個更改以及 60 秒內有 10000 個更改。指定在多長時間內,有多少次更新操作,就將數據同步到數據文件,可以多個條件配合
10 rdbcompression yes 指定存儲至本地數據庫時是否壓縮數據,默認為 yes,Redis 采用 LZF 壓縮,如果為了節省 CPU 時間,可以關閉該選項,但會導致數據庫文件變的巨大
11 dbfilename dump.rdb 指定本地數據庫文件名,默認值為 dump.rdb
12 dir ./ 指定本地數據庫存放目錄
13 slaveof <masterip> <masterport> 設置當本機為 slav 服務時,設置 master 服務的 IP 地址及端口,在 Redis 啟動時,它會自動從 master 進行數據同步
14 masterauth <master-password> 當 master 服務設置了密碼保護時,slav 服務連接 master 的密碼
15 requirepass foobared 設置 Redis 連接密碼,如果配置了連接密碼,客戶端在連接 Redis 時需要通過 AUTH <password> 命令提供密碼,默認關閉
16 maxclients 128 設置同一時間最大客戶端連接數,默認無限制,Redis 可以同時打開的客戶端連接數為 Redis 進程可以打開的最大文件描述符數,如果設置 maxclients 0,表示不作限制。當客戶端連接數到達限制時,Redis 會關閉新的連接并向客戶端返回 max number of clients reached 錯誤信息
17 maxmemory <bytes> 指定 Redis 最大內存限制,Redis 在啟動時會把數據加載到內存中,達到最大內存后,Redis 會先嘗試清除已到期或即將到期的 Key,當此方法處理 后,仍然到達最大內存設置,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis 新的 vm 機制,會把 Key 存放內存,Value 會存放在 swap 區
18 appendonly no 指定是否在每次更新操作后進行日志記錄,Redis 在默認情況下是異步的把數據寫入磁盤,如果不開啟,可能會在斷電時導致一段時間內的數據丟失。因為 redis 本身同步數據文件是按上面 save 條件來同步的,所以有的數據會在一段時間內只存在于內存中。默認為 no
19 appendfilename appendonly.aof 指定更新日志文件名,默認為 appendonly.aof
20 appendfsync everysec 指定更新日志條件,共有 3 個可選值:no:表示等操作系統進行數據緩存同步到磁盤(快)always:表示每次更新操作后手動調用 fsync() 將數據寫到磁盤(慢,安全)everysec:表示秒同步一次(折中,默認值)
21 vm-enabled no 指定是否啟用虛擬內存機制,默認值為 no,簡單的介紹一下,VM 機制將數據分頁存放,由 Redis 將訪問量較少的頁即冷數據 swap 到磁盤上,訪問多的頁面由磁盤自動換出到內存中(在后面的文章我會仔細分析 Redis 的 VM 機制)
22 vm-swap-file /tmp/redis.swap 虛擬內存文件路徑,默認值為 /tmp/redis.swap,不可多個 Redis 實例共享
23 vm-max-memory 0 將所有大于 vm-max-memory 的數據存入虛擬內存,無論 vm-max-memory 設置多小,所有索引數據都是內存存儲的(Redis 的索引數據 就是 keys),也就是說,當 vm-max-memory 設置為 0 的時候,其實是所有 value 都存在于磁盤。默認值為 0
24 vm-page-size 32 Redis swap 文件分成了很多的 page,一個對象可以保存在多個 page 上面,但一個 page 上不能被多個對象共享,vm-page-size 是要根據存儲的 數據大小來設定的,作者建議如果存儲很多小對象,page 大小最好設置為 32 或者 64bytes;如果存儲很大大對象,則可以使用更大的 page,如果不確定,就使用默認值
25 vm-pages 134217728 設置 swap 文件中的 page 數量,由于頁表(一種表示頁面空閑或使用的 bitmap)是在放在內存中的,,在磁盤上每 8 個 pages 將消耗 1byte 的內存。
26 vm-max-threads 4 設置訪問swap文件的線程數,最好不要超過機器的核數,如果設置為0,那么所有對swap文件的操作都是串行的,可能會造成比較長時間的延遲。默認值為4
27 glueoutputbuf yes 設置在向客戶端應答時,是否把較小的包合并為一個包發送,默認為開啟
28 hash-max-zipmap-entries 64 hash-max-zipmap-value 512 指定在超過一定的數量或者最大的元素超過某一臨界值時,采用一種特殊的哈希算法
29 activerehashing yes 指定是否激活重置哈希,默認為開啟(后面在介紹 Redis 的哈希算法時具體介紹)
30 include /path/to/local.conf 指定包含其它的配置文件,可以在同一主機上多個Redis實例之間使用同一份配置文件,而同時各個實例又擁有自己的特定配置文件

更多信息可參考:https://www.runoob.com/redis/redis-conf.html

3.2 設置密碼和驗證

在配置文件中配置requirepass的密碼(當redis重啟時密碼依然有效)。

redis 127.0.0.1:6379> config set requirepass mypass

查詢密碼:

   redis 127.0.0.1:6379> config get requirepass
   (error) ERR operation not permitted

密碼驗證:

   redis 127.0.0.1:6379> auth mypass
   OK

再次查詢:

   redis 127.0.0.1:6379> config get requirepass
   1) "requirepass"
   2) "mypass"

PS:如果配置文件中沒添加密碼 那么redis重啟后,密碼失效;

如果需要在遠程 redis 服務上執行命令,同樣我們使用的也是 redis-cli 命令。

$ redis-cli -h host -p port -a password

【實例】
以下實例演示了如何連接到主機為 127.0.0.1,端口為 6379 ,密碼為 mypass 的 redis 服務上。

$redis-cli -h 127.0.0.1 -p 6379 -a "mypass"
redis 127.0.0.1:6379>

先登陸后驗證:

redis 127.0.0.1:6379> auth "mypass"
OK

AUTH命令跟其他redis命令一樣,是沒有加密的;阻止不了攻擊者在網絡上竊取你的密碼;

3.3 REDIS支持的類型

Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

<1> String(字符串)

string 類型是 Redis 最基本的數據類型,string 類型的值最大能存儲 512MB。

各個數據類型應用場景:
https://www.runoob.com/redis/redis-data-types.html
【實例】

redis 127.0.0.1:6379> SET name "duncanwang"
OK
redis 127.0.0.1:6379> GET name 
"duncanwang"

<2>Hash(哈希)

Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用于存儲對象。

【實例】

127.0.0.1:6379> HMSET say field1 "Hello" field2 "world"
OK
127.0.0.1:6379> HMGET say field1
1) "Hello"
127.0.0.1:6379> HMGET say field2
1) "world"

實例中我們使用了 Redis HMSET, HGET 命令,HMSET 設置了兩個 field=>value 對, HGET 獲取對應 field 對應的 value。

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

<3> List(列表)

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

127.0.0.1:6379> LPUSH mylist "duncan"
(integer) 1
127.0.0.1:6379> LPUSH mylist "jenise"
(integer) 2
127.0.0.1:6379> LPUSH mylist "dijior"
(integer) 3
127.0.0.1:6379> LRANGE mylist 0 2
1) "dijior"
2) "jenise"
3) "duncan"

列表最多可存儲 232 - 1 元素 (4294967295, 每個列表可存儲40多億)。

<4> Set(集合)

Redis 的 Set 是 string 類型的無序集合。
集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是 O(1)。

SADD 命令
添加一個 string 元素到 key 對應的 set 集合中,成功返回 1,如果元素已經在集合中返回 0。

SADD key member

【實例】

127.0.0.1:6379> SADD myset "duncanwang"
(integer) 1
127.0.0.1:6379> SADD myset "jenise"
(integer) 1
127.0.0.1:6379> SADD myset "dejior"
(integer) 1
127.0.0.1:6379> SADD myset "duncanwang"
(integer) 0
127.0.0.1:6379> SMEMBERS myset
1) "dejior"
2) "jenise"
3) "duncanwang"

注意:以上實例中 rabitmq 添加了兩次,但根據集合內元素的唯一性,第二次插入的元素將被忽略。

集合中最大的成員數為 232 - 1(4294967295, 每個集合可存儲40多億個成員)

<5> zset(sorted set:有序集合)

Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。
不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。

zset的成員是唯一的,但分數(score)卻可以重復。

ZADD 命令
添加元素到集合,元素在集合中存在則更新對應score

ZADD key score member

【實例】

127.0.0.1:6379> ZADD myzset 0  "duncanwang"
(integer) 1
127.0.0.1:6379> ZADD myzset 1  "jenise"
(integer) 1
127.0.0.1:6379> ZADD myzset 2  "dejior"
(integer) 1
127.0.0.1:6379> ZADD myzset 1  "dejior"
(integer) 0
127.0.0.1:6379> ZRANGEBYSCORE myzset 0 3
1) "duncanwang"
2) "dejior"
3) "jenise"

3.4 Redis 發布訂閱

Redis 發布訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

Redis 客戶端可以訂閱任意數量的頻道。

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

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

【實例】
以下實例演示了發布訂閱是如何工作的。在我們實例中我們創建了訂閱頻道名為 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"

Redis 發布訂閱命令

下表列出了 redis 發布訂閱常用命令:

序號 命令 描述
1 PSUBSCRIBE pattern [pattern ...] 訂閱一個或多個符合給定模式的頻道。
2 PUBSUB subcommand [argument [argument ...]] 查看訂閱與發布系統狀態。
3 PUBLISH channel message 將信息發送到指定的頻道。
4 PUNSUBSCRIBE [pattern [pattern ...]] 退訂所有給定模式的頻道。
5 SUBSCRIBE channel [channel ...] 訂閱給定的一個或多個頻道的信息。
6 UNSUBSCRIBE [channel [channel ...]] 指退訂給定的頻道。

3.5 Redis 事務

Redis 事務可以一次執行多個命令, 并且帶有以下三個重要的保證:

批量操作在發送 EXEC 命令前被放入隊列緩存。
收到 EXEC 命令后進入事務執行,事務中任意命令執行失敗,其余的命令依然被執行。
在事務執行過程,其他客戶端提交的命令請求不會插入到事務執行命令序列中。
一個事務從開始到執行會經歷以下三個階段:

開始事務。
命令入隊。
執行事務。

實例

以下是一個事務的例子, 它先以 MULTI 開始一個事務, 然后將多個命令入隊到事務中, 最后由 EXEC 命令觸發事務, 一并執行事務中的所有命令:

redis 127.0.0.1:6379> MULTI
OK

redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED

redis 127.0.0.1:6379> GET book-name
QUEUED

redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED

redis 127.0.0.1:6379> SMEMBERS tag
QUEUED

redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
   2) "C++"
   3) "Programming"

單個 Redis 命令的執行是原子性的,但 Redis 沒有在事務上增加任何維持原子性的機制,所以 Redis 事務的執行并不是原子性的。

事務可以理解為一個打包的批量執行腳本,但批量指令并非原子化的操作,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成后續的指令不做。

Redis 事務命令

下表列出了 redis 事務的相關命令:

序號 命令 描述
1 DISCARD 取消事務,放棄執行事務塊內的所有命令。
2 EXEC 執行所有事務塊內的命令。
3 MULTI 標記一個事務塊的開始。
4 UNWATCH 取消 WATCH 命令對所有 key 的監視。
5 WATCH key [key ...] 監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那么事務將被打斷。

4. REDIS常見問題

4.1 如何能夠通過外網IP訪問redis服務器?

默認情況下,連接Redis只能通過本地(127.0.0.1)來連接,不能通過外部IP來訪問。為了支持外部IP訪問,需要做響應的調整。
(1) 確認虛擬主機的安全組放開了6379端口。
(2)注釋掉只能通過本地(127.0.0.1)配置
進入Redis目錄打開Redis.conf配置文件,注釋掉bind對應代碼。

vim /etc/redis/redis.conf

# bind 127.0.0.1
# 默認不是守護進程方式運行,修改為yes
daemonize yes
#禁用保護模式
protected-mode no

kill掉已啟動的進程,然后重啟Redis并指明配置文件:

redis-server /etc/redis/redis.conf

4.2 redis無法向磁盤寫入RDB的報錯

現象:
redis set failed: MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.
分析:
日志顯示:overcommit_memory被設置成0,redis后臺的保存操作在低可用內存的情況下會失敗。這個時候很清楚,并不是磁盤被占滿的緣故,事實上磁盤剩余量還很多。
查了下,內核參數 vm.overcommit_memory 接受三種取值:

0 – Heuristic overcommit handling. 這是缺省值,它允許overcommit,但過于明目張膽的overcommit會被拒絕,比如malloc一次性申請的內存大小就超過了系統總內存。Heuristic的意思是“試探式的”,內核利用某種算法(對該算法的詳細解釋請看文末)猜測你的內存申請是否合理,它認為不合理就會拒絕overcommit。
1 – Always overcommit. 允許overcommit,對內存申請來者不拒。
2 – Don’t overcommit. 禁止overcommit。
CommitLimit 就是overcommit的閾值,申請的內存總數超過CommitLimit的話就算是overcommit。
解決方案:
1、打開redis配置文件

$ sudo vi /etc/redis/redis.conf  # 注意vi后面有空格

在下圖此行中將yes改為no,保存退出

2、指定配置加載文件

$ sudo redis-server /etc/redis/redis.conf
$ redis-cli

以上就是解決redis無法寫入數據的問題。

4.2 redis如何查看所有鍵值的內容?

KEYS * 即可查看。

4.3 redis常見性能問題和解決方案?

(1) Master最好不要做任何持久化工作,如RDB內存快照和AOF日志文件
(2) 如果數據比較重要,某個Slave開啟AOF備份數據,策略設置為每秒同步一次
(3) 為了主從復制的速度和連接的穩定性,Master和Slave最好在同一個局域網內
(4) 盡量避免在壓力很大的主庫上增加從庫
(5) 主從復制不要用圖狀結構,用單向鏈表結構更為穩定,即:Master <- Slave1 <- Slave2 <- Slave3…
這樣的結構方便解決單點故障問題,實現Slave對Master的替換。如果Master掛了,可以立刻啟用Slave1做Master,其他不變。

4.4 MySQL里有2000w數據,redis中只存20w的數據,如何保證redis中的數據都是熱點數據?

相關知識:redis 內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。redis 提供 6種數據淘汰策略:
voltile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰;
volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰;
volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰;
allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰;
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
no-enviction(驅逐):禁止驅逐數據;

5.Redis面試題

(1)吐血整理60個Redis面試題,全網最全了
https://zhuanlan.zhihu.com/p/93515595
(2)面圈網-真題
http://www.mianshigee.com/question/search/?q=redis

6.參考

(1)官網
https://redis.io/
(2)redis中文網
http://www.redis.cn/documentation.html
(3)Redis 教程
https://www.runoob.com/redis/redis-tutorial.html
(4)Redis 服務器
https://www.runoob.com/redis/redis-server.html
(5)Redis 數據備份與恢復
https://www.runoob.com/redis/redis-backup.html
(6)Redis 持久化
一起看懂Redis兩種持久化方式的原理
https://segmentfault.com/a/1190000015983518?utm_source=tag-newest
(6) memcache和redis原理對比
https://www.kancloud.cn/mayan0718/php/555555
(7) Redis底層數據結構 - 跳躍表
http://www.lxweimin.com/p/0206ef2cffa4

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • NOSQL類型簡介鍵值對:會使用到一個哈希表,表中有一個特定的鍵和一個指針指向特定的數據,如redis,volde...
    MicoCube閱讀 4,078評論 2 27
  • redis是一個以key-value存儲的非關系型數據庫。有五種數據類型,string、hashes、list、s...
    林ze宏閱讀 1,023評論 0 0
  • 安全性 設置客戶端連接后進行任何其他指令前需要使用的密碼。 警告:因為redis 速度相當快,所以在一臺比較好的服...
    OzanShareing閱讀 1,832評論 1 7
  • 1 Redis介紹1.1 什么是NoSql為了解決高并發、高可擴展、高可用、大數據存儲問題而產生的數據庫解決方...
    克魯德李閱讀 5,371評論 0 36
  • 不想說話是真的 不想睡也是真的 不知道喜歡你是不是真的 不喜歡你離開是真的 不想你靠太近還是真的 以前的他太假 現...
    六六歡喜閱讀 335評論 0 0