深入了解 RedisRedis 高级特性
Posted 思想累积
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入了解 RedisRedis 高级特性相关的知识,希望对你有一定的参考价值。
1、Redis事务
Redis 事务:一次性,顺序性,排他性
- Redis 事务:一组命令的集合,一个事务中所有的命令的都会被序列化,执行中按照顺序执行。
- Redis 单条命令保证原子性,事务不保证原子性。
- Redis 事务没有隔离级别,发起执行命令才会执行。exec
Redis 执行事务:
- 开启事务(multi)
- 命令入队()
- 执行事务(exec)
# 执行事务
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379> set k1 v1 # 命令入队
QUEUED
127.0.0.1:6379> set k2 v1
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec # 执行事务
1) OK
2) OK
3) "v1"
4) OK
###########################################
# 放弃事务执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v1
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> DISCARD # 取消事务
OK
127.0.0.1:6379> get k4
(nil)
###########################################
# 编译异常:事务中所有命令都不会执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k6 v6
QUEUED
127.0.0.1:6379> exec # 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k5 # 所有命令都不会执行
(nil)
127.0.0.1:6379> get k4
(nil)
# 运行时异常,队列中存在语法性,执行命令时,其他命令可以正常执行。错误命令抛出异常
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> mulit
(error) ERR unknown command 'mulit'
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range # 执行事务报错但依旧执行
2) OK
3) OK
4) OK
5) "v3"
2、Redis 实现乐观锁
监控:watch
悲观锁:
无论做什么都会加锁
乐观锁
不会上锁,在更新数据的时候判断一下,在此期间是否有人修改过数据。
获取 version
更新时比较 version
Redis 监视测试
正常执行成功:
127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money # 监视 money 对象
OK
127.0.0.1:6379> multi # 事务正常执行成功
OK
127.0.0.1:6379> DECRBY money 200
QUEUED
127.0.0.1:6379> INCRBY out 200
QUEUED
127.0.0.1:6379> exec
1) (integer) 800
2) (integer) 200
多线程修改值:使用 watch 做 Redis 的乐观锁操作
127.0.0.1:6379> watch money # 监视 money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 100
QUEUED
127.0.0.1:6379> INCRBY out 100
QUEUED
127.0.0.1:6379> exec # 执行之前,另外一个线程修改了 money 的值
(nil)
#####################################
127.0.0.1:6379> get money
"800"
127.0.0.1:6379> set money 1000
OK
事务执行失败后
127.0.0.1:6379> unwatch # 先解锁
OK
127.0.0.1:6379> watch money # 再次监视
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 100
QUEUED
127.0.0.1:6379> INCRBY out 100
QUEUED
127.0.0.1:6379> exec # 比对监视的值是否发生变化,未变化可以执行成功
1) (integer) 900
2) (integer) 300
3、Redis.conf 配置文件
Redis 通过配置文件启动
- Redis 默认有 16 个数据库
Redis 6 之前是单线程的。Redis 基于内存操作,Redis 的瓶颈是根据原机器的内存和网络带宽。
Redis 是 C 语言写的,官方提供数据为 100000 + 的 QPS,不比 key-value 的 Menmecache 差!
3.1、单位:
配置文件对大小写单位不敏感
# Redis configuration file example
# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
3.2、可以包含多个配置文件
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include .\\path\\to\\local.conf
# include c:\\path\\to\\other.conf
3.3、网络
bind 127.0.0.1 # 绑定的 IP
protected-mode # 保护模式
port # 端口
3.4、通用配置
daemonize yes # 以守护方式运行,默认为 no
pidfile /var/run/redis_6379.pid # 如果以后台方式运行,需要制定一个 pid文件
# 日志
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
logfile "" # 文件名
database 16 # 数据库数量,默认16个数据库
always-show-logo yes # 是否显示 logo
3.5、快照
持久化,在规定时间内执行了多少次操作会持久化到文件 .rdb .aof
Redis 在内存中存储,需要持久化
# 900 秒内,至少有一个 key 进行了修改,就进行持久化操作
save 900 1
# 300 秒内,至少10 个 key 进行修改,进行持久化操作
save 300 10
# 60 秒内,至少 10000 个 key 进行修改,进行持久阿虎操作。
save 60 10000
stop-writes-on-bgsave-error yes # 默认持久化操作出错继续进行工作
rdbcompression yes # 是否压缩 rdb 文件
rdbchecksumyes # 保存文件进行校验
dir ./ # rdb 文件保存目录
3.6、REPLICATION 复制
3.7、SECURITY 安全
可以设置 Redis 密码,默认没密码
requirepass root
127.0.0.1:6379> config set requirepass "root" # 设置 Redis 密码
OK
127.0.0.1:6379> config get requirepass # 获取 Redis 密码
1) "requirepass"
2) "root"
3.8、CLIENTS 客户端
maxclients 10000 # 设置 Redis 最大客户端连接数
maxmemory <bytes> # Redis 配置最大内存容量
maxmemory-policy noeviction # 内存达到上限的拒绝策略
# volatile-lru 删除 lru 算法的 key
# allkeys-lru 删除 lru 算法的 key
# volatile-random 随机删除即将过期的 key
# volatile-ttl 删除即将过期的
# noeviction 永不过期,返回错误
3.9、APPEND ONLY 模式 AOF
appendonly no # 默认不开启 AOF,默认使用 RDB 持久化,大部分情况下,RDB足够使用。
appendfilename "appendonly.aof" # 持久化文件的名字
appendsync always # 每次修改都会 sync
appendsync everysec # 每秒执行一次,可能会丢失 1 秒数据
appendsync no # 不执行 sync
4、Redis 持久化
Redis 持久化方式
4.1 RDB (Redis Database)
RDB 保存的文件是 dump.rdb,都是在配置文件中快照中进行配置的。
dbfilename dump.rdb
save 60 5
save 规则满足,触发 rdb 规则
执行 flushall 命令,也会触发 rdb 规则
退出 redis,也会产生 rdb 规则
恢复 rdb 文件
将 rdb 文件放到 redis 启动目录,启动会自动检查 dump.rdb 文件,恢复其中的数据
优点:
大量数据恢复
对数据完整性不高
缺点
需要时间间隔进行操作
fork 进程时,会占用一定内存空间。
4.2 AOF
以日志的形式记录每个写操作,redis 重启的话根据日志文件的内容将写指令从前到后执行一次完成数据恢复
AOF 保存 appendonly.aof 文件
appendonly yes
默认不开启,手动开启
重启 redis 就可以生效,如果 aof 文件有错误,redis 无法启动,需要修复 aof 文件
redis 提供的工具:redis-ckeck-aof --fix
如果文件正常,可以直接恢复
重写规则:
aof 默认是文件的无限追加,文件越来越大
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb如果 aof 文件大于 64mb,fork 一个新的进程将文件进行重写
优点:
每次修改都同步,文件完整性更好
缺点:
相对于数据文件来说,aof 远大于 rdb 文件,修复速度比较慢
aof 运行效率比 rdb 慢。
- RDB 持久化方式能够在指定时间间隔对数据进行快照存储
- AOF 持久化方式记录每次对服务器写的操作,服务器重启时执行命令恢复原始数据,AOF 命令以 Redis 协议追加保存每次写的操作到文件末尾,Redis 可以对到达文件大小的 AOF 文件进行重写,使 AOF 文件不会过大
- 如果数据只在服务器运行的时候存在,可以不使用持久化
- 同时开启两种持久化方式,Redis 优先载入 AOF 文件恢复原始数据,AOF 文件保存数据比 RDB 数据完整。RDB 文件不实时,同时使用也会找 AOF 文件,RDB 适合备份数据库,快速重启,而且不会有 AOF 可能存在的 Bug。
5、Redis 发布订阅
Redis 发布订阅(pub/sub)是一种消息通信模式,发送者 pub 发送消息,订阅者 sub 接收消息,Redis 客户端可以订阅任意数据量的频道
- 消息发布者
- 频道
- 消息订阅者
原理
Redis 使用 C 实现,pubsub.c 文件,发布和订阅的底层实现
Redis 通过 publish、subscribe、psunscribe 命令实现发布和订阅功能
通过 subscribe 命令订阅频道后,redis-server 中维护了一个字典,字典的键对应一个个的 channel,字典的值为链表,保存所有订阅了频道的客户端,subscribe 命令就是将客户端添加到 channel 的订阅链表中,通过 publish 命令向订阅者发送消息,redis-server 使用指定频道作为键,在维护的 channel 字典中查找记录了订阅这个频道的所有客户端的链表,遍历链表将消息发送给订阅者。
publish 和 subscribe 在 redis 中可以设定对某个 key 值进行消息发布和订阅,当一个 key 值进行了消息发布,所有订阅的客户端都会受到相应的消息。可以作为聊天功能。
发送端
127.0.0.1:6379> PUBLISH channel1 "hello,redis" # 发布消息到指定频道 channel1
(integer) 1
127.0.0.1:6379> PUBLISH channel1 "hello,world"
(integer) 1
订阅端
127.0.0.1:6379> SUBSCRIBE channel1 # 订阅频道 channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message" # 收到订阅频道消息
2) "channel1"
3) "hello,redis"
1) "message"
2) "channel1"
3) "hello,world"
5、Redis 主从复制
主从复制指将一台 Redis 服务器(master/leader)的数据,复制到其他 Redis 服务器(slave/follower),数据复制时单向的,只能由主节点到从节点。master 以写为主,slave 以读为主。
5.1 主从复制的作用
- 数据冗余:数据备份,持久化之外的一种数据冗余方式
- 故障恢复:主节点出现问题,可以由从节点提供服务,实现故障恢复,服务冗余。
- 负载均衡:主从复制的基础上配合读写分离,可以主节点提供写服务,从节点提供读服务,读写连接不同节点,分担服务器负载,在写少读多的情况下,通过多个从节点分担负载,提高并发量
- 主从复制是哨兵和集群能实施的基石,是 redis 高可用的基础。
5.2 环境配置
只配置从库,不配置主库
查看主从信息
127.0.0.1:6379> info replication # 查看当前库信息
# Replication
role:master # 角色 master
connected_slaves:0 # 从机
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
复制 3 个配置文件,修改对应信息
- 端口号
- pid 名字
- log 文件名字
- dump.rdb 名字
修改完毕启动 3 个 redis 服务。默认情况下,每个 Redis 都是主节点
,一般情况只需要配置从机
在配置文件中进行配置
使用命令行配置,重启后自动变成主机,只要变成从机,立马中主机中获取值。
# 暂时性配置
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379 # 配置主机信息
OK
主机写,从机读。主机中所有的信息和数据,都会被从机自动保存
5.3 复制原理
slave 启动成功连接到 master 之后,会发送一个 sync 同步命令
master 接收到指令后,启动后台存盘进程,收集所有用于修改数据的命令,后台进程执行完后,master 将整个数据文件传到 slave 完成一次同步。
全量复制:slave 服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:master继续将所有收集到的修改命令依次传递给slave,完成同步。
重新连接 master,自动执行一次增量复制完全同步。
5.4 宕机后手动配置主机
主机断开连接,使用 SLAVEOF no one
使从机变为主机,原来的主机重新连接后需要重新配置
6、哨兵模式 sentinel
主从切换由人工变为自动切换,监控到主机故障后,根据投票数自动将从库换为主库。
Redis 提供了哨兵的命令,哨兵是一个单独的进程,独立运行,哨兵通过发送命令,等待 Redis 服务器的响应,监控运行的多个 Redis 实例
主服务宕机,系统不会马上进行 fallover 过程,哨兵1 认为 主服务器不可用,称为主观下线
多个哨兵检测主服务器不可用,进行投票后,进行 fallover 操作,切换成功后,通过 pub/sub ,从服务器切换为主机,称为客观下线
6.1 配置哨兵配置文件
默认端口:26379
1.哨兵模式配置文件:sentinel.conf
sentinel monitor 监控的名称 host port num(下线票数的临界点)
2.启动哨兵
redis-sentinel konfig/哨兵配置文件
如果 master 节点断开,从从机中选择服务器作为主机 failover (故障转移)
主机重连后,归并到新的主机下,作为从机
优点
- 哨兵集群,基于主从复制模式,所有主从配置优点都有
- 主从可以切换,故障可以转移,系统可用性更好
- 哨兵模式是主从模式的升级,手动到自动,更加健壮。
缺点
- 集群到达上限,扩容麻烦
- 哨兵模式配置麻烦
7、Redis 缓存穿透和雪崩
缓存穿透(未查到)
用户查询一个数据,Redis 中未查询到数据,缓存未命中,于是向持久层数据库查询,也未查询到数据,查询失败。并发量大的时候,会给数据库造成很大压力,就造成了缓存穿透
布隆过滤器
一种数据结构,对可能查询的参数以 hash 形式存储,在控制层先进行校验,不符合丢弃,避免对底层存储系统的查询压力
缓存空对象,数据库未查询到后返回空对象也将其缓存起来,设置过期时间,之后访问数据从缓存中读取
可能会造成问题数据库与缓存不一致!
缓存击穿(量大)
一个 key 作为热点数据,高并发集中访问一个 key,key 在失效的瞬间,大量请求到数据库。
热点数据永不过期
加互斥锁
分布式锁,保证每个 key 同时只有一个线程查询后端服务,其它线程没有获取分布式锁的权限。
缓存雪崩
某一个时间段,大量缓存集中过期失效
Redis 集群,高可用
限流降级
数据预热,
以上是关于深入了解 RedisRedis 高级特性的主要内容,如果未能解决你的问题,请参考以下文章