20.3 Redis基礎(chǔ)部分

一、安裝

1. 官網(wǎng)下載源碼

image

2. 安裝依賴包

yum install gcc tcl   

3. 下載源碼包

wget http://download.redis.io/releases/redis-4.0.10.tar.gz

3. 解壓安裝

tar -xf redis-4.0.10.tar.gz
cd redis-4.0.10
make && make install

4. 配置 redis

mkdir /etc/redis
cd redis-4.0.10/
cp redis.conf /etc/redis/6379.conf

守護進程的方式啟動服務時初茶,即使執(zhí)行啟動服務命令的終端關(guān)閉商乎,服務仍然可以在后臺運行羊苟。

配置 centos7 systemd 管理 redis 服務

  1. /lib/systemd/system目錄下創(chuàng)建一個腳本文件redis.service寂曹,里面的內(nèi)容如下:
[Unit]
Description=Redis
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/redis-server /etc/redis/6379.conf  --daemonize no
ExecStop=/usr/local/bin/redis-cli -p 6379 shutdown

[Install]
WantedBy=multi-user.target

[Unit] 表示這是基礎(chǔ)信息配置塊
Description 是描述
After 開啟自啟動時候的順序, 指定的服務必須先于次此服務啟動腹备,一般是網(wǎng)絡服務啟動后啟動
[Service] 表示這里是服務信息配置塊
Type 指定啟動服務的類型, simple 是默認的方式
EnvironmentFile 指定服務啟動時用到的配置文件
ExecStart 是啟動服務的命令
ExecStop 是停止服務的指令
[Install] 表示這是是安裝信息配置塊
WantedBy 是以哪種方式啟動:multi-user.target表明當系統(tǒng)以多用戶方式(默認的運行級別)啟動時衬潦,這個服務需要被自動運行。

授權(quán)在主機啟動的時候同時啟動服務

systemctl enable redis.service

關(guān)于 server 文件的詳細參數(shù)介紹參考這里

  1. 使用 systemctl 操作

刷新配置植酥,讓 systemd 識別剛剛添加的 redis 服務

systemctl daemon-reload

啟動服務

systemctl start redis

關(guān)于配置文件中的配置

設置監(jiān)聽地址

shell> vi /etc/redis/6379.conf
# bind 127.0.0.1 192.168.1.10             

bind 參數(shù)若都注釋掉镀岛,則會監(jiān)聽服務器上的所有 ip
可以指定一個或者多個,打開注釋友驮。
注意此配置項可能在 71 行左右漂羊。默認是 bind 127.0.0.1

檢查并測試

檢查默認端口 6379 是否監(jiān)聽
``

image
shell> redis-cli
127.0.0.1:6379> info
# Server
redis_version:4.0.10
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:cfb22f7d67db356d
... 略 ...

手動使用命令指定配置文件啟動服務

/usr/local/bin/redis-server /etc/redis/6379.conf

這種方式執(zhí)行,默認 Redis 服務侯會在前臺運行卸留。

設置使用守護進程都方式運行服務
需要編輯配置文件 /etc/redis/6379.conf

daemonize yes   # 守護進程的方式啟動服務

客戶端指定端口訪問

redis-cli -p 6379

手動停止服務

redis-cli -p 6379 shutdown

假如重啟后出現(xiàn)如下錯誤信息走越,就按照提示操作

1044:M 27 Feb 14:47:21.993 # Server initialized
1044:M 27 Feb 14:47:21.993 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1044:M 27 Feb 14:47:21.993 # Short read or OOM loading DB. Unrecoverable error, aborting now.
1044:M 27 Feb 14:47:21.993 # Internal error in RDB reading function at rdb.c:1666 -> Unexpected EOF reading RDB file

echo "vm.overcommit_memory = 1"  >> /etc/sysctl.conf

sysctl -p

問題二

 error, aborting now.
1344:M 27 Feb 14:59:33.466 # Internal error in RDB reading function at rdb.c:1666 -> Unexpected EOF reading RDB file

移動 dump.db 文件或者更名,可以刪除艾猜。

rm dump.rdb

二买喧、數(shù)據(jù)類型

1. 數(shù)據(jù)類型的基本介紹

image

2. 數(shù)據(jù)類型的基本操作

a.String

set

127.0.0.1:6379> help set
SET key value [EX seconds] [PX milliseconds] [NX|XX]

在 Redis 中設置值,默認匆赃,不存在則創(chuàng)建淤毛,存在則修改
參數(shù):
ex,過期時間(秒)
px算柳,過期時間(毫秒)
nx低淡,假如設置為True,則只有 name 不存在時瞬项,當前 set 操作才執(zhí)行
xx蔗蹋,假如設置為True,則只有 name 存在時囱淋,當前 set 操作才執(zhí)行

