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

守護進程的方式啟動服務(wù)時壁畸,即使執(zhí)行啟動服務(wù)命令的終端關(guān)閉短蜕,服務(wù)仍然可以在后臺運行。

配置 centos7 systemd 管理 redis 服務(wù)

  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ù)必須先于次此服務(wù)啟動,一般是網(wǎng)絡(luò)服務(wù)啟動后啟動
[Service] 表示這里是服務(wù)信息配置塊
Type 指定啟動服務(wù)的類型, simple 是默認(rèn)的方式
EnvironmentFile 指定服務(wù)啟動時用到的配置文件
ExecStart 是啟動服務(wù)的命令
ExecStop 是停止服務(wù)的指令
[Install] 表示這是是安裝信息配置塊
WantedBy 是以哪種方式啟動:multi-user.target表明當(dāng)系統(tǒng)以多用戶方式(默認(rèn)的運行級別)啟動時镊靴,這個服務(wù)需要被自動運行铣卡。

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

systemctl enable redis.service

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

  1. 使用 systemctl 操作

刷新配置,讓 systemd 識別剛剛添加的 redis 服務(wù)

systemctl daemon-reload

啟動服務(wù)

systemctl start redis

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

設(shè)置監(jiān)聽地址

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

bind 參數(shù)若都注釋掉偏竟,則會監(jiān)聽服務(wù)器上的所有 ip
可以指定一個或者多個煮落,打開注釋。
注意此配置項可能在 71 行左右踊谋。默認(rèn)是 bind 127.0.0.1

檢查并測試

檢查默認(rèn)端口 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
... 略 ...

手動使用命令指定配置文件啟動服務(wù)

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

這種方式執(zhí)行蝉仇,默認(rèn) Redis 服務(wù)侯會在前臺運行。

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

daemonize yes   # 守護進程的方式啟動服務(wù)

客戶端指定端口訪問

redis-cli -p 6379

手動停止服務(wù)

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 中設(shè)置值害驹,默認(rèn),不存在則創(chuàng)建蛤育,存在則修改
參數(shù):
ex宛官,過期時間(秒)
px,過期時間(毫秒)
nx瓦糕,假如設(shè)置為True底洗,則只有 name 不存在時,當(dāng)前 set 操作才執(zhí)行
xx咕娄,假如設(shè)置為True亥揖,則只有 name 存在時,當(dāng)前 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

設(shè)置值圣勒,只有name 不存在時费变,執(zhí)行設(shè)置操作(添加)

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

設(shè)置 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

設(shè)置一個 key 的過期時間(單位: 秒)

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

EXPIRE

設(shè)置key的過期時間空扎,如果key不存在則返回0蝶押,否則返回1.如果key已經(jīng)存在過期時間則再設(shè)置會覆蓋之前的過期時間

b. List 操作

lpush

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

最后加入到元素橙困,在列表的第一位

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

通過元素在列表中的位置獲取到這個元素,位置稱為索引號/下標(biāo)凡傅,

位置支持正整數(shù)和負(fù)整數(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) 設(shè)置成指定的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設(shè)置成指定的值喳张,只有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設(shè)定到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)重復(fù)的數(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ù)另外一個值來進行比較赌蔑,所以俯在,對于有序集合,每一個元素有兩個值娃惯,即:值和分?jǐn)?shù)跷乐,分?jǐn)?shù)專門用來做排序。

// 向有序集合添加一個或多個成員趾浅,或者更新已存在成員的分?jǐn)?shù)
ZADD key score1 member1 [score2 member2]

// score1 是成員的分?jǐn)?shù)
// member 是有序集合中的成員

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

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

// 返回有序集合中的所有成員及其索引號(分?jǐn)?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 的認(rèn)證連接

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

mypassword 就是密碼了,更改好后重啟服務(wù)

使用設(shè)置好的密碼認(rèn)證

// 使用 auth 進行密碼認(rèn)證
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 服務(wù)及 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)選項的修改舶赔,當(dāng)達到某個配置好的條件后,自動生成 RDB 文件
谦秧,其內(nèi)部使用的是 bgsave 命令竟纳。

配置文件中相關(guān)選項的默認(rè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 文件的配置信息

默認(rèn)文件名
dbfilename dump.rdb

默認(rèn)文件保存位置
dir ./

假如 bgsave 執(zhí)行中發(fā)生錯誤际歼,是否停止寫入,默認(rèn)是 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 服務(wù)器允許客戶端可以從非本機訪問客给,應(yīng)該在配置文件中,把 protected-mode 的值設(shè)置問 no肢簿。

這樣的話靶剑,客戶端就可以從其他主機訪問 Redis 服務(wù)器了蜻拨,并且不需要密碼。

重啟服務(wù)后桩引,在 Rdis 命令行客戶端中輸入 save 命令缎讼。

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

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

恢復(fù)數(shù)據(jù)時坑匠,只需要保證此文件完好血崭,并且在配置文件中指定的目錄下即可。這樣 Rdis 啟動時就會把此文件中的數(shù)據(jù)恢復(fù)到當(dāng)前的服務(wù)器中厘灼。

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

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

查看當(dāng)前服務(wù)器的數(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ā)疾就, 在一般情況下澜术, 這種模式只需要為寫入阻塞, 因此它的寫入性能要比后面兩種模式要高猬腰, 當(dāng)然鸟废, 這種性能的提高是以降低安全性為代價的: 在這種模式下, 如果運行的中途發(fā)生停機姑荷, 那么丟失數(shù)據(jù)的數(shù)量由操作系統(tǒng)的緩存沖洗策略決定盒延。

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

模式 3 的安全性是最高的计露, 但性能也是最差的陨闹, 因為服務(wù)器必須阻塞直到命令信息被寫入并保存到磁盤之后, 才能繼續(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)絡(luò)連接的偽客戶端(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)絡(luò)消玄, 所以程序使用了一個沒有網(wǎng)絡(luò)連接的偽客戶端來執(zhí)行命令跟伏。

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

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

AOF 的重寫機制

為什么需要重寫機制

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

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

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

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

實際上裕偿, AOF 重寫并不需要對原有的 AOF 文件進行任何寫入和讀取洞慎, 它針對的是數(shù)據(jù)庫中鍵的當(dāng)前值,也就是源數(shù)據(jù)從目前的內(nèi)存中獲取嘿棘。

考慮這樣一個情況劲腿, 如果服務(wù)器對鍵 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]

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

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

