Redis
一、安装
1. 官网下载源码
image.png2. 安装依赖包
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
- 配置 redis
mkdir /etc/redis
cd redis-4.0.10/
cp redis.conf /etc/redis/6379.conf
cp utils/redis_init_script /etc/init.d/redis
chmod 755 /etc/init.d/redis
编辑配置文件 /etc/redis/6379.conf
daemonize yes # 守护进程的方式启动服务
守护进程的方式启动服务时,即使执行启动服务命令的终端关闭,服务仍然可以在后台运行。
centos7 正统配置 systemd 管理 redis 服务
- 在
/lib/systemd/system
目录下创建一个脚本文件redis.service,里面的内容如下:
[Unit]
Description=Redis
After=network.target
[Service]
Type=simple
EnvironmentFile=-/etc/redis/6379.conf
ExecStart=/usr/local/bin/redis-server --daemonize no
ExecStop=/usr/local/bin/redis-cli shutdown
[Install]
WantedBy=multi-user.target
[Unit] 表示这是基础信息配置块
Description 是描述
After 开启自启动时候的顺序, 指定的服务必须先于次此服务启动,一般是网络服务启动后启动
[Service] 表示这里是服务信息配置块
Type 指定启动服务的类型, simple 是默认的方式
EnvironmentFile 指定服务器的时用到的配置文件
ExecStart 是启动服务的命令
ExecStop 是停止服务的指令
[Install] 表示这是是安装信息配置块
WantedBy 是以哪种方式启动:multi-user.target表明当系统以多用户方式(默认的运行级别)启动时,这个服务需要被自动运行。
关于 server
文件的详细参数介绍参考这里
- 使用 systemd 操作
刷新配置,让 systemd
识别刚刚添加的 redis
服务
systemctl daemon-reload
启动服务
systemctl start redis
设置监听地址
shell> vi /etc/redis/63779.conf
# bind 127.0.0.1 192.168.1.10
bind
参数若都注释掉,则会监听服务器上的所有 ip
可以指定一个或者多个,打开注释。
注意此配置项可能在71
行左右。默认是bind 127.0.0.1
检查并测试
检查默认端口 6379
是否监听
``
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
客户端指定端口访问
redis-cli -p 6379
手动停止服务
redis-cli -p 6379 shutdown
通用命令
二、数据类型
1. 数据类型的基本介绍
image.png2. 数据类型的基本操作
a.String
set
127.0.0.1:6379> help set
SET key value [EX seconds] [PX milliseconds] [NX|XX]
在 Redis 中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,假如设置为True,则只有 name 不存在时,当前 set 操作才执行
xx,假如设置为True,则只有 name 存在时,当前 set 操作才执行
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
不存在时,执行设置操作(添加)
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 已经过期
expire
设置一个 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
inrc
对一个 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 的值后面追加内容
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 表示不存在
TYPE
返回key存储的类型,如果不存在则返回none
type key
keys
通过通配符来获取匹配到的 key
一般不在生产环境中使用此命令
-
*
匹配所有 -
?
匹配任意一个
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
返回数据库种 key
的总数
dbsize
EXPIRE
设置key的过期时间,如果key不存在则返回0,否则返回1.如果key已经存在过期时间则再设置会覆盖之前的过期时间
b. List
操作
lpush
向列表左端添加元素,values是按左到右依次插入的,返回值为列表中元素个数,列表元素可以重复
最后加入到元素,在列表的第一位
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
通过元素在列表中的位置获取到这个元素,位置称为索引号/下标,
位置支持正整数和负整数
列表中元素的位置中,第一位是 0,最后一位是列表总长度减 1 或者是 -1
千锋云计算127.0.0.1:6379> LINDEX list 0
"c"
LRANGE
获取列表表一个区间的值
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
删除列表中指定的值,返回值为删除的元素的个数,count值有以下几种:
- count > 0: 从列表的头开始,向尾部搜索,移除与value相等的元素,移除count个
- count < 0: 从列表尾部开始,向头部搜索,移除与value相等的元素,移除-count个
- count == 0: 移除列表中所有与value相等的
c. Hash
image.png
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的数量
127.0.0.1:6379> HLEN userinfo
(integer) 4
HINCRBY key field increment
给key中存储的hash表field增加increment,如果此field不存在,则创建值为0的field,然后增加increment。操作的字段必须是整数,参照字符串处理
127.0.0.1:6379> HINCRBY userinfo age 10
(integer) 10
HINCRBYFLOAT key field increment
给key中存储的hash表field增加increment,可以为浮点数,参照字符串处理
127.0.0.1:6379> HINCRBYFLOAT userinfo salary 150.56
"150.56"
HDEL key field [field]
删除key中存储的hash表的field,可以删除一个或多个,成功返回被移除域的数量
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 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的。
// 向集合中添加一个或者多个元素
SADD key member [member ...]
// 获取集合中元素的个数
SCARD key
// 返回所有集合的差集,就是存在于第一个集合中,且不存在于其他集合中的成员
SDIFF key [key ...]
// 交集,就是所有集合共有的元素
SINTER key [key ...]
// 并集, 就是所有集合的元素合并在一起,并去重
SUNION key [key ...]
// 返回一个集合中的所有成员
SMEMBERS 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 操作
有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
// 向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZADD key score1 member1 [score2 member2]
// 获取有序集合的元素个数
ZCARD key
三、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
选项指定密码,会出现警告信息
[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 前, 我们需要确保已经安装了 redis 服务及 PHP redis 驱动,且你的机器上能正常使用 PHP。
安装 phpredis 驱动
点我进入下载页面,,注意选择版本
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. 执行如下命令,生成配置工具
在解压后的 php 目录中执行如下命令
shell> phpize
image.png
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 将数据库的快照(snapshot)以二进制的方式保存到磁盘中。
-
AOF 则以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件,以此达到记录数据库状态的目的。
2. RDB
a. 什么是RDB
和 MySQL 中的 mysqldump
差不多一个道理。
b. 什么情况下会触发 RDB
第一种情况,主动执行 save
命令(同步,阻塞 ,就是save
命令执行完毕后才能执行后续的其他命令操作)
千锋云计算
阻塞
千锋云计算保存 RDB 文件的策略
每次创建新的文件,并且替换原来旧文件(假如存在旧的文件)
第二种情况,主动执行 ·bgsave` 命令 (异步,非阻塞 )
image.png- 文件策略和
save
相同
第三种情况,自动触发
自动触发,就是通过对 Redis 的配置文件重相关选项的修改,当达到某个配置好的条件后,自动生成 RDB 文件
,其内部使用的是 bgsave
命令。
配置文件中相关选项的默认值如下表:
配置 | seconds | changes | 含义 |
---|---|---|---|
save | 900 | 1 | 每隔 900 秒检查一次,假如至少有 1 条数据改变,就生成新的 RDB 文件 |
save | 300 | 10 | 每隔 300 秒检查一次,假如至少有 10 条数据改变,就生成新的 RDB 文件 |
save | 60 | 10000 | 每隔 60 秒检查一次,假如至少有 10000 条数据改变,就生成新的 RDB 文件 |
每次检查都会建立一个新的检查点,以便用于下次检查作为参考信息。
关于 RDB 文件的配置信息
配置内容 | 含义 |
---|---|
dbfilename dump.rdb |
默认文件名 |
dir ./ |
默认文件保存位置 |
stop-writes-on-bgsave-error yes |
假如 bgsave 执行中发生错误,是否停止写入,默认是 yes , 表示假如出错,就停止写入。 |
rdbcompression yes |
是否使用压缩 |
rdbchecksum yes |
是否进行数据的校验 |
建议的最佳配置
关闭自动生成 RDB 文件
在配置文件中注释掉如下内容
#save 900 1
#save 300 10
#save 60 10000
使用不同端口号进行区分,因为,有可能会在同一台主机上开启多个 Redis 实例。
防止多个实例产生的数据信息写到一个文件中。
dbfilename dump-${port}.rdb
指定一个大硬盘的路径
dir /redis_data
假如出现错误,停止继续写入
stop-writes-on-bgsave-error yes
采用压缩
rdbcompression yes
进行校验
rdbchecksum yes
实验
修改配置文件中的相关选项,使其成为如下内容中显示的值:
dbfilename dump-6379.rdb
dir /redis_data # 此目录需要自己创建
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>
该命令将在配置文件重配置的指定目录中创建 dump-6379.rdb
文件。
恢复数据时,只需要保证此文件完好,并且在配置文件中指定的目录下即可。这样 Rdis 启动时就会把此文件中的数据恢复到当前的服务器中。
bgsave
命令基本一样,就是 bgsave
命令不会产生阻塞
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379>
查看当前服务器的数据文件目录
127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/"
2. AOF
什么是 AOF
AOF 文件保存了 Redis 的数据库状态, 而文件里面包含的都是符合 Redis 通讯协议格式的命令文本。
image.pngAOF 保存的模式
Redis 目前支持三种 AOF 保存模式,它们分别是:
-
AOF_FSYNC_NO
:不保存。 -
AOF_FSYNC_EVERYSEC
:每一秒钟保存一次。(生产中一般选这种) -
AOF_FSYNC_ALWAYS
:每执行一个命令保存一次
不保存
在这种模式下, SAVE 只会在以下任意一种情况中被执行:
Redis 被关闭
AOF 功能被关闭
系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)
这三种情况下的 SAVE 操作都会引起 Redis 主进程阻塞。
每执行一个命令保存一次
在这种模式下,每次执行完一个命令之后, WRITE 和 SAVE 都会被执行。
另外,因为 SAVE 是由 Redis 主进程执行的,所以在 SAVE 执行期间,主进程会被阻塞,不能接受命令请求。
AOF 三种保存模式的比较
因为阻塞操作会让 Redis 主进程无法持续处理请求, 所以一般说来, 阻塞操作执行得越少、完成得越快, Redis 的性能就越好。
模式 1 的保存操作只会在AOF 关闭或 Redis 关闭时执行, 或者由操作系统触发, 在一般情况下, 这种模式只需要为写入阻塞, 因此它的写入性能要比后面两种模式要高, 当然, 这种性能的提高是以降低安全性为代价的: 在这种模式下, 如果运行的中途发生停机, 那么丢失数据的数量由操作系统的缓存冲洗策略决定。
模式 2 在性能方面要优于模式 3 , 并且在通常情况下, 这种模式最多丢失不多于 2 秒的数据, 所以它的安全性要高于模式 1 , 这是一种兼顾性能和安全性的保存方案。
模式 3 的安全性是最高的, 但性能也是最差的, 因为服务器必须阻塞直到命令信息被写入并保存到磁盘之后, 才能继续处理请求。
综合起来,三种 AOF 模式的操作特性可以总结如下:
模式 | WRITE 是否阻塞? | SAVE 是否阻塞? | 停机时丢失的数据量 | |
---|---|---|---|---|
AOF_FSYNC_NO |
阻塞 | 阻塞 | 操作系统最后一次对 AOF 文件触发 SAVE 操作之后的数据。 | |
AOF_FSYNC_EVERYSEC |
阻塞 | 不阻塞 | 一般情况下不超过 2 秒钟的数据。 | |
AOF_FSYNC_ALWAYS |
阻塞 | 阻塞 | 最多只丢失一个命令的数据。 |
AOF 方式下的数据还原
Redis 读取 AOF 文件并还原数据库的详细步骤如下:
创建一个不带网络连接的伪客户端(fake client)。
读取 AOF 所保存的文本,并根据内容还原出命令、命令的参数以及命令的个数。
根据命令、命令的参数和命令的个数,使用伪客户端执行该命令。
执行 2 和 3 ,直到 AOF 文件中的所有命令执行完毕。
完成第 4 步之后, AOF 文件所保存的数据库就会被完整地还原出来。
注意, 因为 Redis 的命令只能在客户端的上下文中被执行, 而 AOF 还原时所使用的命令来自于 AOF 文件, 而不是网络, 所以程序使用了一个没有网络连接的伪客户端来执行命令。
当程序读入这个 AOF 文件时, 它首先执行 SELECT 0 命令 —— 这个 SELECT 命令是由 AOF 写入程序自动生成的, 它确保程序可以将数据还原到正确的数据库上。
注意:
为了避免对数据的完整性产生影响, 在服务器载入数据的过程中, 只有和数据库无关的订阅与发布功能可以正常使用, 其他命令一律返回错误。
AOF 的重写机制
为什么需要重写机制
AOF 文件通过同步 Redis 服务器所执行的命令, 从而实现了数据库状态的记录, 但是, 这种同步方式会造成一个问题: 随着运行时间的流逝, AOF 文件会变得越来越大。
-
对同一个键的状态的多次不同操作,而最终得到一个结果。比如对列表的添加删除元素。
-
被频繁操作的键。比如累加
重新机制是如何实现的
实际上, AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取, 它针对的是数据库中键的当前值,也就是源数据从目前的内存中获取。
考虑这样一个情况, 如果服务器对键 list 执行了以下四条命令:
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 在数据库中的值就为 [1, 2, 3] 。
如果我们要保存这个列表的当前状态, 并且尽量减少所使用的命令数, 那么最简单的方式不是去 AOF 文件上分析前面执行的四条命令, 而是直接读取 list 键在数据库的当前值, 然后用一条 RPUSH 1 2 3 命令来代替前面的四条命令。
除了列表之外,集合、字符串、有序集、哈希表等键也可以用类似的方法来保存状态。
根据键的类型, 使用适当的写入命令来重现键的当前值, 这就是 AOF 重写的实现原理。
基本都步骤
for 遍历所有数据库:
if 如果数据库为空:
那么跳过这个数据库
else:
写入 SELECT 命令,用于切换数据库
for 选择一个库后,遍历这个库的所有键
if 如果键带有过期时间,并且已经过期,那么跳过这个键
if 根据数据的类型,进行相关操作。
AOF 重写的实现方式
方式 | 区别 |
---|---|
bgrewriteaof 命令 |
不需要重启服务,不便于统一管理 |
配置文件实现 | 需要重启服务,便于进行统一管理 |
bgrewriteaof
image.png
配置文件实现
image.png触发条件,必须同时满足如下条件
image.png配置示例
// 要想使用 AOF 的全部功能,需要设置为 yes
appendonly yes
// AOF 文件名,路径才看之前的 `dir` 配置项
appendfilename "appendonly.aof"
// AOF 的策略
appendfsync everysec
// 当执行 AOF 重新时,是否继续执行平常的 AOF 操作。
// 这里设置文件 yes , 表示不执行
no-appendfsync-on-rewrite no
// AOF 文件容量的增长率
auto-aof-rewrite-percentage 100
// AOF 文件的最低容量,就是当前文件的大小大于此值时,就会进行重写。当然这只是其中一个条件。
auto-aof-rewrite-min-size 64mb
当然这些配置项是支持在线设置的
image.png添加键值对数据,观察 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"
进行简单的数据添加操作
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
主动触发重新
先备份一份目前的 AOF 文件
[root@s1 ~]# cp /appendonly.aof{,.bak}
执行命令 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
最后对比两个文件的内容的不同之处。
RDB 和 AOF
区别
image.png如何抉择
从服务器开启 RDB
始终开启 AOF
不要使用主机的全部内存
六、主从复制
image.pngRdis 的主从复制特点
image.png1. 配置主从
实现方式同样有两种: 命令方式和配置文件方式
命令方式
只需要在从服务器上执行如下命令即可
slaveof 主服务器的IP 端口号
slaveof
命令是异步的,不阻塞。
并且此时,从服务器现有的数据会先被清空,之后再同步主服务器的数据。
停止一台从服务器的复制操作,在此台服务器上执行如下命令
slaveof no one
配置文件的方式如下
只需要在从服务器上配置即可
修改配置文件
假如主服务器 IP 是: 172.16.153.178
端口是: 6379
# slaveof <masterip> <masterport>
slaveof 172.16.153.178 6379
// 配置此服务器只提供读取操作
slave-read-only yes
之后重启从主机的 Redis 服务
查看主从信息
127.0.0.1:6379> info replication
七、主从 + Sentinel
哨兵模式
Redis Sentinel是Redis官方的高可用性解决方案。
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
-
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
-
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
-
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。
虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。
此种模式下,客户端要访问的 服务 IP 不是主节点,而是 sentiner
服务器的 IP。
架构图
image.pngRedis Sentinel 故障转移
image.png架构的扩展应用
image.png1. 配置主从
a. 快速生成主节点的配置文件
编译全新文件 /etc/redis/redis-6389.conf
, 添加如下内容
port 6380
daemonize yes
pidfile /var/run/redis-6380.pid
logfile /var/log/redis-6389.log
dir /redis/data/
b. 快速生成从节点的配置文件
[root@s1 ~]# sed 's/6380/6381/g' /etc/redis/redis-6380.conf > /etc/redis/redis-6381.conf
[root@s1 ~]# sed 's/6380/6382/g' /etc/redis/redis-6380.conf > /etc/redis/redis-6382.conf
查看配置文件内容,检验配置结果
[root@s1 ~]# cat /etc/redis/redis-6381.conf
port 6381
daemonize yes
pidfile /var/run/redis-6381.pid
logfile /var/log/redis-6381.log
dir /redis/data/
[root@s1 ~]# cat /etc/redis/redis-6382.conf
port 6382
daemonize yes
pidfile /var/run/redis-6382.pid
logfile /var/log/redis-6382.log
dir /redis/data/
[root@s1 ~]#
c. 配置主从关系
[root@s1 ~]# echo "slaveof 172.16.153.178 6380" >> /etc/redis/redis-6381.conf
[root@s1 ~]# echo "slaveof 172.16.153.178 6380" >> /etc/redis/redis-6382.conf
[root@s1 ~]#
d. 启动服务,并验证进程
[root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6380.conf
[root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6381.conf
[root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6382.conf
[root@s1 ~]# ps -ef |grep redis
root 4335 1 0 19:30 ? 00:00:03 /usr/local/bin/redis-server *:6380
root 4490 1 0 20:17 ? 00:00:00 /usr/local/bin/redis-server *:6381
root 4495 1 0 20:17 ? 00:00:00 /usr/local/bin/redis-server *:6382
root 4500 3755 0 20:17 pts/0 00:00:00 grep --color=auto redis
[root@s1 ~]#
假如日志中出现如下警告信息
4668:S 17 Feb 20:28:42.107 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
4668:S 17 Feb 20:28:42.107 # Server initialized
4668:S 17 Feb 20:28:42.108 # 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.
4668:S 17 Feb 20:28:42.108 * DB loaded from disk: 0.000 seconds
4668:S 17 Feb 20:28:42.110 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
解决办法
The TCP backlog...
方法1: 临时设置生效:
shell> sysctl -w net.core.somaxconn=1024
方法2: 永久生效:
修改/etc/sysctl.conf文件,增加一行
net.core.somaxconn=1024
然后执行命令
sysctl -p
WARNING overcommit_memory ...
方法1: 临时设置生效:
shell> sysctl -w vm.overcommit_memory=1
方法2: 永久生效:
修改/etc/sysctl.conf文件,增加一行
vm.overcommit_memory=1
然后执行命令
sysctl -p
e. 查看主从复制信息
image.png2. 配置 sentinel
获取程序
Sentinel 程序可以在编译后的 src 文档中发现, 它是一个命名为 redis-sentinel 的程序。
运行一个 Sentinel 所需的最少配置如下所示:
Redis 源码中包含了一个名为 sentinel.conf
的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。
运行一个 Sentinel 所需的最少配置如下所示:
// 监控一个 Redis 服务器
// 名称为 mymaster ,IP 为 127.0.0.1 端口为 6379
// 最后的 2 是指最少有 2 给 Sentinel 实例同意一台 redis 服务器宕机,才会执行故障转义。
sentinel monitor mymaster 127.0.0.1 6379 2
// Sentinel 认为 Redis 服务器已经断线所需的毫秒数。
sentinel down-after-milliseconds mymaster 60000
//
sentinel failover-timeout mymaster 180000
// 开始故障转义时,最多允许有多少个从服务器同时对新的主服务器进行同步数据。数字越小,完成整个故障转义所用的时间越长。
sentinel parallel-syncs mymaster 1
a. 获取并修改配置文件
快速创建三个 sentinel 配置文件
进入到 Redis 源码的目录下,执行如下命令
image.png
修改监听端口
image.png之后在每个 sentinel
配置文件中添加守护进程方式运行,
并修改dir
配置项的目录,
daemonize yes
dir /redis/data/
最后别忘了修改监控的主服务器的 IP 和端口正确的 6380
最终其中一个的配置文件应该是这样的
image.png
b. 启动服务并验证
启动服务的语法:
shell> redis-sentinel sentinel的配置文件
image.png
image.png
可以使用以下命令查看哨兵的信息
[root@s1 ~]# redis-cli -p 27001 info
...略...
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6380,slaves=2,sentinels=3
[root@s1 ~]#
3. 客户端如何连接使用 Sentinel
客户端需要知道所有 Sentinel 所有节点的 IP和一个 Master Name。
第一步从所有的 Sentinel 列表中得到一个有效的 Sentinel 节点。
image.png第二步向得到的 Sentinel 节点发送查询一个已知的 Master Name 的信息到请求,并得到 Master 节点的信息
image.png第三步向 Master 节点验证 Maset 角色的真实性
image.png第四步 客户端 和 Sentiel 之间建立发布订阅关系。
客户端订阅 Sentinel 的频道,一旦 Master 的 IP 信息有变化,客户端就会通过此频道发布的信息得知。
image.png
4. 故障演练
停止 Master 节点的服务
[root@s1 ~]# redis-cli -p 6380 shutdown
不断的刷新其中一个 Sentinel 节点的信息,观察最后一行信息的变化
[root@s1 ~]# redis-cli -p 27001 info
...略...
master0:name=mymaster,status=ok,address=127.0.0.1:6382,slaves=2,sentinels=3
八、 集群
1. 数据分区介绍
image.pnga. 数据分区的方式
image.png两者的对比
image.pngb. 哈希分区的三种方式
-
节点取余
-
一致性哈希
-
虚拟槽哈希
① 节点取余(不推荐使用)
image.png问题: 当向集群重添加一个节点时,数据迁移率太大
迁移前
迁移后
建议添加节点时,采用多倍扩容的方式
多倍扩容② 一致性哈希分区方式
基本规则,顺时针的方式式
image.png
一致性哈希的扩容
扩容前
扩容后
image.png特点总结
image.png③ 虚拟槽分区方式(Redis Cluster 使用了此方式)
虚拟槽的分配
image.png2.Redis 集群的优势
自动分割数据到不同的节点上。
整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
九、缓存设计和优化
jalksjdfkj
klajsdfklj
lkjasdlkjf
罗卡角六点十分几