Example

127.0.0.1:6379> set name shark EX 10
OK
127.0.0.1:6379> get name
"shark"

setnx

127.0.0.1:6379> help setnx
  SETNX key value

設置值猪杭,只有name 不存在時,執(zhí)行設置操作(添加)

Example

127.0.0.1:6379> setnx age 10
(integer) 1
127.0.0.1:6379> get age
"10"
127.0.0.1:6379> setnx age 20
(integer) 0
127.0.0.1:6379> get age
"10"
127.0.0.1:6379>

setex

127.0.0.1:6379> help setex
  SETEX key seconds value

設置 key 和 value妥衣,并且指的過期時間(單位: 秒)

Example

127.0.0.1:6379> setex name 5 shark
OK

get

獲取一個 key 的 value

127.0.0.1:6379> get name
"shark"

ttl

查看一個 key 的過期時間

127.0.0.1:6379> ttl age
(integer) -1

  • -1 永不過期
  • -2 已經(jīng)過期

expire

設置一個 key 的過期時間(單位: 秒)
如果key不存在則返回0皂吮,否則返回1.如果key已經(jīng)存在過期時間則再設置會覆蓋之前的過期時間

127.0.0.1:6379> EXPIRE age 10
(integer) 1
127.0.0.1:6379> ttl age
(integer) 7

persist key

移除 key 的過期時間

mset

一次添加多個值

127.0.0.1:6379> mset name shark age 10
OK

mget

一次獲取多個 key 的值

127.0.0.1:6379> MGET name age
1) "shark"
2) "10

incr

對一個 key 的值自增 1

127.0.0.1:6379> incr age
(integer) 11

decr

對一個 key 的值自減 1

127.0.0.1:6379> DECR age
(integer) 10

append

向一個 key 的值后面追加內(nèi)容

127.0.0.1:6379> get n
"10"
127.0.0.1:6379> APPEND n 10
(integer) 4
127.0.0.1:6379> get n
"1010"

getrange

127.0.0.1:6379> GETRANGE n 0 -1
"1010"

del

刪除 一個或者多個 key

127.0.0.1:6379> del name age
(integer) 2

EXISTS

判斷一個 key 是否存在, 返回 1 表示存在, 0 表示不存在

127.0.0.1:6379> exists age
(integer) 1
127.0.0.1:6379> exists aaa
(integer) 0
127.0.0.1:6379>

TYPE

返回key存儲的類型税手,如果不存在則返回none

type key

keys

通過通配符來獲取匹配到的 key
一般不在生產(chǎn)環(huán)境中使用此命令

  • * 匹配所有
  • ? 匹配任意一個
127.0.0.1:6379> keys *
1) "num"
2) "age"
3) "n"
127.0.0.1:6379> keys n*
1) "num"
2) "n"
127.0.0.1:6379> keys a[f-g]
(empty list or set)
127.0.0.1:6379> keys a[e-g]?
1) "age"

scan

dbsize

返回數(shù)據(jù)庫種 key 的總數(shù)

dbsize

b. List 操作

lpush

向列表左端添加元素蜂筹,values是按左到右依次插入的,返回值為列表中元素個數(shù)芦倒,列表元素可以重復

最后加入到元素艺挪,在列表的第一位

127.0.0.1:6379> LPUSH list a b c
(integer) 3
127.0.0.1:6379> LPUSH list a b c
(integer) 6

rpush

向列表右端依次的添加元素,最后加入的元素在列表的最后位置

127.0.0.1:6379> RPUSH list d e f
(integer) 9

LINDEX

通過元素在列表中的位置獲取到這個元素兵扬,位置稱為索引號/下標麻裳,

位置支持正整數(shù)和負整數(shù)

列表中元素的位置中口蝠,第一位是 0,最后一位是列表總長度減 1 或者是 -1

image
127.0.0.1:6379> LINDEX list 0
"c"

LRANGE

獲取列表表一個區(qū)間的值

127.0.0.1:6379> LRANGE list 0 2
1) "c"
2) "b"
3) "a"

LPUSHX

向列表左端添加元素掂器,只有key存在時才可以添加

127.0.0.1:6379> EXISTS list1 
(integer) 0
127.0.0.1:6379> LPUSHX list1 a
(integer) 0
127.0.0.1:6379> LPUSHX list g
(integer) 10

RPUSHX

向列表右端添加元素亚皂,其他與LPUSHX相同

LPOP

將左端列表元素彈出俱箱,會將其從列表中刪除国瓮,如果key不存在則返回(nil)

127.0.0.1:6379> LPOP list
"g"
127.0.0.1:6379> LPOP list
"c"

RPOP

將右端列表元素彈出,其他同LPOP