除了列表之外,集合房午、字符串矿辽、有序集、哈希表等鍵也可以用類似的方法來保存狀態(tài)郭厌。

根據(jù)鍵的類型嗦锐, 使用適當(dāng)?shù)膶懭朊顏碇噩F(xiàn)鍵的當(dāng)前值, 這就是 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 命令 不需要重啟服務(wù)嘱根,不便于統(tǒng)一管理
配置文件實現(xiàn) 需要重啟服務(wù),便于進行統(tǒng)一管理

bgrewriteaof

image

配置文件實現(xiàn)

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

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

重寫流程圖

image

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

在重寫期間该抒,由于主進程依然在響應(yīng)命令,為了保證最終備份的完整性顶燕;因此它依然會寫入舊的AOF file中凑保,如果重寫失敗冈爹,能夠保證數(shù)據(jù)不丟失。當(dāng)然這個是可以通過配置來決定在重寫期間是否進行主進程普通的 AOF 操作欧引。
為了把重寫期間響應(yīng)的寫入信息也寫入到新的文件中频伤,因此也會為子進程保留一個buf,防止新寫的file丟失數(shù)據(jù)芝此。
重寫是直接把當(dāng)前內(nèi)存的數(shù)據(jù)生成對應(yīng)命令憋肖,并不需要讀取老的AOF文件進行分析、命令合并婚苹。
AOF文件直接采用的文本協(xié)議岸更,主要是兼容性好、追加方便膊升、可讀性高可認(rèn)為修改修復(fù)怎炊。

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

配置示例

// 要想使用 AOF 的全部功能结胀,需要設(shè)置為  yes
appendonly yes

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

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

// 當(dāng)執(zhí)行 AOF 重寫時责循,是否繼續(xù)執(zhí)行平常普通的 AOF 操作糟港。
// 這里設(shè)置文件  yes , 表示不執(zhí)行
// 因為假如,同時執(zhí)行院仿,兩種操作都會對磁盤 I/O 進行訪問秸抚,造成
// I/O 訪問量過大,產(chǎn)生性能衰減
no-appendfsync-on-rewrite yes

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

// AOF 文件的最低容量歹垫,就是當(dāng)前文件的大小大于此值時剥汤,就會進行重寫。當(dāng)然這只是其中一個條件排惨。
auto-aof-rewrite-min-size 64mb

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

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

[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

如何抉擇

從服務(wù)器開啟 RDB

始終開啟 AOF

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鹿驼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辕宏,更是在濱河造成了極大的恐慌畜晰,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瑞筐,死亡現(xiàn)場離奇詭異凄鼻,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門块蚌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闰非,“玉大人,你說我怎么就攤上這事匈子『犹ィ” “怎么了闯袒?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵虎敦,是天一觀的道長。 經(jīng)常有香客問我政敢,道長其徙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任喷户,我火速辦了婚禮唾那,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘褪尝。我一直安慰自己闹获,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布河哑。 她就那樣靜靜地躺著避诽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪璃谨。 梳的紋絲不亂的頭發(fā)上沙庐,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機與錄音佳吞,去河邊找鬼拱雏。 笑死,一個胖子當(dāng)著我的面吹牛底扳,可吹牛的內(nèi)容都是我干的铸抑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼衷模,長吁一口氣:“原來是場噩夢啊……” “哼鹊汛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起算芯,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柒昏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后熙揍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體职祷,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了有梆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片是尖。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖泥耀,靈堂內(nèi)的尸體忽然破棺而出饺汹,到底是詐尸還是另有隱情,我是刑警寧澤痰催,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布兜辞,位于F島的核電站,受9級特大地震影響夸溶,放射性物質(zhì)發(fā)生泄漏逸吵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一缝裁、第九天 我趴在偏房一處隱蔽的房頂上張望扫皱。 院中可真熱鬧,春花似錦捷绑、人聲如沸韩脑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽段多。三九已至,卻和暖如春厕怜,著一層夾襖步出監(jiān)牢的瞬間衩匣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工粥航, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留琅捏,地道東北人。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓递雀,卻偏偏與公主長得像柄延,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缀程,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,446評論 2 359

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