Redis基礎(chǔ)知識(一)
微信公眾號:運(yùn)維開發(fā)故事,作者:wanger
Redis簡介
Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協(xié)議、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value 數(shù)據(jù)庫,并提供多種語言的 API。
它通常被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,因?yàn)橹?value)可以是 字符串(String), 哈希(Map),列表(list),集合(sets)和 有序集合(sorted sets)等類型。
Redis安裝
$ wget http://download.redis.io/releases/redis-5.0.5.tar.gz
$ tar xzf redis-5.0.5.tar.gz
$ cd redis-5.0.5
$ make
以后臺方式啟動Redis
修改Redis.conf文件
將daemonize on
修改為
daemonize yes
啟動Redis
src/redis-server redis.conf
開機(jī)啟動Redis
執(zhí)行安裝腳本,一直默認(rèn)就可以
./utils/install_server.sh
mv /etc/init.d/redis_6379 /etc/init.d/redis
設(shè)置Redis密碼
vim /etc/redis/6379.conf
requirepass redispass
service redis restart
再次連接發(fā)現(xiàn)需要輸入密碼
Redis命令
全局命令
獲取鍵
keys pattern
keys還支持通配符
127.0.0.1:6379> set we "hello"
OK
127.0.0.1:6379> keys *
1) "we"
127.0.0.1:6379> set name wanger
OK
127.0.0.1:6379> keys name
1) "name"
127.0.0.1:6379> keys *
1) "name"
2) "we"
keys 命令遍歷了Redis中所有的鍵,當(dāng)鍵的數(shù)量過多時會影響Redis性能
刪除鍵
del key1 key2 ..
例如:
127.0.0.1:6379> keys *
1) "qwe"
2) "asd"
3) "we"
127.0.0.1:6379> del asd qwe
(integer) 2
127.0.0.1:6379> keys *
1) "we"
判斷鍵是否存在
exists key1 key2
例如:
127.0.0.1:6379> exists we
(integer) 1
127.0.0.1:6379> exists name
(integer) 0
127.0.0.1:6379> set qwe 2
OK
127.0.0.1:6379> exists we qwe
(integer) 2
127.0.0.1:6379> exists we name
(integer) 1
獲取鍵的總數(shù)
dbsize
例如:
127.0.0.1:6379> dbsize
(integer) 2
127.0.0.1:6379> keys *
1) "qwe"
2) "we"
獲取鍵的數(shù)據(jù)類型
type key
例如:
127.0.0.1:6379> type we
string
127.0.0.1:6379> lpush list1 1 2 3
(integer) 3
127.0.0.1:6379> type list1
list
對列表、集合、有序集合的元素進(jìn)行排序
sort key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
例如:
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "7"
3) "2"
4) "4"
5) "3"
6) "1"
sort list desc limit 0 5
1) "7"
2) "5"
3) "4"
4) "4"
5) "3"
127.0.0.1:6379> lpush list2 asd qwe zxc
(integer) 3
sort list2 desc limit 0 5 alpha
1) "zxc"
2) "qwe"
3) "asd"
清空數(shù)據(jù)庫
flushdb //清空當(dāng)前數(shù)據(jù)庫
flushall //清空所有數(shù)據(jù)庫
例如:
127.0.0.1:6379[11]> set a 1
OK
127.0.0.1:6379[11]> get a
"1"
127.0.0.1:6379[11]> flushdb
OK
127.0.0.1:6379[11]> get a
(nil)
將指定的鍵移動到其他數(shù)據(jù)庫
move key db
例如:
127.0.0.1:6379[11]> set a 1
OK
127.0.0.1:6379[11]> move a 2
(integer) 1
127.0.0.1:6379[11]> select 2
OK
127.0.0.1:6379[2]> get a
"1"
字符串
字符串類型是Redis最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),字符串類型是其他幾種數(shù)據(jù)類型的基礎(chǔ),他能存儲任何形式的字符串,包括二進(jìn)制數(shù)據(jù)
設(shè)值取值
set key value [EX seconds] [PX milliseconds] [NX|XX]
get key
-
nx:
鍵必須不存在,才可以設(shè)置成功,用于添加。
-
xx:
與nx相反,鍵必須存在,才可以設(shè)置成功,用于更新
例如:
127.0.0.1:6379> set name wanger
OK
127.0.0.1:6379> get name
"wanger"
127.0.0.1:6379> setnx name wanger
(integer) 0
127.0.0.1:6379> set name wang xx
OK
批量設(shè)值取值
mset key1 value1 key2 value2 ..
mget key1 key2
例如:
127.0.0.1:6379> mset key1 1 key2 2
OK
127.0.0.1:6379> mget key1 key2
1) "1"
2) "2"
對鍵值自增自減
incr key
decr key
例如:
127.0.0.1:6379> incr key1
(integer) 2
127.0.0.1:6379> incr key2
(integer) 3
127.0.0.1:6379> get key1
"2"
127.0.0.1:6379> get key2
"3"
127.0.0.1:6379> get we
"hello"
127.0.0.1:6379> incr we
(error) ERR value is not an integer or out of range
127.0.0.1:6379> decr key1
(integer) 1
127.0.0.1:6379> decr key2
(integer) 2
追加值
append key value
例如:
127.0.0.1:6379> append key hello
(integer) 5
127.0.0.1:6379> append key world
(integer) 10
127.0.0.1:6379> get key
"helloworld"
獲取字符串長度
strlen key
例如:
127.0.0.1:6379> get key
"helloworld"
127.0.0.1:6379> strlen key
(integer) 10
127.0.0.1:6379> set name "王二"
OK
127.0.0.1:6379> strlen name
(integer) 6
設(shè)置和獲取指定位置的字符串
setrange key offset value
getrange key start end
例如:
127.0.0.1:6379> SET key1 "Hello World"
OK
127.0.0.1:6379> setrange key1 6 "Redis"
(integer) 11
127.0.0.1:6379> get key1
"Hello Redis"
127.0.0.1:6379> getrange key1 6 12
"Redis"
字符串對象編碼
字符串類型的內(nèi)部編碼有3種:
-
int:
8個字節(jié)的長整型。
-
embstr:
小于等于39個字節(jié)的字符串。
-
raw:
大于39個字節(jié)的字符串。
例如:
127.0.0.1:6379> set num 123456
OK
127.0.0.1:6379> object encoding num
"int"
127.0.0.1:6379> set short qweasd
OK
127.0.0.1:6379> object encoding short
"embstr"
127.0.0.1:6379> set raw "when you love me I have lost of plot wow wow"
OK
127.0.0.1:6379> object encoding raw
"raw"
列表
Redis列表可以存儲一個有序的字符串列表,內(nèi)部使用雙向鏈表實(shí)現(xiàn),雙向鏈表作為一種常見的數(shù)據(jù)結(jié)構(gòu),雙向鏈表的每個數(shù)據(jù)節(jié)點(diǎn)都有兩個指針,分別指向后繼與前驅(qū)節(jié)點(diǎn),從雙向鏈表中的任意一個節(jié)點(diǎn)開始都可以很方便地訪問其前驅(qū)與后繼節(jié)點(diǎn),因此獲取越接近兩端的元素就越快
從左右兩邊插入元素或者從某一個元素前后插入數(shù)據(jù)
lpush key value1 value2 value3
rpush key value1 value2 value3
linsert key BEFORE|AFTER pivot value
例如:
127.0.0.1:6379> lpush names 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange names 0 4
1) "4"
2) "3"
3) "2"
4) "1"
127.0.0.1:6379> rpush nums 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange nums 0 4
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> linsert nums before 2 5
(integer) 5
127.0.0.1:6379> lrange nums 0 5
1) "1"
2) "5"
3) "2"
4) "3"
5) "4"
從列表兩端刪除元素
lpop key
rpop key
例如:
127.0.0.1:6379> lrange nums 0 5
1) "1"
2) "5"
3) "2"
4) "3"
5) "4"
127.0.0.1:6379> lpop nums
"1"
127.0.0.1:6379> rpop nums
"4"
127.0.0.1:6379> lrange nums 0 5
1) "5"
2) "2"
3) "3"
獲取給定位置上的元素
lindex key index
例如:
127.0.0.1:6379> lrange nums 0 5
1) "5"
2) "2"
3) "3"
127.0.0.1:6379> lindex nums 2
"3"
127.0.0.1:6379> lindex nums 1
"2"
127.0.0.1:6379> lindex nums -1
"3"
獲取給定范圍的元素
lrange key start stop
例如:
127.0.0.1:6379> lrange nums 0 1
1) "5"
2) "2"
127.0.0.1:6379> lrange nums 0 2
1) "5"
2) "2"
3) "3"
獲取列表長度
llen key
例如:
127.0.0.1:6379> lrange nums 0 3
1) "5"
2) "2"
3) "3"
127.0.0.1:6379> llen nums
(integer) 3
從列表中刪除值
lrem key count value
-
count > 0:
刪除數(shù)量為count的從頭到尾移動的值為value的元素。
-
count < 0:
刪除數(shù)量為count的從尾到頭移動的值為value的元素。
-
count = 0:
刪除所有等于value的元素。
例如:
127.0.0.1:6379> lrange mylist 0 10
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "2"
7) "3"
8) "4"
9) "5"
10) "5"
127.0.0.1:6379> lrem mylist 1 5
(integer) 1
127.0.0.1:6379> lrange mylist 0 10
1) "1"
2) "2"
3) "3"
4) "4"
5) "2"
6) "3"
7) "4"
8) "5"
9) "5"
127.0.0.1:6379> lrem mylist -2 5
(integer) 2
127.0.0.1:6379> lrange mylist 0 10
1) "1"
2) "2"
3) "3"
4) "4"
5) "2"
6) "3"
7) "4"
127.0.0.1:6379> lrem mylist 0 2
(integer) 2
127.0.0.1:6379> lrange mylist 0 11
1) "1"
2) "3"
3) "4"
4) "3"
5) "4"
修改指定索引的元素
lset key index value
例如:
127.0.0.1:6379> lrange mylist 0 6
1) "1"
2) "3"
3) "4"
4) "3"
5) "4"
127.0.0.1:6379> lset mylist 1 5
OK
127.0.0.1:6379> lrange mylist 0 6
1) "1"
2) "5"
3) "4"
4) "3"
5) "4"
阻塞操作
blpop和brpop分別是lpop和rpop的阻塞版本,功能類似,當(dāng)列表為空時,會發(fā)生阻塞,timeout可定義阻塞時間,timeout為0時將一直阻塞,直到在另一個客戶端中往列表中加入元素
blpop key1 key2 timeout
brpop key1 key2 timeout
例如:
127.0.0.1:6379> lrange list2 0 4
1) "4"
2) "3"
3) "2"
127.0.0.1:6379> lrange list1 0 4
1) "8"
2) "7"
127.0.0.1:6379> blpop list1 list2 0
1) "list1"
2) "8"
127.0.0.1:6379> brpop list1 list2 0
1) "list1"
2) "7"
127.0.0.1:6379> brpop list1 list2 0
1) "list2"
2) "2"
127.0.0.1:6379> brpop list1 list2 0
1) "list2"
2) "3"
127.0.0.1:6379> brpop list1 list2 0
1) "list2"
2) "4"
127.0.0.1:6379> brpop list1 list2 0
1) "list2"
2) "1"
(18.49s)
在另一個客戶端執(zhí)行
127.0.0.1:6379> lpush list2 1
(integer) 1
列表內(nèi)部編碼
-
ziplist(壓縮列表):
列表元素保存的所有字符串元素的長度都小于64字節(jié)且元素數(shù)量小于512個時使用ziplist編碼
-
linkedlist(鏈表):
當(dāng)列表類型無法滿足兩個條件的任意一個的時候,redis會使用linkedlist作為列表的內(nèi)部實(shí)現(xiàn)
-
quicklist:
list的內(nèi)部實(shí)現(xiàn)quicklist是一個ziplist的雙向鏈表,雙向鏈表是由多個節(jié)點(diǎn)(Node)組成的,quicklist的每個節(jié)點(diǎn)都是一個ziplist。
參考張鐵蕾http://zhangtielei.com/posts/blog-redis-quicklist.html
哈希
哈希是由與值關(guān)聯(lián)的字段組成的映射。字段和值都是字符串,哈希類型中的映射關(guān)系叫作field-value
設(shè)值取值
hset key field value
hget key field
例如:
127.0.0.1:6379> hset ha name wanger
(integer) 1
127.0.0.1:6379> hget ha name
"wanger"
批量設(shè)值取值
hmset key field1 value1 field2 value2
hmget key field1 field2
例如:
127.0.0.1:6379> hmset he name wanger sex nan
OK
127.0.0.1:6379> hmget he name sex
1) "wanger"
2) "nan"
刪除field
hdel key field1 field2
例如:
127.0.0.1:6379> hdel he name
(integer) 1
127.0.0.1:6379> hget he name
(nil)
獲取field個數(shù)
hlen key
例如:
127.0.0.1:6379> hmset he name wanger sex nan age 18
OK
127.0.0.1:6379> hlen he
(integer) 3
獲取哈希中的所有字段和值
hgetall key
例如:
127.0.0.1:6379> hgetall he
1) "sex"
2) "nan"
3) "name"
4) "wanger"
5) "age"
6) "18"
獲取哈希中的所有字段
hkeys key
例如:
127.0.0.1:6379> hkeys he
1) "sex"
2) "name"
3) "age"
判斷哈希字段是否存在
hexists key field
例如:
127.0.0.1:6379> hexists he name
(integer) 1
127.0.0.1:6379> hexists he sex
(integer) 1
將哈希字段的值遞增
hincrby key field increment
例如:
127.0.0.1:6379> hincrby asd asdf 2
(integer) 3
127.0.0.1:6379> hget asd asdf
"3"
127.0.0.1:6379> hincrby asd asdf 2
(integer) 5
127.0.0.1:6379> hget asd asdf
"5"
獲取哈希中的所有值
hvals key
例如:
127.0.0.1:6379> hvals he
1) "nan"
2) "wanger"
3) "18"
內(nèi)部編碼:
-
ziplist(壓縮列表):
當(dāng)哈希類型元素個數(shù)小于hash-max-ziplist-entries配置(默認(rèn)512個)、同時所有值都小于hash-max-ziplist-value配置(默認(rèn)64字節(jié))時,Redis會使用ziplist作為哈希的內(nèi)部實(shí)現(xiàn),ziplist使用更加緊湊的結(jié)構(gòu)實(shí)現(xiàn)多個元素的連續(xù)存儲,所以在節(jié)省內(nèi)存方面比hashtable更加優(yōu)秀。
-
hashtable(哈希表):
當(dāng)哈希類型無法滿足ziplist的條件時,Redis會使用hashtable作為哈希的內(nèi)部實(shí)現(xiàn),因?yàn)榇藭rziplist的讀寫效率會下降,而hashtable的讀寫時間復(fù)雜度為O(1)
例如:
127.0.0.1:6379> hset ziplist hash 12335452335235fwgvsfwbhfbwhhfwuesrfhwueywhufgbrewfghusfhwueughsajkifo34ejigji
(integer) 1
127.0.0.1:6379> hmset hash asd fcfg zdf fty
OK
集合
唯一且無序的字符串元素的集合。
將一個或多個成員添加到集合中
sadd key member1 member2
例如
127.0.0.1:6379> sadd set s1 s2
(integer) 0
獲取集合所有值
smembers key
例如:
127.0.0.1:6379> smembers set
1) "s2"
2) "s1"
3) "s3"
刪除集合的元素
srem key member1 members2
例如:
127.0.0.1:6379> srem set s2
(integer) 1
127.0.0.1:6379> smembers set
1) "s1"
2) "s3"
獲取元素的長度
scard key
例如:
127.0.0.1:6379> scard set
(integer) 2
隨機(jī)獲取指定個數(shù)的元素
srandmember key [count]
例如:
127.0.0.1:6379> srandmember set 1
1) "s1"
判斷元素是否在集合中
sismember key member
例如:
127.0.0.1:6379> sismember set s2
(integer) 0
127.0.0.1:6379> sismember set s3
(integer) 1
從集合中彈出指定數(shù)量的元素
spop key [count]
例如:
127.0.0.1:6379> smembers set
1) "s5"
2) "s4"
3) "s1"
4) "s3"
127.0.0.1:6379> spop set
"s4"
127.0.0.1:6379> spop set 3
1) "s5"
2) "s1"
3) "s3"
127.0.0.1:6379> smembers set
(empty list or set)
集合間的并集運(yùn)算
sunion key1 key2
例如:
127.0.0.1:6379> sadd set1 1 2 3
(integer) 3
127.0.0.1:6379> sadd set2 2 3 4 5
(integer) 4
127.0.0.1:6379> sunion set1 set2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
集合間的交集運(yùn)算
sinter key1 key2
例如:
127.0.0.1:6379> sinter set1 set2
1) "2"
2) "3"
集合間的差集運(yùn)算
sdiff key1 key2
例如:
127.0.0.1:6379> sdiff set1 set2
1) "1"
127.0.0.1:6379> sdiff set2 set1
1) "4"
2) "5"
內(nèi)部編碼
-
intset(整數(shù)集合):
當(dāng)集合中的元素都是整數(shù)且元素個數(shù)小于set-max-intset-entries配置(默認(rèn)512個)時,Redis會選用intset來作為集合的內(nèi)部實(shí)現(xiàn),從而減少內(nèi)存的使用。
-
hashtable(哈希表):
當(dāng)集合類型無法滿足intset的條件時,Redis會使用hashtable作為集合的內(nèi)部實(shí)現(xiàn)。
例如:
127.0.0.1:6379> sadd set3 s1 s2 s3
(integer) 3
127.0.0.1:6379> object encoding set3
"hashtable"
127.0.0.1:6379> sadd set4 1 2 3
(integer) 3
127.0.0.1:6379> object encoding set4
"intset"
有序集合
每個字符串元素都與一個稱為score的浮點(diǎn)值相關(guān)聯(lián)。元素總是按它們的分?jǐn)?shù)排序,因此與Sets不同,可以檢索一系列元素
添加元素
zadd key [NX|XX] [CH] [INCR] score1 member1 score2 member2
例如:
127.0.0.1:6379> zadd score xx 80 wanger 80 huazai 95 dongdong +inf a
(integer) 0
127.0.0.1:6379> zrange score 0 -1
1) "huazai"
2) "wanger"
3) "dongdong"
4) "a"
+inf和-inf分別表示正無窮和負(fù)無窮
獲取某個成員的分?jǐn)?shù)
zscore key member
例如:
127.0.0.1:6379> zscore score dongdong
"95"
對成員進(jìn)行排名,從0開始
zrange key start end [withscores] #升序排列
zrevrange key start end [withscores] #降序排列
例如:
127.0.0.1:6379> zadd score 95 huazai 90 wanger 85 dongdong +inf a
(integer) 0
127.0.0.1:6379> zrank score huazai
(integer) 2
127.0.0.1:6379> zrevrank score huazai
(integer) 1
127.0.0.1:6379> zrevrank score a
(integer) 0
127.0.0.1:6379> zrange score 0 -1 WITHSCORES
1) "dongdong"
2) "85"
3) "wanger"
4) "90"
5) "huazai"
6) "95"
7) "a"
8) "inf"
獲取成員個數(shù)
zcard key
例如:
127.0.0.1:6379> zcard score
(integer) 4
刪除成員
zrem key member1 member2
例如:
127.0.0.1:6379> zrem score dongdong
(integer) 1
127.0.0.1:6379> zrange score 0 -1
1) "wanger"
2) "huazai"
3) "a"
增加成員的分?jǐn)?shù)
zincrby key increment member
例如:
127.0.0.1:6379> zincrby score 5 wanger
"95"
獲取指定分?jǐn)?shù)范圍的成員
zrangebyscore key min max [withscores] [limit offset count] #升序
zrevrangebyscore key max min [withscores] [limit offset count] #降序
例如:
127.0.0.1:6379> zrangebyscore score 80 90 withscores
1) "dongdong"
2) "85"
3) "wanger"
4) "90"
127.0.0.1:6379> zrevrangebyscore score 95 80 withscores
1) "huazai"
2) "95"
3) "wanger"
4) "90"
5) "dongdong"
6) "85"
獲取指定分?jǐn)?shù)范圍成員個數(shù)
zcount key min max
例如:
127.0.0.1:6379> zcount score 85 95
(integer) 3
刪除指定分?jǐn)?shù)范圍的成員
zremrangebyscore key min max
例如:
127.0.0.1:6379> zremrangebyscore score 85 90
(integer) 2
有序集合的交集運(yùn)算
zinterstore destination numkeys key1 key2 [WEIGHTS weight]
-
destination:
交集計算結(jié)果保存到這個鍵。
-
numkeys:
需要做交集計算鍵的個數(shù)。
-
key[key…]:
需要做交集計算的鍵。
-
weights weight[weight…]:
每個鍵的權(quán)重,在做交集計算時,每個鍵中
-
的每個member會將自己分?jǐn)?shù)乘以這個權(quán)重,每個鍵的權(quán)重默認(rèn)是1。
-
aggregate sum|min|max:
計算成員交集后,分值可以按照sum(和)、
-
min(最小值)、max(最大值)做匯總,默認(rèn)值是sum。
最終的結(jié)果就是權(quán)重乘分?jǐn)?shù),之后再進(jìn)行聚合
例如:
127.0.0.1:6379> zadd user 10 wanger 20 huazai 30 dongdong
(integer) 3
127.0.0.1:6379> zadd user1 15 wanger 35 huazai
(integer) 2
127.0.0.1:6379> zinterstore userset 2 user user1
(integer) 2
127.0.0.1:6379> zrange userset 0 -1 withscores
1) "wanger"
2) "25"
3) "huazai"
4) "55"
127.0.0.1:6379> zinterstore user2set 2 user user1 weights 1 0.5 aggregate min
(integer) 2
127.0.0.1:6379> zrange user2set 0 -1 withscores
1) "wanger"
2) "7.5"
3) "huazai"
4) "17.5"
有序集合的并集計算
zunionstore destination numkeys key [key ...] [WEIGHTS weight]
例如:
127.0.0.1:6379> zadd user 10 wanger 20 huazai 30 dongdong
(integer) 3
127.0.0.1:6379> zadd user1 15 wanger 35 huazai
(integer) 2
127.0.0.1:6379> zunionstore user3set 2 user user1 weights 1 0.5 aggregate max
(integer) 3
127.0.0.1:6379> zrange user3set 0 -1 withscores
1) "wanger"
2) "10"
3) "huazai"
4) "20"
5) "dongdong"
6) "30"
內(nèi)部編碼
-
ziplist(壓縮列表):
當(dāng)有序集合的元素小于zset-max-ziplist-entries配置(默認(rèn)是128個),同時每個元素的值都小于zset-max-ziplist-value(默認(rèn)是64字節(jié))時,Redis會用ziplist來作為有序集合的內(nèi)部編碼實(shí)現(xiàn),ziplist可以有效的減少內(nèi)存的使用
-
skiplist(跳躍表):
當(dāng)ziplist的條件不滿足時,有序集合將使用skiplist作為內(nèi)部編碼的實(shí)現(xiàn),來解決此時ziplist造成的讀寫效率下降的問題.
例如:
127.0.0.1:6379> zadd sortset1 10 a 20 b 30 c
(integer) 3
127.0.0.1:6379> object encoding sortset1
"ziplist"
127.0.0.1:6379> zadd sortset2 10 a 20 b 30 cddddddddddddddddddddddffffffffffffffffffffffffwfwfwggggggggggggggggggwg4yhhhhhhhhhhhhhhhh
(integer) 3
127.0.0.1:6379> object encoding sortset2
"skiplist"
Redis持久化
redis提供了兩種持久化的方法來將數(shù)據(jù)以二進(jìn)制的方式存儲到硬盤,一種為在某一時刻生成快照的RDB持久化,另一種為將寫入命令追加到aof的持久化文件的持久化
RDB
在 Redis 運(yùn)行時,RDB 程序?qū)?dāng)前內(nèi)存中的數(shù)據(jù)庫快照保存到磁盤文件中,在 Redis 重啟動
時,RDB 程序可以通過載入 RDB 文件來還原數(shù)據(jù)庫的狀態(tài)。RDB文件非常適合備份以及用于災(zāi)難恢復(fù)
rdb持久化的過程
-
Redis 會fork 一個子進(jìn)程。
這樣就有了一個子進(jìn)程和一個父過程。
-
子進(jìn)程開始將數(shù)據(jù)集寫入臨時RDB文件。
-
當(dāng)子進(jìn)程完成新的RDB文件的寫入后,它將替換舊的RDB文件。
rdb分為手動觸發(fā)和自動觸發(fā),自動觸發(fā)需要在配置文件中定義
自動觸發(fā)
rdb持久化默認(rèn)在配置文件中開啟的
vim /etc/redis/6379.conf
此配置表示在15分鐘內(nèi)至少修改一次,或者在5分鐘內(nèi)至少修改十次,或者在1分鐘內(nèi)修改10000次會觸發(fā)rdb操作
是否對快照數(shù)據(jù)進(jìn)行壓縮存儲
rdbcompression yes
是否使用CRC64算法進(jìn)行數(shù)據(jù)校驗(yàn),如果開啟那么將增加10的性能消耗
rdbchecksum yes
指定生成的文件名
dbfilename dump.rdb
指定文件存放的目錄
dir /var/lib/redis/6379
手動觸發(fā)
rdb的手動觸發(fā)需要手動調(diào)用SAVE或BGSAVE命令
-
SAVE命令:
在當(dāng)前進(jìn)程執(zhí)行,阻塞當(dāng)前Redis服務(wù)器,直到RDB過程完成為止,在主進(jìn)程阻塞期間,服務(wù)器不能處理客戶端的任何請求。
-
BGSAVE命令:
當(dāng)前進(jìn)程會 fork 出一個子進(jìn)程,父進(jìn)程繼續(xù)處理請求,子進(jìn)程開始將數(shù)據(jù)寫入臨時RDB文件 ,并在保存完成之后向主進(jìn)程發(fā)送信號,通知保存已完成。
因?yàn)樵谧舆M(jìn)程被調(diào)用,所以 Redis 服務(wù)器在BGSAVE 執(zhí)行期間仍然可以繼續(xù)處理客戶端的請求
AOF
AOF持久性會記錄服務(wù)器接收的每個寫入操作,這些操作將在服務(wù)器啟動時再次運(yùn)行,以重建原始數(shù)據(jù)集。使用與Redis協(xié)議本身相同的格式記錄命令,并且采用僅追加方式。當(dāng)日志太大時,Redis可以在后臺重寫日志。AOF的主要作用是解決了數(shù)據(jù)持久化的實(shí)時性
AOF持久化流程
-
所有的寫入命令會追加到aof_buf(緩沖區(qū))中。
-
AOF緩沖區(qū)根據(jù)對應(yīng)的策略向硬盤做同步操作。
-
隨著AOF文件越來越大,需要定期對AOF文件進(jìn)行重寫,達(dá)到壓縮的目的。
-
當(dāng)Redis服務(wù)器重啟時,可以加載AOF文件進(jìn)行數(shù)據(jù)恢復(fù)
AOF持久化策略
-
appendfsync always:
每次將新命令附加到AOF時。
雖然很慢,但是數(shù)據(jù)不會丟失
-
appendfsync everysec:
每秒鐘保存一次。
如果發(fā)生災(zāi)難,可能會丟失1秒的數(shù)據(jù)。
-
appendfsync no:
不主動進(jìn)行同步操作,由操作系統(tǒng)來完成。
更快,更不安全的方法。
通常,Linux使用此配置每30秒刷新一次數(shù)據(jù),但這取決于內(nèi)核的精確調(diào)整。
默認(rèn)采用everysec模式
AOF重寫
當(dāng)AOF太大時,Redis會簡單地從頭開始將其重寫到臨時文件中。重寫不是通過讀取舊的文件,而是由Redis fork一個子進(jìn)程直接訪問內(nèi)存中的數(shù)據(jù),將其轉(zhuǎn)換為寫命令同步到新的aof文件,因此Redis可以創(chuàng)建更小的AOF文件,并且在寫入新的AOF時不需要讀取磁盤。
重寫終止后,臨時文件將被fsync同步在磁盤上,并覆蓋舊的AOF文件。
當(dāng)aof被重寫的過程中又有新數(shù)據(jù)寫入怎么辦?這可能會導(dǎo)致數(shù)據(jù)不一致
新寫入的數(shù)據(jù)會放到舊的aof文件里,同時也會追加到aof的重寫緩沖區(qū)中,最后替換掉舊的aof文件
AOF配置持久化
vim /etc/redis/6379.conf
是否在后臺aof文件重寫期間調(diào)用fsync,默認(rèn)為no,表示調(diào)用
no-appendfsync-on-rewrite no
當(dāng)前aof文件增長量超過上次afo文件大小的100%時,則觸發(fā)rewrite,如果為0,則禁用自動觸發(fā)重寫
auto-aof-rewrite-percentage 100
aof文件重寫最小的文件大小,低于這個值將不會觸發(fā)重寫操作
auto-aof-rewrite-min-size 64mb
當(dāng)子進(jìn)程重寫AOF文件時,每生成32 MB的數(shù)據(jù),文件就會把數(shù)據(jù)落盤,防止單次文件數(shù)據(jù)過大造成阻塞
aof-rewrite-incremental-fsync yes
使用rdb和aof混合持久化方式,會將aof重寫操作時的數(shù)據(jù)狀態(tài)保存為rdb格式,而重寫之后的redis命令會繼續(xù)追加到rdb數(shù)據(jù)之后
aof-use-rdb-preamble yes
rdb與aof同時存在時,優(yōu)先使用aof進(jìn)行數(shù)據(jù)恢復(fù)
作者:wanger
歡迎關(guān)注:運(yùn)維開發(fā)故事