LLEN

返回列表的長度狞谱,如果列表不存在則返回0

127.0.0.1:6379> LLEN list
(integer) 8
127.0.0.1:6379> LLEN list1
(integer) 0

LREM

lrem  key count value

刪除列表中指定的值乃摹,返回值為刪除的元素的個數(shù),count值有以下幾種:

  • count > 0: 從列表的頭開始跟衅,向尾部搜索孵睬,移除與value相等的元素,移除count個
  • count < 0: 從列表尾部開始伶跷,向頭部搜索掰读,移除與value相等的元素,移除-count個
  • count == 0: 移除列表中所有與value相等的

c. Hash

image

HSET key field value

將哈希表key中的域 (field) 設置成指定的value叭莫,如果key不存在則新建一個hash表蹈集,如果域不存在則新建域,如果域已存在則更新域雇初,如果field不存在返回1表示新建拢肆,存在則返回0表示更新

127.0.0.1:6379> HSET userinfo username 'shark'
(integer) 1
127.0.0.1:6379> HSET userinfo userpsw '123456'
(integer) 1
127.0.0.1:6379> HSET userinfo userpsw '654321'
(integer) 0

HGET key field

獲取哈希表key中的域field的值,如果key或者field不存在則返回(nil)

127.0.0.1:6379> HGET userinfo2 username
(nil)
127.0.0.1:6379> HGET userinfo username
"stronger"
127.0.0.1:6379> HGET userinfo email
(nil)

HSETNX key field value

將哈希表中的域field設置成指定的值靖诗,只有field不存在時才可以成功郭怪,如果field存在操作無效,返回0

127.0.0.1:6379> HGET userinfo username
"stronger"
127.0.0.1:6379> HSETNX userinfo username 'fish'
(integer) 0
127.0.0.1:6379> HGET userinfo username
"stronger"

HMSET key field vale [field value]

同時將多個field-value設定到hash表中刊橘,如果field已存在值則會被覆蓋掉

127.0.0.1:6379> HMSET userinfo email 'yangdm@gmail.com' sex 'male'
OK

HMGET key field [field]

同時獲得key存儲的hansh表中多個field的值鄙才,如果不存在則返回(nil)

127.0.0.1:6379> HMGET userinfo email sex age
1) "yangdm@gmail.com"
2) "male"
3) (nil)

HGETALL key

返回key存儲的所有field及value

127.0.0.1:6379> HGETALL userinfo
1) "username"
2) "stronger"
3) "userpsw"
4) "654321"
5) "email"
6) "yangdm@gmail.com"
7) "sex"
8) "male"
127.0.0.1:6379> HGETALL userinfo2
(empty list or set)

HKEYS key

返回hash的所有域

127.0.0.1:6379> HKEYS userinfo
1) "username"
2) "userpsw"
3) "email"
4) "sex"

HVALS key

返回hash的所有域的值

127.0.0.1:6379> HVALS userinfo
1) "stronger"
2) "654321"
3) "yangdm@gmail.com"
4) "male"

HEXISTS key field

檢測key中存儲的hash中field是否存在,存在返回1促绵,否則返回0

127.0.0.1:6379> HEXISTS userinfo username
(integer) 1
127.0.0.1:6379> HEXISTS userinfo age
(integer) 0

HLEN key

返回key中存儲的hash表中field的數(shù)量

127.0.0.1:6379> HLEN userinfo
(integer) 4

HINCRBY key field increment

給key中存儲的hash表field增加increment攒庵,如果此field不存在,則創(chuàng)建值為0的field绞愚,然后增加increment叙甸。操作的字段必須是整數(shù),參照字符串處理

127.0.0.1:6379> HINCRBY userinfo age 10
(integer) 10

HINCRBYFLOAT key field increment

給key中存儲的hash表field增加increment位衩,可以為浮點數(shù)裆蒸,參照字符串處理

127.0.0.1:6379> HINCRBYFLOAT userinfo salary 150.56
"150.56"

HDEL key field [field]

刪除key中存儲的hash表的field,可以刪除一個或多個,成功返回被移除域的數(shù)量

127.0.0.1:6379> HKEYS userinfo
1) "username"
2) "userpsw"
3) "email"
4) "sex"
5) "age"
6) "salary"
127.0.0.1:6379> HDEL userinfo salary age
(integer) 2
127.0.0.1:6379> HKEYS userinfo
1) "username"
2) "userpsw"
3) "email"
4) "sex"

Set

Redis 的 Set 是 String 類型的無序集合糖驴。集合成員是唯一的僚祷,這就意味著集合中不能出現(xiàn)重復的數(shù)據(jù)佛致。

Redis 中集合是通過哈希表實現(xiàn)的。

