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

守護(hù)進(jìn)程的方式啟動(dòng)服務(wù)時(shí),即使執(zhí)行啟動(dòng)服務(wù)命令的終端關(guān)閉,服務(wù)仍然可以在后臺(tái)運(yùn)行。

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

  1. /lib/systemd/system目錄下創(chuàng)建一個(gè)腳本文件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 開啟自啟動(dòng)時(shí)候的順序, 指定的服務(wù)必須先于次此服務(wù)啟動(dòng),一般是網(wǎng)絡(luò)服務(wù)啟動(dòng)后啟動(dòng)
[Service] 表示這里是服務(wù)信息配置塊
Type 指定啟動(dòng)服務(wù)的類型, simple 是默認(rèn)的方式
EnvironmentFile 指定服務(wù)啟動(dòng)時(shí)用到的配置文件
ExecStart 是啟動(dòng)服務(wù)的命令
ExecStop 是停止服務(wù)的指令
[Install] 表示這是是安裝信息配置塊
WantedBy 是以哪種方式啟動(dòng):multi-user.target表明當(dāng)系統(tǒng)以多用戶方式(默認(rèn)的運(yùn)行級(jí)別)啟動(dòng)時(shí),這個(gè)服務(wù)需要被自動(dòng)運(yùn)行。

授權(quán)在主機(jī)啟動(dòng)的時(shí)候同時(shí)啟動(dòng)服務(wù)

systemctl enable redis.service

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

  1. 使用 systemctl 操作

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

systemctl daemon-reload

啟動(dòng)服務(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ù)若都注釋掉,則會(huì)監(jiān)聽服務(wù)器上的所有 ip
可以指定一個(gè)或者多個(gè),打開注釋。
注意此配置項(xiàng)可能在 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
... 略 ...

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

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

這種方式執(zhí)行,默認(rèn) Redis 服務(wù)侯會(huì)在前臺(tái)運(yùn)行。

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

daemonize yes   # 守護(hù)進(jìn)程的方式啟動(dòng)服務(wù)

客戶端指定端口訪問

redis-cli -p 6379

手動(dòng)停止服務(wù)

redis-cli -p 6379 shutdown

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

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

移動(dòng) 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,過期時(shí)間(秒)
px,過期時(shí)間(毫秒)
nx,假如設(shè)置為True,則只有 name 不存在時(shí),當(dāng)前 set 操作才執(zhí)行
xx,假如設(shè)置為True,則只有 name 存在時(shí),當(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 不存在時(shí),執(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,并且指的過期時(shí)間(單位: 秒)

Example

127.0.0.1:6379> setex name 5 shark
OK

get

獲取一個(gè) key 的 value

127.0.0.1:6379> get name
"shark"

ttl

查看一個(gè) key 的過期時(shí)間

127.0.0.1:6379> ttl age
(integer) -1

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

expire

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

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

persist key

移除 key 的過期時(shí)間

mset

一次添加多個(gè)值

127.0.0.1:6379> mset name shark age 10
OK

mget

一次獲取多個(gè) key 的值

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

incr

對一個(gè) key 的值自增 1

127.0.0.1:6379> incr age
(integer) 11

decr

對一個(gè) key 的值自減 1

127.0.0.1:6379> DECR age
(integer) 10

append

向一個(gè) 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

刪除 一個(gè)或者多個(gè) key

127.0.0.1:6379> del name age
(integer) 2

EXISTS

判斷一個(gè) 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存儲(chǔ)的類型,如果不存在則返回none

type key

keys

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

  • * 匹配所有
  • ? 匹配任意一個(gè)
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

返回?cái)?shù)據(jù)庫種 key 的總數(shù)

dbsize

EXPIRE

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

b. List 操作

lpush

向列表左端添加元素,values是按左到右依次插入的,返回值為列表中元素個(gè)數(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

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

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

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

image
127.0.0.1:6379> LINDEX list 0
"c"

LRANGE

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

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

LPUSHX

向列表左端添加元素,只有key存在時(shí)才可以添加

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

將左端列表元素彈出,會(huì)將其從列表中刪除,如果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

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

  • count > 0: 從列表的頭開始,向尾部搜索,移除與value相等的元素,移除count個(gè)
  • count < 0: 從列表尾部開始,向頭部搜索,移除與value相等的元素,移除-count個(gè)
  • count == 0: 移除列表中所有與value相等的

c. Hash

image

HSET key field value

將哈希表key中的域 (field) 設(shè)置成指定的value,如果key不存在則新建一個(gè)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不存在時(shí)才可以成功,如果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]

