1. Redis簡介及安裝
1.1 Redis 簡介
Redis 是完全開源免費的,遵守BSD協議,是一個高性能的key-value數據庫。
Redis 與其他 key - value 緩存產品有以下三個特點:
- Redis支持數據的持久化,可以將內存中的數據保存在磁盤中,重啟的時候可以再次加載進行使用。
- Redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
- Redis支持數據的備份,即master-slave模式的數據備份。
1.2 Redis 優勢
- 性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
- 豐富的數據類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操作。
- 原子 – Redis的所有操作都是原子性的,同時Redis還支持對幾個操作全並后的原子性執行。
- 豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性。
1.3 Redis與其他key-value存儲有什么不同?
-
Redis有着更為復雜的數據結構並且提供對他們的原子性操作,這是一個不同於其他數據庫的進化路徑。Redis的數據類型都是基於基本數據結構的同時對程序員透明,無需進行額外的抽象。
-
Redis運行在內存中但是可以持久化到磁盤,所以在對不同數據集進行高速讀寫時需要權衡內存,因為數據量不能大於硬件內存。在內存數據庫方面的另一個優點是,相比在磁盤上相同的復雜的數據結構,在內存中操作起來非常簡單,這樣Redis可以做很多內部復雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產生的,因為他們並不需要進行隨機訪問。
2. Redis基礎知識、數據類型、Keys的操作命令
2.1 數據類型
Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
2.2 Redis 鍵(key)
Redis 鍵命令用於管理 redis 的鍵。
語法
Redis 鍵命令的基本語法如下:
redis 127.0.0.1:6379> COMMAND KEY_NAME
實例
redis 127.0.0.1:6379> SET runoobkey redis OK redis 127.0.0.1:6379> DEL runoobkey (integer) 1
在以上實例中 DEL 是一個命令, runoobkey 是一個鍵。 如果鍵被刪除成功,命令執行后輸出 (integer) 1,否則將輸出 (integer) 0
2.2.1 Key命令
1 DEL key
該命令用於在 key 存在時刪除 key。
2 DUMP key
序列化給定 key ,並返回被序列化的值。
3 EXISTS key
檢查給定 key 是否存在。
4 EXPIRE key seconds
為給定 key 設置過期時間。
5 EXPIREAT key timestamp
EXPIREAT 的作用和 EXPIRE 類似,都用於為 key 設置過期時間。 不同在於 EXPIREAT 命令接受的時間參數是 UNIX 時間戳(unix timestamp)。
6 PEXPIRE key milliseconds
設置 key 的過期時間以毫秒計。
7 PEXPIREAT key milliseconds-timestamp
設置 key 過期時間的時間戳(unix timestamp) 以毫秒計
8 KEYS pattern
查找所有符合給定模式( pattern)的 key 。
9 MOVE key db
將當前數據庫的 key 移動到給定的數據庫 db 當中。
10 PERSIST key
移除 key 的過期時間,key 將持久保持。
11 PTTL key
以毫秒為單位返回 key 的剩余的過期時間。
12 TTL key
以秒為單位,返回給定 key 的剩余生存時間(TTL, time to live)。
13 RANDOMKEY
從當前數據庫中隨機返回一個 key 。
14 RENAME key newkey
修改 key 的名稱
15 RENAMENX key newkey
僅當 newkey 不存在時,將 key 改名為 newkey 。
16 TYPE key
返回 key 所儲存的值的類型。
3. Redis對不同數據類型的操作命令使用
3.1 String(字符串)
string是redis最基本的類型,你可以理解成與Memcached一模一樣的類型,一個key對應一個value。
string類型是二進制安全的。意思是redis的string可以包含任何數據。比如jpg圖片或者序列化的對象 。
string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。
實例
redis 127.0.0.1:6379> SET name "runoob" OK redis 127.0.0.1:6379> GET name "runoob"
在以上實例中我們使用了 Redis 的 SET 和 GET 命令。鍵為 name,對應的值為 runoob。
注意:一個鍵最大能存儲512MB。
3.2 Hash(哈希)
Redis hash 是一個鍵名對集合。
Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。
實例
127.0.0.1:6379> HMSET user:1 username runoob password runoob points 200 OK 127.0.0.1:6379> HGETALL user:1 1) "username" 2) "runoob" 3) "password" 4) "runoob" 5) "points" 6) "200"
以上實例中 hash 數據類型存儲了包含用戶腳本信息的用戶對象。 實例中我們使用了 Redis HMSET, HGETALL 命令,user:1為鍵值。
每個 hash 可以存儲 232 -1 鍵值對(40多億)。
3.3 List(列表)
Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。
實例
redis 127.0.0.1:6379> lpush runoob redis (integer) 1 redis 127.0.0.1:6379> lpush runoob mongodb (integer) 2 redis 127.0.0.1:6379> lpush runoob rabitmq (integer) 3 redis 127.0.0.1:6379> lrange runoob 0 10 1) "rabitmq" 2) "mongodb" 3) "redis" redis 127.0.0.1:6379>
列表最多可存儲 232 - 1 元素 (4294967295, 每個列表可存儲40多億)。
3.4 Set(集合)
Redis的Set是string類型的無序集合。
集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是O(1)。
sadd 命令
添加一個string元素到,key對應的set集合中,成功返回1,如果元素已經在集合中返回0,key對應的set不存在返回錯誤。
sadd key member
實例
redis 127.0.0.1:6379> sadd runoob redis (integer) 1 redis 127.0.0.1:6379> sadd runoob mongodb (integer) 1 redis 127.0.0.1:6379> sadd runoob rabitmq (integer) 1 redis 127.0.0.1:6379> sadd runoob rabitmq (integer) 0 redis 127.0.0.1:6379> smembers runoob 1) "rabitmq" 2) "mongodb" 3) "redis"
注意:以上實例中 rabitmq 添加了兩次,但根據集合內元素的唯一性,第二次插入的元素將被忽略。
集合中最大的成員數為 232 - 1(4294967295, 每個集合可存儲40多億個成員)。
3.5 zset(sorted set:有序集合)
Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。
不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。
zset的成員是唯一的,但分數(score)卻可以重復。
zadd 命令
添加元素到集合,元素在集合中存在則更新對應score
zadd key score member
實例
redis 127.0.0.1:6379> zadd runoob 0 redis (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 mongodb (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 rabitmq (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 rabitmq (integer) 0 redis 127.0.0.1:6379> ZRANGEBYSCORE runoob 0 1000 1) "redis" 2) "mongodb" 3) "rabitmq"
4. Redis核心配置分析
Redis 的配置文件位於 Redis 安裝目錄下,文件名為 redis.conf。
你可以通過 CONFIG 命令查看或設置配置項。
語法
Redis CONFIG 命令格式如下:
redis 127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME
實例
redis 127.0.0.1:6379> CONFIG GET loglevel 1) "loglevel" 2) "notice"
使用 * 號獲取所有配置項:
實例
redis 127.0.0.1:6379> CONFIG GET *
1) "dbfilename"
2) "dump.rdb"
3) "requirepass"
4) ""
5) "masterauth"
6) ""
7) "unixsocket"
8) ""
9) "logfile"
10) ""
11) "pidfile"
12) "/var/run/redis.pid"
13) "maxmemory"
14) "0"
15) "maxmemory-samples"
16) "3"
17) "timeout"
18) "0"
19) "tcp-keepalive"
20) "0"
21) "auto-aof-rewrite-percentage"
22) "100"
23) "auto-aof-rewrite-min-size"
24) "67108864"
25) "hash-max-ziplist-entries"
26) "512"
27) "hash-max-ziplist-value"
28) "64"
29) "list-max-ziplist-entries"
30) "512"
31) "list-max-ziplist-value"
32) "64"
33) "set-max-intset-entries"
34) "512"
35) "zset-max-ziplist-entries"
36) "128"
37) "zset-max-ziplist-value"
38) "64"
39) "hll-sparse-max-bytes"
40) "3000"
41) "lua-time-limit"
42) "5000"
43) "slowlog-log-slower-than"
44) "10000"
45) "latency-monitor-threshold"
46) "0"
47) "slowlog-max-len"
48) "128"
49) "port"
50) "6379"
51) "tcp-backlog"
52) "511"
53) "databases"
54) "16"
55) "repl-ping-slave-period"
56) "10"
57) "repl-timeout"
58) "60"
59) "repl-backlog-size"
60) "1048576"
61) "repl-backlog-ttl"
62) "3600"
63) "maxclients"
64) "4064"
65) "watchdog-period"
66) "0"
67) "slave-priority"
68) "100"
69) "min-slaves-to-write"
70) "0"
71) "min-slaves-max-lag"
72) "10"
73) "hz"
74) "10"
75) "no-appendfsync-on-rewrite"
76) "no"
77) "slave-serve-stale-data"
78) "yes"
79) "slave-read-only"
80) "yes"
81) "stop-writes-on-bgsave-error"
82) "yes"
83) "daemonize"
84) "no"
85) "rdbcompression"
86) "yes"
87) "rdbchecksum"
88) "yes"
89) "activerehashing"
90) "yes"
91) "repl-disable-tcp-nodelay"
92) "no"
93) "aof-rewrite-incremental-fsync"
94) "yes"
95) "appendonly"
96) "no"
97) "dir"
98) "/home/deepak/Downloads/redis-2.8.13/src"
99) "maxmemory-policy"
100) "volatile-lru"
101) "appendfsync"
102) "everysec"
103) "save"
104) "3600 1 300 100 60 10000"
105) "loglevel"
106) "notice"
107) "client-output-buffer-limit"
108) "normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60"
109) "unixsocketperm"
110) "0"
111) "slaveof"
112) ""
113) "notify-keyspace-events"
114) ""
115) "bind"
116) ""
4.1 編輯配置
你可以通過修改 redis.conf 文件或使用 CONFIG set 命令來修改配置。
語法
CONFIG SET 命令基本語法:
redis 127.0.0.1:6379> CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE
實例
redis 127.0.0.1:6379> CONFIG SET loglevel "notice" OK redis 127.0.0.1:6379> CONFIG GET loglevel 1) "loglevel" 2) "notice"
4.2 參數說明
redis.conf 配置項說明如下:
1. Redis默認不是以守護進程的方式運行,可以通過該配置項修改,使用yes啟用守護進程
daemonize no
2. 當Redis以守護進程方式運行時,Redis默認會把pid寫入/var/run/redis.pid文件,可以通過pidfile指定
pidfile /var/run/redis.pid
3. 指定Redis監聽端口,默認端口為6379,作者在自己的一篇博文中解釋了為什么選用6379作為默認端口,因為6379在手機按鍵上MERZ對應的號碼,而MERZ取自意大利歌女Alessia Merz的名字
port 6379
4. 綁定的主機地址
bind 127.0.0.1
5.當 客戶端閑置多長時間后關閉連接,如果指定為0,表示關閉該功能
timeout 300
6. 指定日志記錄級別,Redis總共支持四個級別:debug、verbose、notice、warning,默認為verbose
loglevel verbose
7. 日志記錄方式,默認為標准輸出,如果配置Redis為守護進程方式運行,而這里又配置為日志記錄方式為標准輸出,則日志將會發送給/dev/null
logfile stdout
8. 設置數據庫的數量,默認數據庫為0,可以使用SELECT <dbid>命令在連接上指定數據庫id
databases 16
9. 指定在多長時間內,有多少次更新操作,就將數據同步到數據文件,可以多個條件配合
save <seconds> <changes>
Redis默認配置文件中提供了三個條件:
save 900 1
save 300 10
save 60 10000
分別表示900秒(15分鍾)內有1個更改,300秒(5分鍾)內有10個更改以及60秒內有10000個更改。
10. 指定存儲至本地數據庫時是否壓縮數據,默認為yes,Redis采用LZF壓縮,如果為了節省CPU時間,可以關閉該選項,但會導致數據庫文件變的巨大
rdbcompression yes
11. 指定本地數據庫文件名,默認值為dump.rdb
dbfilename dump.rdb
12. 指定本地數據庫存放目錄
dir ./
13. 設置當本機為slav服務時,設置master服務的IP地址及端口,在Redis啟動時,它會自動從master進行數據同步
slaveof <masterip> <masterport>
14. 當master服務設置了密碼保護時,slav服務連接master的密碼
masterauth <master-password>
15. 設置Redis連接密碼,如果配置了連接密碼,客戶端在連接Redis時需要通過AUTH <password>命令提供密碼,默認關閉
requirepass foobared
16. 設置同一時間最大客戶端連接數,默認無限制,Redis可以同時打開的客戶端連接數為Redis進程可以打開的最大文件描述符數,如果設置 maxclients 0,表示不作限制。當客戶端連接數到達限制時,Redis會關閉新的連接並向客戶端返回max number of clients reached錯誤信息
maxclients 128
17. 指定Redis最大內存限制,Redis在啟動時會把數據加載到內存中,達到最大內存后,Redis會先嘗試清除已到期或即將到期的Key,當此方法處理 后,仍然到達最大內存設置,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把Key存放內存,Value會存放在swap區
maxmemory <bytes>
18. 指定是否在每次更新操作后進行日志記錄,Redis在默認情況下是異步的把數據寫入磁盤,如果不開啟,可能會在斷電時導致一段時間內的數據丟失。因為 redis本身同步數據文件是按上面save條件來同步的,所以有的數據會在一段時間內只存在於內存中。默認為no
appendonly no
19. 指定更新日志文件名,默認為appendonly.aof
appendfilename appendonly.aof
20. 指定更新日志條件,共有3個可選值:
no:表示等操作系統進行數據緩存同步到磁盤(快)
always:表示每次更新操作后手動調用fsync()將數據寫到磁盤(慢,安全)
everysec:表示每秒同步一次(折衷,默認值)
appendfsync everysec
21. 指定是否啟用虛擬內存機制,默認值為no,簡單的介紹一下,VM機制將數據分頁存放,由Redis將訪問量較少的頁即冷數據swap到磁盤上,訪問多的頁面由磁盤自動換出到內存中(在后面的文章我會仔細分析Redis的VM機制)
vm-enabled no
22. 虛擬內存文件路徑,默認值為/tmp/redis.swap,不可多個Redis實例共享
vm-swap-file /tmp/redis.swap
23. 將所有大於vm-max-memory的數據存入虛擬內存,無論vm-max-memory設置多小,所有索引數據都是內存存儲的(Redis的索引數據 就是keys),也就是說,當vm-max-memory設置為0的時候,其實是所有value都存在於磁盤。默認值為0
vm-max-memory 0
24. Redis swap文件分成了很多的page,一個對象可以保存在多個page上面,但一個page上不能被多個對象共享,vm-page-size是要根據存儲的 數據大小來設定的,作者建議如果存儲很多小對象,page大小最好設置為32或者64bytes;如果存儲很大大對象,則可以使用更大的page,如果不 確定,就使用默認值
vm-page-size 32
25. 設置swap文件中的page數量,由於頁表(一種表示頁面空閑或使用的bitmap)是在放在內存中的,,在磁盤上每8個pages將消耗1byte的內存。
vm-pages 134217728
26. 設置訪問swap文件的線程數,最好不要超過機器的核數,如果設置為0,那么所有對swap文件的操作都是串行的,可能會造成比較長時間的延遲。默認值為4
vm-max-threads 4
27. 設置在向客戶端應答時,是否把較小的包合並為一個包發送,默認為開啟
glueoutputbuf yes
28. 指定在超過一定的數量或者最大的元素超過某一臨界值時,采用一種特殊的哈希算法
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
29. 指定是否激活重置哈希,默認為開啟(后面在介紹Redis的哈希算法時具體介紹)
activerehashing yes
30. 指定包含其它的配置文件,可以在同一主機上多個Redis實例之間使用同一份配置文件,而同時各個實例又擁有自己的特定配置文件
include /path/to/local.conf
5. Redis持久化概述,RDB原理、AOF原理分析
由於Redis是基於內存的數據庫,為了保證數據的可用性,Redis提供了兩種數據持久化機制:RDB和AOF,下面對這兩種持久化方式加以分析。
5.1 RDB
運行原理
RDB模式可以在指定的時間間隔內生成內存中整個數據集的持久化快照。快照文件默認被存儲在當前文件夾中,名稱為dump.rdb,可以通過dir和dbfilename參數來修改默認值。
1.redis調用fork函數復制當前進行的一個副本-子進程 2.父進程繼續接收並處理客戶端發來的命令 3.子進行將內存中的數據寫入一個臨時的dump文件 4.子進程寫入完成后,會用新的臨時dump文件替換就的rdb文件 5.一次持久化完成
- 1
- 2
- 3
- 4
- 5
在執行fork函數的時候,操作系統會使用寫時復制(copy-on-write)策略,也就是說在調用fork的一刻,父子進行有相同的內存模型,當父進程要修改其中的某片數據時,操作系統會將該片數據復制一份,從而保證不影響子進程。
rdb文件是經過壓縮的文件,占用的空間比較小,更有利於傳輸,並且數據恢復速度也比較快。
RDB模式的優點
1.rdb持久化文件很緊湊,占用空間更小。
2.rdb保存的是基於時間點的數據快照,更適合數據的備份和容災
3.利用rdb文件進行數據恢復時,速度更快
RDB模式的缺點
1.會造成部分數據的丟失
2.當數據集非常大時,fork操作會占用很多系統資源,造成主服務進程假死
RDB模式適用的場景
1.數據備份
2.可容忍部分數據丟失
3.跨數據中心的容災備份
5.2 AOF
aof持久化 記錄服務器的所有寫操作,並在服務器啟動時重新執行這些命令來恢復數據集。aof文件中的命令全部以redis的協議格式存儲,新命令會追加到文件的末尾,同時,redis還會在后台對aof文件進行重寫,使得aof文件的體積不會過大。
aof機制默認關閉,可以通過appendonly = yes
參數開啟aof機制,通過appendfilename = myaoffile.aof
指定aof文件名稱。
對於觸發aof重寫機制也可以通過配置文件來進行設置:
auto-aof-rewrite-percenttage = 100 auto-aof-rewrite-min-size 64mb
- 1
- 2
第一個參數是配置較前一個aof文件大小增長的百分比,第二個參數是配置觸發aof重寫的aof的最小的大小。
修改aof的fsync策略:
appendfsync=always 同步持久化每一次修改操作 appendfsync=everysec 每秒想aof文件同步一次 appendfsync=no 關閉向aof文件寫入修改
- 1
- 2
- 3
aof的優點
1.支持不同的fsync策略:no/always/everysec
2.能夠記錄所有寫操作,不會造成數據丟失
3.aof重寫機制確保aof文件不會過大
4.aof文件可以很容易的讀懂
aof的缺點
1.雖然有aof重寫機制,單aof文件通常比rdb文件大
2.在不同的fsync策略寫,redis性能會受到一定影響
6. Redis事務操作分析以及發布訂閱模式的操作使用
6.1 Redis 事務
Redis 事務可以一次執行多個命令, 並且帶有以下兩個重要的保證:
- 事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。
- 事務是一個原子操作:事務中的命令要么全部被執行,要么全部都不執行。
一個事務從開始到執行會經歷以下三個階段:
- 開始事務。
- 命令入隊。
- 執行事務。
6.1.1 實例
以下是一個事務的例子, 它先以 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"
6.1.2 事務命令
1 DISCARD
取消事務,放棄執行事務塊內的所有命令。
2 EXEC
執行所有事務塊內的命令。
3 MULTI
標記一個事務塊的開始。
4 UNWATCH
取消 WATCH 命令對所有 key 的監視。
5 WATCH key [key ...]
監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那么事務將被打斷。
6.2 Redis 發布訂閱
Redis 發布訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。
Redis 客戶端可以訂閱任意數量的頻道。
下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關系:
當有新消息通過 PUBLISH 命令發送給頻道 channel1 時, 這個消息就會被發送給訂閱它的三個客戶端:
6.2.1 實例
以下實例演示了發布訂閱是如何工作的。在我們實例中我們創建了訂閱頻道名為 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"
6.2.2 發布訂閱命令
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 ...]]
指退訂給定的頻道。
7. Redis集群搭建
8. Redis主從復制原理分析
9. Redis的優化建議,最佳實踐
1、停止使用 KEYS *
Okay,以挑戰這個命令開始這篇文章,或許並不是一個好的方式,但其確實可能是最重要的一點。很多時候當我們關注一個redis實例的統計數據,我們會快速地輸入”KEYS *”命令,這樣key的信息會很明顯地展示出來。平心而論,從程序化的角度出發往往傾向於寫出下面這樣的偽代碼:
for key in'keys *':
doAllTheThings()
但是當你有1300萬個key時,執行速度將會變慢。因為KEYS命令的時間復雜度是O(n),其中n是要返回的keys的個數,這樣這個命令的復雜度就取決於數據庫的大小了。並且在這個操作執行期間,其它任何命令在你的實例中都無法執行。
作為一個替代命令,看一下 SCAN 吧,其允許你以一種更友好的方式來執行… SCAN 通過增量迭代的方式來掃描數據庫。這一操作基於游標的迭代器來完成的,因此只要你覺得合適,你可以隨時停止或繼續。
2、找出拖慢 Redis 的罪魁禍首
由於 Redis 沒有非常詳細的日志,要想知道在 Redis 實例內部都做了些什么是非常困難的。幸運的是 Redis 提供了一個下面這樣的命令統計工具:
127.0.0.1:6379> INFO commandstats
# Commandstats
cmdstat_get:calls=78,usec=608,usec_per_call=7.79
cmdstat_setex:calls=5,usec=71,usec_per_call=14.20
cmdstat_keys:calls=2,usec=42,usec_per_call=21.00
cmdstat_info:calls=10,usec=1931,usec_per_call=193.10
通過這個工具可以查看所有命令統計的快照,比如命令執行了多少次,執行命令所耗費的毫秒數(每個命令的總時間和平均時間)
只需要簡單地執行 CONFIG RESETSTAT 命令就可以重置,這樣你就可以得到一個全新的統計結果。
3、 將 Redis-Benchmark 結果作為參考,而不要一概而論
Redis 之父 Salvatore 就說過:“通過執行GET/SET命令來測試Redis就像在雨天檢測法拉利的雨刷清潔鏡子的效果”。很多時候人們跑到我這里,他們想知道為什么自己的Redis-Benchmark統計的結果低於最優結果 。但我們必須要把各種不同的真實情況考慮進來,例如:
- 可能受到哪些客戶端運行環境的限制?
- 是同一個版本號嗎?
- 測試環境中的表現與應用將要運行的環境是否一致?
Redis-Benchmark的測試結果提供了一個保證你的 Redis-Server 不會運行在非正常狀態下的基准點,但是你永遠不要把它作為一個真實的“壓力測試”。壓力測試需要反應出應用的運行方式,並且需要一個盡可能的和生產相似的環境。
4、Hashes 是你的最佳選擇
以一種優雅的方式引入 hashes 吧。hashes 將會帶給你一種前所未有的體驗。之前我曾看到過許多類似於下面這樣的key結構:
foo:first_name
foo:last_name
foo:address
上面的例子中,foo 可能是一個用戶的用戶名,其中的每一項都是一個單獨的 key。這就增加了 犯錯的空間,和一些不必要的 key。使用 hash 代替吧,你會驚奇地發現竟然只需要一個 key :
127.0.0.1:6379> HSET foo first_name "Joe"(integer) 1
127.0.0.1:6379> HSET foo last_name "Engel"(integer) 1
127.0.0.1:6379> HSET foo address "1 Fanatical Pl"(integer) 1
127.0.0.1:6379> HGETALL foo
1)"first_name"
2)"Joe"
3)"last_name"
4)"Engel"
5)"address"
6)"1 Fanatical Pl"
127.0.0.1:6379> HGET foo first_name
"Joe"
5、設置 key 值的存活時間
無論什么時候,只要有可能就利用key超時的優勢。一個很好的例子就是儲存一些諸如臨時認證key之類的東西。當你去查找一個授權key時——以OAUTH為例——通常會得到一個超時時間。這樣在設置key的時候,設成同樣的超時時間,Redis就會自動為你清除!而不再需要使用KEYS *來遍歷所有的key了,怎么樣很方便吧?
6、 選擇合適的回收策略
既然談到了清除key這個話題,那我們就來聊聊回收策略。當 Redis 的實例空間被填滿了之后,將會嘗試回收一部分key。根據你的使用方式,我強烈建議使用 volatile-lru 策略——前提是你對key已經設置了超時。但如果你運行的是一些類似於 cache 的東西,並且沒有對 key 設置超時機制,可以考慮使用 allkeys-lru 回收機制。我的建議是先在這里查看一下可行的方案。
7、如果你的數據很重要,請使用 Try/Except
如果必須確保關鍵性的數據可以被放入到 Redis 的實例中,我強烈建議將其放入 try/except 塊中。幾乎所有的Redis客戶端采用的都是“發送即忘”策略,因此經常需要考慮一個 key 是否真正被放到 Redis 數據庫中了。至於將 try/expect 放到 Redis 命令中的復雜性並不是本文要講的,你只需要知道這樣做可以確保重要的數據放到該放的地方就可以了。
8、不要耗盡一個實例
無論什么時候,只要有可能就分散多redis實例的工作量。從3.0.0版本開始,Redis就支持集群了。Redis集群允許你基於key范圍分離出部分包含主/從模式的key。完整的集群背后的“魔法”可以在這里找到。但如果你是在找教程,那這里是一個再適合不過的地方了。如果不能選擇集群,考慮一下命名空間吧,然后將你的key分散到多個實例之中。關於怎樣分配數據,在redis.io網站上有這篇精彩的評論。
9、內核越多越好嗎?!
當然是錯的。Redis 是一個單線程進程,即使啟用了持久化最多也只會消耗兩個內核。除非你計划在一台主機上運行多個實例——希望只會是在開發測試的環境下!——否則的話對於一個 Redis 實例是不需要2個以上內核的。
10、高可用
到目前為止 Redis Sentinel 已經經過了很全面的測試,很多用戶已經將其應用到了生產環境中(包括 ObjectRocket )。如果你的應用重度依賴於 Redis ,那就需要想出一個高可用方案來保證其不會掉線。當然,如果不想自己管理這些東西,ObjectRocket 提供了一個高可用平台,並提供7×24小時的技術支持,有意向的話可以考慮一下。
10. Redis的JAVA客戶端使用
使用 jedis.jar
鏈接測試:
package redis; import redis.clients.jedis.Jedis; public class RedisJava { public static void main(String[] args) { //連接本地的 Redis 服務 Jedis jedis = new Jedis("localhost"); System.out.println("連接成功"); //查看服務是否運行 System.out.println("服務正在運行: "+jedis.ping()); jedis.close(); } }
String:
package redis; import redis.clients.jedis.Jedis; public class RedisStringJava { public static void main(String[] args) { //連接本地的 Redis 服務 Jedis jedis = new Jedis("localhost"); System.out.println("連接成功"); //設置 redis 字符串數據 jedis.set("name", "loveincode"); // 獲取存儲的數據並輸出 System.out.println("redis 存儲的字符串為: "+ jedis.get("name")); jedis.close(); } }
11. Redis集成Spring的使用
學習筆記部分來自菜鳥教程:http://www.runoob.com/redis/ 、redis持久化:http://blog.csdn.net/zhangdong2012/article/details/53116213