// 向集合中添加一個或者多個元素
SADD key member [member ...]

// 返回一個集合中的所有成員
SMEMBERS key

// 獲取集合中元素的個數(shù)
SCARD key

// 返回所有集合的差集辙谜,就是存在于第一個集合中俺榆,且不存在于其他集合中的成員
SDIFF key [key ...]

// 交集,就是所有集合共有的元素
SINTER key [key ...]

// 并集装哆, 就是所有集合的元素合并在一起罐脊,并去重
SUNION key [key ...]

// 差集, 返回第一集合中獨有的元素
SDIFF  key  [key...]

Example

127.0.0.1:6379> sadd s1 a b
(integer) 2
127.0.0.1:6379> sadd s2 a b c d
(integer) 4
127.0.0.1:6379> sadd s3 c d e f
(integer) 4

127.0.0.1:6379> sdiff s2 s1
1) "d"
2) "c"

127.0.0.1:6379> SINTER s1 s2
1) "b"
2) "a"

127.0.0.1:6379> SUNION s1 s2 s3
1) "b"
2) "c"
3) "d"
4) "f"
5) "a"
6) "e"

127.0.0.1:6379> SMEMBERS s1
1) "b"
2) "a"

Sort Set 操作

有序集合蜕琴,在集合的基礎(chǔ)上萍桌,為每元素排序;元素的排序需要根據(jù)另外一個值來進行比較凌简,所以上炎,對于有序集合,每一個元素有兩個值雏搂,即:值和分數(shù)藕施,分數(shù)專門用來做排序。

// 向有序集合添加一個或多個成員凸郑,或者更新已存在成員的分數(shù)
ZADD key score1 member1 [score2 member2]

// score1 是成員的分數(shù)
// member 是有序集合中的成員

// 獲取有序集合的元素個數(shù)
ZCARD key 

// 返回有序集合中的所有成員
127.0.0.1:6379> zrange sort_s 0 -1
1) "no"
2) "hello"

// 返回有序集合中的所有成員及其索引號(分數(shù))
127.0.0.1:6379> zrange sort_s 0 -1  withscores
1) "no"
2) "1"
3) "hello"
4) "2"
127.0.0.1:6379>

出現(xiàn)下面的錯誤裳食,是操作的命令和這個命令所能操作的數(shù)據(jù)類型不符合。

(error) WRONGTYPE Operation against a key holding the wrong kind of value

三线椰、Redis 的認證連接

// 在配置文件中找到以下配置項胞谈,大約在第 `500` 行
shell> vi /etc/redis/6379.conf
requirepass mypassword

mypassword 就是密碼了,更改好后重啟服務

使用設置好的密碼認證

// 使用 auth 進行密碼認證
127.0.0.1:6379> info
NOAUTH Authentication required.
127.0.0.1:6379> auth  mypassword
OK
127.0.0.1:6379> info
# Server
redis_version:4.0.10
...略...

或者在 shell 命令行里使用 -a 選項指定密碼憨愉,會出現(xiàn)警告信息

[root@localhost ~]# redis-cli  -a foobared info
Warning: Using a password with '-a' option on the command line interface may not be safe.
# Server
redis_version:4.0.10
...略...

四烦绳、php-redis

開始在 PHP 中使用 Redis 前, 我們需要確保已經(jīng)安裝了 redis 服務及 PHP redis 驅(qū)動配紫,且你的機器上能正常使用 PHP径密。

安裝 phpredis 驅(qū)動

點我進入下載頁面,,注意選擇版本

1. 下載解壓后躺孝,進入解壓后的目錄

[root@s2 ~]# wget https://github.com/phpredis/phpredis/archive/4.2.0.tar.gz
shell> 
shell> cd php7-redis

2. 安裝 php

安裝 php , 只需要使用 YUM 安裝 php-devel 即可享扔。

yum install php-devel

3. 執(zhí)行如下命令,生成配置工具

在解壓后的 php 目錄中執(zhí)行如下命令

shell> phpize

image

4. 使用生成的配置工具命令 configre 進行配置并編譯安裝

配置

[root@s2 phpredis-4.2.0]# find / -name php-config
/usr/bin/php-config
[root@s2 phpredis-4.2.0]# ./configure --with-php-config=/usr/bin/php-config
   ... 略...
checking whether to build shared libraries... yes
checking whether to build static libraries... no
configure: creating ./config.status
config.status: creating config.h
config.status: executing libtool commands

編譯安裝

[root@s2 phpredis-4.2.0]# make && make install
  ...略...
Build complete.
Don't forget to run 'make test'.

Installing shared extensions:     /usr/lib64/php/modules/

5. 測試安裝是否成功