同時(shí)將多個(gè)field-value設(shè)定到hash表中,如果field已存在值則會(huì)被覆蓋掉

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

HMGET key field [field]

同時(shí)獲得key存儲(chǔ)的hansh表中多個(gè)field的值,如果不存在則返回(nil)

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

HGETALL key

返回key存儲(chǔ)的所有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中存儲(chǔ)的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中存儲(chǔ)的hash表中field的數(shù)量

127.0.0.1:6379> HLEN userinfo
(integer) 4

HINCRBY key field increment

給key中存儲(chǔ)的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中存儲(chǔ)的hash表field增加increment,可以為浮點(diǎn)數(shù),參照字符串處理

127.0.0.1:6379> HINCRBYFLOAT userinfo salary 150.56
"150.56"

HDEL key field [field]

刪除key中存儲(chǔ)的hash表的field,可以刪除一個(gè)或多個(gè),成功返回被移除域的數(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 中集合是通過哈希表實(shí)現(xiàn)的。

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

// 返回一個(gè)集合中的所有成員
SMEMBERS key

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

// 返回所有集合的差集,就是存在于第一個(gè)集合中,且不存在于其他集合中的成員
SDIFF key [key ...]

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

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

// 差集, 返回第一集合中獨(dú)有的元素
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ù)另外一個(gè)值來進(jìn)行比較,所以,對于有序集合,每一個(gè)元素有兩個(gè)值,即:值和分?jǐn)?shù),分?jǐn)?shù)專門用來做排序。

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

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

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

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

// 返回有序集合中的所有成員及其索引號(hào)(分?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)下面的錯(cuò)誤,是操作的命令和這個(gè)命令所能操作的數(shù)據(jù)類型不符合。

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

三、Redis 的認(rèn)證連接

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

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

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

// 使用 auth 進(jìn)行密碼認(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àng)指定密碼,會(huì)出現(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ū)動(dòng),且你的機(jī)器上能正常使用 PHP。

安裝 phpredis 驅(qū)動(dòng)

點(diǎn)我進(jìn)入下載頁面,,注意選擇版本

1. 下載解壓后,進(jìn)入解壓后的目錄

[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 進(jìn)行配置并編譯安裝

配置

[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

五、持久化存儲(chǔ)

1. 持久化存儲(chǔ)的方式介紹

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

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

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

2. RDB

a. 什么是RDB

和 MySQL 中的 mysqldump 差不多一個(gè)道理。

image

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

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

image

阻塞

image
保存 RDB 文件的策略

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

第二種情況,主動(dòng)執(zhí)行 bgsave 命令 (異步,非阻塞 )

image
  • 文件策略和 save 相同

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

自動(dòng)觸發(fā),就是通過對 Redis 的配置文件重相關(guān)選項(xiàng)的修改,當(dāng)達(dá)到某個(gè)配置好的條件后,自動(dòng)生成 RDB 文件
,其內(nèi)部使用的是 bgsave 命令。

配置文件中相關(guān)選項(xiàng)的默認(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 文件

每次檢查都會(huì)建立一個(gè)新的檢查點(diǎn),以便用于下次檢查作為參考信息。

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

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

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

假如 bgsave 執(zhí)行中發(fā)生錯(cuò)誤,是否停止寫入,默認(rèn)是 yes , 表示假如出錯(cuò),就停止寫入。
stop-writes-on-bgsave-error yes

是否使用壓縮|
rdbcompression yes

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

建議的最佳配置

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

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

使用不同端口號(hào)進(jìn)行區(qū)分,因?yàn)椋锌赡軙?huì)在同一臺(tái)主機(jī)上開啟多個(gè) Redis 實(shí)例。
防止多個(gè)實(shí)例產(chǎn)生的數(shù)據(jù)信息寫到一個(gè)文件中。
dbfilename dump-${port}.rdb

指定一個(gè)大硬盤的路徑
dir /redis_data

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

采用壓縮
rdbcompression yes

進(jìn)行校驗(yàn)
rdbchecksum yes

實(shí)驗(yàn)

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

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

假如你的 Redis 服務(wù)器允許客戶端可以從非本機(jī)訪問,應(yīng)該在配置文件中,把 protected-mode 的值設(shè)置問 no。

這樣的話,客戶端就可以從其他主機(jī)訪問 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ù)時(shí),只需要保證此文件完好,并且在配置文件中指定的目錄下即可。這樣 Rdis 啟動(dòng)時(shí)就會(huì)把此文件中的數(shù)據(jù)恢復(fù)到當(dāng)前的服務(wù)器中。