[root@s2 phpredis-4.2.0]# php -v
PHP 5.4.16 (cli) (built: Oct 30 2018 19:30:51)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies

6. 在php.ini中添加 extension=redis.so

[root@s2 phpredis-4.2.0]# find / -name php.ini
/etc/php.ini
[root@s2 phpredis-4.2.0]# vi /etc/php.ini
[root@s2 phpredis-4.2.0]# tail /etc/php.ini
;mcrypt.modes_dir=

[dba]
;dba.default_handler=

; Local Variables:
; tab-width: 4
; End:

extension=redis.so
[root@s2 phpredis-4.2.0]# php -m | grep redis
redis

7. php -m | grep redis或者phpinfo查看安裝是否成功

[root@s2 phpredis-4.2.0]# php -m | grep redis
redis

五植袍、持久化存儲

1. 持久化存儲的方式介紹

Redis 分別提供了 RDB 和 AOF 兩種持久化機制:

  • RDB 將數(shù)據(jù)庫的快照(snapshot)以二進制的方式保存到磁盤中惧眠。

  • AOF 則以協(xié)議文本的方式,將所有對數(shù)據(jù)庫進行過寫入的命令(及其參數(shù))記錄到 AOF 文件于个,以此達到記錄數(shù)據(jù)庫狀態(tài)的目的氛魁。

2. RDB

a. 什么是RDB

和 MySQL 中的 mysqldump 差不多一個道理。

image

b. 什么情況下會觸發(fā) RDB

第一種情況,主動執(zhí)行 save 命令(同步秀存,阻塞 捶码,就是save 命令執(zhí)行完畢后才能執(zhí)行后續(xù)的其他命令操作)

image

阻塞

image
保存 RDB 文件的策略

每次創(chuàng)建新的文件,并且替換原來舊文件(假如存在舊的文件)

第二種情況或链,主動執(zhí)行 bgsave 命令 (異步惫恼,非阻塞 )

image
  • 文件策略和 save 相同

第三種情況,自動觸發(fā)

自動觸發(fā)澳盐,就是通過對 Redis 的配置文件重相關(guān)選項的修改祈纯,當達到某個配置好的條件后,自動生成 RDB 文件
洞就,其內(nèi)部使用的是 bgsave 命令盆繁。

配置文件中相關(guān)選項的默認值如下表:

配置 seconds changes 含義
save 900 1 每隔 900 秒檢查一次掀淘,假如至少有 1 條數(shù)據(jù)改變旬蟋,就生成新的 RDB 文件
save 300 10 每隔 300 秒檢查一次,假如至少有 10 條數(shù)據(jù)改變革娄,就生成新的 RDB 文件
save 60 10000 每隔 60 秒檢查一次倾贰,假如至少有 10000 條數(shù)據(jù)改變,就生成新的 RDB 文件

每次檢查都會建立一個新的檢查點拦惋,以便用于下次檢查作為參考信息匆浙。

關(guān)于 RDB 文件的配置信息

默認文件名
dbfilename dump.rdb

默認文件保存位置
dir ./

假如 bgsave 執(zhí)行中發(fā)生錯誤,是否停止寫入厕妖,默認是 yes 首尼, 表示假如出錯,就停止寫入言秸。
stop-writes-on-bgsave-error yes

是否使用壓縮|
rdbcompression yes

是否進行數(shù)據(jù)的校驗
rdbchecksum yes

建議的最佳配置

關(guān)閉自動生成 RDB 文件
在配置文件中注釋掉如下內(nèi)容

#save 900 1
#save 300 10
#save 60    10000

使用不同端口號進行區(qū)分软能,因為,有可能會在同一臺主機上開啟多個 Redis 實例举畸。
防止多個實例產(chǎn)生的數(shù)據(jù)信息寫到一個文件中查排。
dbfilename dump-${port}.rdb

指定一個大硬盤的路徑
dir /redis_data

假如出現(xiàn)錯誤,停止繼續(xù)寫入
stop-writes-on-bgsave-error yes

采用壓縮
rdbcompression yes

進行校驗
rdbchecksum yes

實驗

修改配置文件中的相關(guān)選項抄沮,使其成為如下內(nèi)容中顯示的值:

dbfilename dump-6379.rdb
dir /redis_data   # 此目錄需要自己創(chuàng)建
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

假如你的 Redis 服務器允許客戶端可以從非本機訪問跋核,應該在配置文件中狠持,把 protected-mode 的值設置問 no腿堤。

這樣的話,客戶端就可以從其他主機訪問 Redis 服務器了布讹,并且不需要密碼率挣。

重啟服務后刻伊,在 Rdis 命令行客戶端中輸入 save 命令。

[root@s1 ~]# redis-cli
127.0.0.1:6379> save
OK
127.0.0.1:6379>

該命令將在配置文件重配置的指定目錄中創(chuàng)建 dump-6379.rdb文件。

恢復數(shù)據(jù)時娃圆,只需要保證此文件完好玫锋,并且在配置文件中指定的目錄下即可。這樣 Rdis 啟動時就會把此文件中的數(shù)據(jù)恢復到當前的服務器中讼呢。

bgsave 命令和 save基本一樣撩鹿,就是 bgsave 命令不會產(chǎn)生阻塞

127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379>

查看當前服務器的數(shù)據(jù)文件目錄

127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/"

2. AOF

什么是 AOF

AOF 文件保存了 Redis 的數(shù)據(jù)庫狀態(tài), 而文件里面包含的都是符合 Redis 通訊協(xié)議格式的命令文本悦屏。

image

AOF 保存的模式

Redis 目前支持三種 AOF 保存模式节沦,它們分別是:

  1. AOF_FSYNC_NO :不保存。
  2. AOF_FSYNC_EVERYSEC :每一秒鐘保存一次础爬。(生產(chǎn)中一般選這種)
  3. AOF_FSYNC_ALWAYS :每執(zhí)行一個命令保存一次

不保存

在這種模式下甫贯, SAVE 只會在以下任意一種情況中被執(zhí)行:

Redis 被關(guān)閉
AOF 功能被關(guān)閉
系統(tǒng)的寫緩存被刷新(可能是緩存已經(jīng)被寫滿,或者定期保存操作被執(zhí)行)
這三種情況下的 SAVE 操作都會引起 Redis 主進程阻塞看蚜。

每執(zhí)行一個命令保存一次

在這種模式下叫搁,每次執(zhí)行完一個命令之后, WRITE 和 SAVE 都會被執(zhí)行供炎。

另外渴逻,因為 SAVE 是由 Redis 主進程執(zhí)行的,所以在 SAVE 執(zhí)行期間音诫,主進程會被阻塞惨奕,不能接受命令請求。

AOF 三種保存模式的比較

因為阻塞操作會讓 Redis 主進程無法持續(xù)處理請求竭钝, 所以一般說來梨撞, 阻塞操作執(zhí)行得越少、完成得越快香罐, Redis 的性能就越好卧波。

模式 1 的保存操作只會在AOF 關(guān)閉或 Redis 關(guān)閉時執(zhí)行, 或者由操作系統(tǒng)觸發(fā)穴吹, 在一般情況下幽勒, 這種模式只需要為寫入阻塞, 因此它的寫入性能要比后面兩種模式要高港令, 當然啥容, 這種性能的提高是以降低安全性為代價的: 在這種模式下, 如果運行的中途發(fā)生停機顷霹, 那么丟失數(shù)據(jù)的數(shù)量由操作系統(tǒng)的緩存沖洗策略決定咪惠。

模式 2 在性能方面要優(yōu)于模式 3 , 并且在通常情況下淋淀, 這種模式最多丟失不多于 2 秒的數(shù)據(jù)遥昧, 所以它的安全性要高于模式 1 , 這是一種兼顧性能和安全性的保存方案。

模式 3 的安全性是最高的炭臭, 但性能也是最差的永脓, 因為服務器必須阻塞直到命令信息被寫入并保存到磁盤之后, 才能繼續(xù)處理請求鞋仍。

綜合起來常摧,三種 AOF 模式的操作特性可以總結(jié)如下:

模式 WRITE 是否阻塞? SAVE 是否阻塞威创? 停機時丟失的數(shù)據(jù)量
AOF_FSYNC_NO 阻塞 阻塞 操作系統(tǒng)最后一次對 AOF 文件觸發(fā) SAVE 操作之后的數(shù)據(jù)落午。
AOF_FSYNC_EVERYSEC 阻塞 不阻塞 一般情況下不超過 2 秒鐘的數(shù)據(jù)。
AOF_FSYNC_ALWAYS 阻塞 阻塞 最多只丟失一個命令的數(shù)據(jù)肚豺。

AOF 方式下的數(shù)據(jù)還原

Redis 讀取 AOF 文件并還原數(shù)據(jù)庫的詳細步驟如下:

創(chuàng)建一個不帶網(wǎng)絡連接的偽客戶端(fake client)溃斋。
讀取 AOF 所保存的文本,并根據(jù)內(nèi)容還原出命令吸申、命令的參數(shù)以及命令的個數(shù)梗劫。
根據(jù)命令、命令的參數(shù)和命令的個數(shù)呛谜,使用偽客戶端執(zhí)行該命令在跳。
執(zhí)行 2 和 3 ,直到 AOF 文件中的所有命令執(zhí)行完畢隐岛。
完成第 4 步之后, AOF 文件所保存的數(shù)據(jù)庫就會被完整地還原出來瓷翻。