bgsave 命令和 save基本一樣,就是 bgsave 命令不會(huì)產(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í)行一個(gè)命令保存一次

不保存

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

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

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

在這種模式下,每次執(zhí)行完一個(gè)命令之后, WRITE 和 SAVE 都會(huì)被執(zhí)行。

另外,因?yàn)?SAVE 是由 Redis 主進(jìn)程執(zhí)行的,所以在 SAVE 執(zhí)行期間,主進(jìn)程會(huì)被阻塞,不能接受命令請求。

AOF 三種保存模式的比較

因?yàn)樽枞僮鲿?huì)讓 Redis 主進(jìn)程無法持續(xù)處理請求, 所以一般說來, 阻塞操作執(zhí)行得越少、完成得越快, Redis 的性能就越好。

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

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

模式 3 的安全性是最高的, 但性能也是最差的, 因?yàn)榉?wù)器必須阻塞直到命令信息被寫入并保存到磁盤之后, 才能繼續(xù)處理請求。

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

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

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

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

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

注意, 因?yàn)?Redis 的命令只能在客戶端的上下文中被執(zhí)行, 而 AOF 還原時(shí)所使用的命令來自于 AOF 文件, 而不是網(wǎng)絡(luò), 所以程序使用了一個(gè)沒有網(wǎng)絡(luò)連接的偽客戶端來執(zhí)行命令。

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

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

AOF 的重寫機(jī)制

為什么需要重寫機(jī)制

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

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

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

重新機(jī)制是如何實(shí)現(xiàn)的

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

考慮這樣一個(gè)情況, 如果服務(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] 。

如果我們要保存這個(gè)列表的當(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 重寫的實(shí)現(xiàn)原理。

基本都步驟

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

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

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

bgrewriteaof

image

配置文件實(shí)現(xiàn)

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

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

重寫流程圖

image

對于上圖有四個(gè)關(guān)鍵點(diǎn)補(bǔ)充一下:

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

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

配置示例

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

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

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

// 當(dāng)執(zhí)行 AOF 重寫時(shí),是否繼續(xù)執(zhí)行平常普通的 AOF 操作。
// 這里設(shè)置文件  yes , 表示不執(zhí)行
// 因?yàn)榧偃?,同時(shí)執(zhí)行,兩種操作都會(huì)對磁盤 I/O 進(jìn)行訪問,造成
// I/O 訪問量過大,產(chǎn)生性能衰減
no-appendfsync-on-rewrite yes

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

// AOF 文件的最低容量,就是當(dāng)前文件的大小大于此值時(shí),就會(huì)進(jìn)行重寫。當(dāng)然這只是其中一個(gè)條件。
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"

進(jìn)行簡單的數(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

主動(dòng)觸發(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

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

RDB 和 AOF

區(qū)別

image

如何抉擇

從服務(wù)器開啟 RDB

始終開啟 AOF

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文鏈接: http://www.itdecent.cn/p/2a9c21bfeca8 一、安裝 1. 官網(wǎng)下載...
    運(yùn)維開發(fā)_西瓜甜閱讀 5,125評(píng)論 0 22
  • 原帖地址:http://www.itdecent.cn/p/2f14bc570563 redis概述 Redis...
    onlyHalfSoul閱讀 2,227評(píng)論 0 28
  • Redis是啥 Redis是一個(gè)開源的key-value存儲(chǔ)系統(tǒng),由于擁有豐富的數(shù)據(jù)結(jié)構(gòu),又被其作者戲稱為數(shù)據(jù)結(jié)構(gòu)...
    一凡呀閱讀 1,232評(píng)論 0 5
  • 【本教程目錄】 1.redis是什么2.redis的作者3.誰在使用redis4.學(xué)會(huì)安裝redis5.學(xué)會(huì)啟動(dòng)r...
    徐猿猿閱讀 1,918評(píng)論 0 35
  • 前言 在上一篇文章中,介紹了Redis內(nèi)存模型,從這篇文章開始,將依次介紹Redis高可用相關(guān)的知識(shí)——持久化、復(fù)...
    Java架構(gòu)閱讀 2,495評(píng)論 3 21

友情鏈接更多精彩內(nèi)容