注意聚凹, 因為 Redis 的命令只能在客戶端的上下文中被執(zhí)行, 而 AOF 還原時所使用的命令來自于 AOF 文件齐帚, 而不是網(wǎng)絡妒牙, 所以程序使用了一個沒有網(wǎng)絡連接的偽客戶端來執(zhí)行命令。

當程序讀入這個 AOF 文件時对妄, 它首先執(zhí)行 SELECT 0 命令 —— 這個 SELECT 命令是由 AOF 寫入程序自動生成的湘今, 它確保程序可以將數(shù)據(jù)還原到正確的數(shù)據(jù)庫上。

注意:
為了避免對數(shù)據(jù)的完整性產(chǎn)生影響剪菱, 在服務器載入數(shù)據(jù)的過程中摩瞎, 只有和數(shù)據(jù)庫無關(guān)的訂閱與發(fā)布功能可以正常使用, 其他命令一律返回錯誤孝常。

AOF 的重寫機制

為什么需要重寫機制

AOF 文件通過同步 Redis 服務器所執(zhí)行的命令旗们, 從而實現(xiàn)了數(shù)據(jù)庫狀態(tài)的記錄, 但是构灸, 這種同步方式會造成一個問題: 隨著運行時間的流逝上渴, AOF 文件會變得越來越大。

  1. 對同一個鍵的狀態(tài)的多次不同操作,而最終得到一個結(jié)果稠氮。比如對列表的添加刪除元素曹阔。

  2. 被頻繁操作的鍵。比如累加

重新機制是如何實現(xiàn)的

實際上隔披, AOF 重寫并不需要對原有的 AOF 文件進行任何寫入和讀取次兆, 它針對的是數(shù)據(jù)庫中鍵的當前值,也就是源數(shù)據(jù)從目前的內(nèi)存中獲取锹锰。

考慮這樣一個情況芥炭, 如果服務器對鍵 list 執(zhí)行了以下四條命令:

RPUSH list 1 2 3 4      // [1, 2, 3, 4]

RPOP list               // [1, 2, 3]

LPOP list               // [2, 3]

LPUSH list 1            // [1, 2, 3]

那么當前列表鍵 list 在數(shù)據(jù)庫中的值就為 [1, 2, 3] 。

如果我們要保存這個列表的當前狀態(tài)恃慧, 并且盡量減少所使用的命令數(shù)园蝠, 那么最簡單的方式不是去 AOF 文件上分析前面執(zhí)行的四條命令, 而是直接讀取 list 鍵在數(shù)據(jù)庫的當前值痢士, 然后用一條 RPUSH 1 2 3 命令來代替前面的四條命令彪薛。

除了列表之外,集合怠蹂、字符串善延、有序集、哈希表等鍵也可以用類似的方法來保存狀態(tài)城侧。

根據(jù)鍵的類型易遣, 使用適當?shù)膶懭朊顏碇噩F(xiàn)鍵的當前值, 這就是 AOF 重寫的實現(xiàn)原理嫌佑。

基本都步驟

for  遍歷所有數(shù)據(jù)庫:
      if  如果數(shù)據(jù)庫為空:
             那么跳過這個數(shù)據(jù)庫
      else:
            寫入 SELECT 命令豆茫,用于切換數(shù)據(jù)庫
            for  選擇一個庫后,遍歷這個庫的所有鍵
                   if 如果鍵帶有過期時間屋摇,并且已經(jīng)過期揩魂,那么跳過這個鍵
                   if 根據(jù)數(shù)據(jù)的類型,進行相關(guān)操作炮温。

AOF 重寫的實現(xiàn)方式

方式 區(qū)別
bgrewriteaof 命令 不需要重啟服務火脉,不便于統(tǒng)一管理
配置文件實現(xiàn) 需要重啟服務,便于進行統(tǒng)一管理

bgrewriteaof

image

配置文件實現(xiàn)

image
觸發(fā)條件柒啤,必須同時滿足如下條件
image

aof_current_sizeaof_base_size 可以通過命令 info persistence 查看到

重寫流程圖

image

對于上圖有四個關(guān)鍵點補充一下:

在重寫期間倦挂,由于主進程依然在響應命令,為了保證最終備份的完整性白修;因此它依然會寫入舊的AOF file中妒峦,如果重寫失敗,能夠保證數(shù)據(jù)不丟失兵睛。當然這個是可以通過配置來決定在重寫期間是否進行主進程普通的 AOF 操作肯骇。
為了把重寫期間響應的寫入信息也寫入到新的文件中窥浪,因此也會為子進程保留一個buf,防止新寫的file丟失數(shù)據(jù)笛丙。
重寫是直接把當前內(nèi)存的數(shù)據(jù)生成對應命令漾脂,并不需要讀取老的AOF文件進行分析、命令合并胚鸯。
AOF文件直接采用的文本協(xié)議骨稿,主要是兼容性好、追加方便姜钳、可讀性高可認為修改修復坦冠。

注意:無論是RDB還是AOF都是先寫入一個臨時文件,然后通過 rename 完成文件的替換工作哥桥。

配置示例

// 要想使用 AOF 的全部功能辙浑,需要設置為  yes
appendonly yes

// AOF 文件名,路徑才看之前的 `dir` 配置項
appendfilename "appendonly.aof"

// 平常普通的 AOF 的策略
appendfsync everysec

// 當執(zhí)行 AOF 重寫時拟糕,是否繼續(xù)執(zhí)行平常普通的 AOF 操作判呕。
// 這里設置文件  yes , 表示不執(zhí)行
// 因為假如,同時執(zhí)行送滞,兩種操作都會對磁盤 I/O 進行訪問侠草,造成
// I/O 訪問量過大,產(chǎn)生性能衰減
no-appendfsync-on-rewrite yes

// AOF 文件容量的增長率
auto-aof-rewrite-percentage 100

// AOF 文件的最低容量犁嗅,就是當前文件的大小大于此值時边涕,就會進行重寫。當然這只是其中一個條件愧哟。
auto-aof-rewrite-min-size 64mb

添加鍵值對數(shù)據(jù)奥吩,觀察 AOF 文件

這里在命令行中設置,以便立刻生效

[root@s1 ~]# redis-cli
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "no"
127.0.0.1:6379> config set appendonly yes
OK
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "yes"

進行簡單的數(shù)據(jù)添加操作

127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> set hello python
OK
127.0.0.1:6379> set hello redis
OK
127.0.0.1:6379> incr nums
(integer) 1
127.0.0.1:6379> incr nums
(integer) 2
127.0.0.1:6379> incr nums
(integer) 3
127.0.0.1:6379> incr nums
(integer) 4
127.0.0.1:6379> rpush li a
(integer) 1
127.0.0.1:6379> rpush li b
(integer) 2
127.0.0.1:6379> rpush li b
(integer) 3
127.0.0.1:6379> rpush li c
(integer) 4
127.0.0.1:6379> exit

查看 AOF 文件

[root@s1 ~]# head appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
SET
$5
hello

主動觸發(fā)

先備份一份目前的 AOF 文件

[root@s1 ~]# cp /appendonly.aof{,.bak}

執(zhí)行命令 bgrewriteaof

127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "yes"
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

最后對比兩個文件的內(nèi)容的不同之處蕊梧。

RDB 和 AOF

區(qū)別

image

如何抉擇

從服務器開啟 RDB

始終開啟 AOF

不要使用主機的全部內(nèi)存

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市腮介,隨后出現(xiàn)的幾起案子肥矢,更是在濱河造成了極大的恐慌,老刑警劉巖叠洗,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甘改,死亡現(xiàn)場離奇詭異,居然都是意外死亡灭抑,警方通過查閱死者的電腦和手機十艾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腾节,“玉大人忘嫉,你說我怎么就攤上這事荤牍。” “怎么了庆冕?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵康吵,是天一觀的道長。 經(jīng)常有香客問我访递,道長晦嵌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任拷姿,我火速辦了婚禮惭载,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘响巢。我一直安慰自己描滔,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布抵乓。 她就那樣靜靜地躺著伴挚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪灾炭。 梳的紋絲不亂的頭發(fā)上茎芋,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音蜈出,去河邊找鬼田弥。 笑死,一個胖子當著我的面吹牛铡原,可吹牛的內(nèi)容都是我干的偷厦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼燕刻,長吁一口氣:“原來是場噩夢啊……” “哼只泼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卵洗,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤请唱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后过蹂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體十绑,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年酷勺,在試婚紗的時候發(fā)現(xiàn)自己被綠了本橙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡脆诉,死狀恐怖甚亭,靈堂內(nèi)的尸體忽然破棺而出贷币,到底是詐尸還是另有隱情,我是刑警寧澤狂鞋,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布片择,位于F島的核電站,受9級特大地震影響骚揍,放射性物質(zhì)發(fā)生泄漏字管。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一信不、第九天 我趴在偏房一處隱蔽的房頂上張望嘲叔。 院中可真熱鬧,春花似錦抽活、人聲如沸硫戈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丁逝。三九已至,卻和暖如春梭姓,著一層夾襖步出監(jiān)牢的瞬間霜幼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工誉尖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留罪既,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓铡恕,卻偏偏與公主長得像琢感,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子探熔,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容