一、Redis 简介
Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库,类似于 Java 中的 Map<key, value>。
Redis 与其他 key - value 缓存产品有以下特点:
(1)
Redis 数据库中所有数据都存储在内存中,由于内存的读写速度远快于硬盘,因此 Redis 在性能上对比其他基于硬盘存储的数据库有非常明显的优势
。
(2)Redis 支持数据的持久化,可以将内存中的数据异步写入到磁盘中,重启的时候可以再次加载进行使用
。
(3)Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。
(4)Redis支持数据的备份,即 master-slave 模式的数据备份
。
Redis 的特点:
(1)速度快
1)
纯内存操作
2)单线程操作,避免了频繁的上下文切换
3)采用了非阻塞 I/O 多路复用机制
(2)原子性
Redis 的所有操作都是原子性的
,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC 指令包起来
。(3)键值对的数据结构服务器
5种常用数据结构:String、hash、 list、 set、 zSet
(4)简单稳定
单线程,协议简单
(5)持久化
将内存数据写入磁盘
(6)主从复制
实现多个相同数据的 redis 副本
(7)高可用和分布式集群
哨兵机制实现高可用,保证 redis 节点故障发现和自动转移
(8)客户端语言多
java、php、python、c、c++、node.js等
使用 Redis 的缺点
(1)缓存和数据库双写一致性问题
(2)缓存雪崩问题
(3)缓存击穿问题
(4)缓存的并发竞争问题
Redis 应用场景
1、
缓存数据库
合理使用缓存加快数据访问速度,降低关系型数据库压力
2、
排行榜
按照热度排名,按照发布时间排行,
主要用到列表和有序集合
3、
计数器应用
视频网站播放数,网站浏览数
4、社交网络
赞、踩、粉丝、下拉刷新
5、
消息队列
发布和订阅
6、其他场景。。
二、redis 配置、启动、操作、关闭
停止 redis 服务:redis-cli shutdown
注意:
a、
关闭时,断开连接,持久化文件生成,相对安全
。
b、使用 kill 方式关闭进程时,不会做持久化,还会造成缓冲区非法关闭,会导致数据丢失
。
c、 关闭前持久化文件,登录 redis-cli 客户端,再 shutdown nosave|save 。
三、Redis 的数据结构
1、String
字符串类型:实际上可
以是字符串(包括 XML JSON),还有数字(整形 浮点数),二进制(图片 音频 视频),最大不能超过 512MB
。
示例
// 1、设值指令
set age 22 ex 10 // 10秒后过期, ttl age 查询剩余时间
setnx name test // 不存在键name时,返回1设置为成功,返回0失败
// 2、获取指令
get age // 存在返回age的值
// 3、删除指令
del age // 删除age,返回1
// 4、批量操作
mset name wanglei age 22 // 批量set
mget name age // 批量get
// 5、计数
incr age // 必须为证书自加1,非整数返回错误,无age键从0开始自增返回1
decr age // 整数age减1
incrby age 2 // 整数age + 2
decrby age 2 // 整数age - 2
incrbyfloat score 1.1 // 浮点型 score + 1.1
// 5、追加、长度、截取字符串
set name hello;
append name zhangsan; // 追加字符串,变成 hellozhangsan
set zhangsan "张三";
strlen zhangsan // 字符串长度,结果为6,每个中文占3个字节
set name helloworld;
getrange name 0 2 // 截取字符串,返回hel
补充
1)EX seconds : 将键的过期时间设置为 seconds 秒。 执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value 。
2)PX milliseconds : 将键的过期时间设置为 milliseconds 毫秒。 执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value 。
3)NX : 只在键不存在时, 才对键进行设置操作。 执行 SET key value NX 的效果等同于执行 SETNX key value 。
4)XX : 只在键已经存在时, 才对键进行设置操作。
2、Hash
Redis hash 是一个键值对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象
,类似 Java 里面的 Map<String,Object>,最大存储 512M。
示例:
hset user:1 name wanglei // 设置指令,成功返回1,失败返回0
hget user:1 name // 读取指令,返回wanglei
hlen user:1 // 计算field个数,返回2
hdel user:1 name // 删除field,返回删除个数
hmset user:2 name wanglei age 23 sex boy // 批量设置,返回OK
hmget user:2 name age sex // 批量读取,返回三行:wanglei 23 boy
// 判断field是否存在:
hexists user:2 name // 若存在返回1,不存在返回0
// 获取所有field:
hkeys user:2 // 返回name age sex三个field
// 获取user:2所有value:
hvals user:2 // wanglei 23 boy
// 获取user:2所有field与value:
hgetall user:2
// 整型增加1:
hincrby user:2 age 1 // age+1
// 浮点型增加2:
hincrbyfloat user:2 age 2 // 浮点型加2
三种方式存储user信息比较
1)原生
set user:1:name wanglei;
set user:1:age 22;
set user:1:sex boy;
优点:简单直观,每个键对应一个值。
缺点:键数过多,占用内存多,用户信息过于分散,不用于生产环境。
2)将对象序列化存入 redis。
set user:1 serialize(userInfo);
优点:编程简单,若使用序列化合理内存使用率高。
缺点:序列化与反序列化有一定开销,更新属性时需要把 userInfo 全取出来进行反序列化,更新后再序列化到 redis。
3)使用 hash 类型。
hmset user:1 name wanglei age 23 sex boy
优点:简单直观,使用合理可减少内存空间消耗。
缺点:要控制 ziplist 与 hashtable 两种编码转换,且 hashtable 会消耗更多内存 serialize(userInfo)。
3、List
用来
存储多个有序的字符串
,一个列表可以存的最大元素:2的23次方减1 。
因为有序,可以通过索引下标获取元素或某个范围内的元素列表,列表元素可以重复
。
特点
单键多值
,底层实际是个双向链表
,对两端的操作性能很高,通过索引下标操作中间的节点性能会较差
。
示例
rpush testlist c b a // 从右向左插入c b a, 返回3
lrange testlist 0 -1 // 从左往右获取列表元素,返回c b a,0 -1为索引下标
lpush testlist 1 2 3 // 从左向右插入1 2 3, 返回6
linsert testlist before 1 0 // 在1之前插入0,返回7,after为之后,使用lrange testlist 0 -1 查看,返回结果为3 2 0 1 c b a
lindex testlist -1 // 返回最右末尾a,-2返回b
llen testlist // 当前列表长度,返回7
lpop testlist // 把最左边的第一个元素删除,返回3
rpop testlist // 把最右边的第一个元素删除,返回a
4、 Set
用户标签,社交,查询有共同兴趣爱好的人,智能推荐。
保存多元素,与列表不一样的是
不允许有重复元素,且集合是无序
,一个集合最多可存2的32次方减1个元素,除了支持增删改查,还支持集合交集、并集、差集。
底层其实是一个 value 为 null 的哈希表
。
示例
exists user // 检查user键值是否存在,存在返回1,不存在返回0
sadd user a b c // 向user插入3个元素,返回3
sadd user a b // 若再加入相同的元素,则重复无效,返回0
smembers user // 获取user的所有元素,返回结果无序
srem user a // 返回1,删除a元素
scard user // 返回2,计算元素个数
// 场景,求共同爱好语言
// 使用方式,给用户添加标签,或者给标签添加用户。
// 给用户添加标签
sadd user:1:fav java js vue python
sadd user:2:fav vue python node.js
sadd user:3:fav c c++ c#
// 求共同爱好,即求交集
sinter user:1:fav user:2:fav // 返回vue、python
sinter user:1:fav user:2:fav user:3:fav // 返回(empty list or set)
5、zSet
Redis
有序集合 zset
与普通集合 set 非常相似,是一个没有重复元素的字符串集合
。不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复的
。
zset 底层使用了两个数据结构:1)hash:hash 的作用就是关联元素 value 和权重 score,保障元素 value 的唯一性,可以通过元素 value 找到相应的 score 值。
2)跳跃表:跳跃表的目的在于给元素 value 排序,根据 score 的范围获取元素列表。
常用于排行榜,如视频网站需要对用户上传视频做排行榜,或点赞数与集合有联系,不能有重复的成员。
示例
zadd user:zan 200 wanglei 120 zhangsan 140 lisi // 增加元素,返回3
zrange user:zan 0 -1 withscores // 查询元素,返回点赞数和成员名称,返回张三 120 lisi 140 wanglei 200
zrank user:zan lisi // 返回名次,返回1,排名为0,1,2
zrevrank user:zan wanglei // 反向排名,点赞越多排名越前,返回0
zadd test:1 nx 100 wanglei // 键test:1必须不存在,主要用于添加
zadd test:1 xx incr 200 wanglei // 键test:1必须存在,主要用于修改,此时300
zadd test:1 xx ch incr -299 wanglei // 返回操作结果1,300-29=1
zcard test:1 // 计算成员个数,返回1
list、set、zSet 比较
Redis6 的新数据类型
(1)Bitmaps
Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:
(1)Bitmaps 本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它
可以对字符串的位进行操作
。(2)Bitmaps 单独提供了一套命令, 所以在 Redis 中使用 Bitmaps 和使用字符串的方法不太相同。 可以把 Bitmaps 想象成一个以位为单位的数组, 数组的每个单元只能存储 0 和 1, 数组的下标在 Bitmaps 中叫做偏移量。
(2)HyperLogLog
Redis HyperLogLog 是用来做
基数统计
的算法。
HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数,这与元素越多耗费内存就越多的集合形成鲜明对比。
(3)Geospatial
redis 基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度 Hash 等常见操作。
四、redis 数据库管理
默认支持16个数据库
;可以理解为一个命名空间。跟关系型数据库不一样的点:
redis
不支持自定义数据库名词
。
每个数据库不能单独设置授权。
每个数据库之间并不是完全隔离的
。 可以通过 flushall 命令清空 redis 实例面的所有数据库中的数据。
通过 select dbid 去选择不同的数据库命名空间,dbid 的取值范围默认是 0 -15
。
全局命令
(1)查看所有键: keys * (可以查询所有key,也可以模糊搜索,如 keys user* ,但是线上不推荐使用。)
(2)键总数:dbsize (如果存在大量键,线上不建议使用。)
(3)检查键是否存在:exists key (存在返回 1,不存在返回 0。)
(4) 设置键过期时间: expire username 20 (设置 username 20秒过期,ttl username 查看剩余时间。)
(5)查看数据类型:type username (返回string,不存在返回none。)
五、Redis 持久化机制
redis 是一个支持持久化的内存数据库,也就是说 redis 需要经常将内存中的数据同步到磁盘来保证持久化,持久化可以避免因进程退出而造成数据丢失。
1、RDB 持久化方式
RDB 持久化把当前进程数据生成快照(.rdb)文件保存到硬盘的过程
,有手动触发和自动触发。
手动触发有 save 和 bgsave 两命令 :
1) save命令:阻塞当前redis,直到RDB持久化过程完成为止,若内存实例比较大会造成长时间阻塞,线上环境不建议用它。
2)bgsave命令:redis 进程执行 fork 操作创建子进程,由子线程完成持久化,阻塞时间很短(微秒级)
,是 save 的优化,在执行 redis-cli shutdown 关闭 redis 服务时,如果没有开启 AOF 持久化,自动执行 bgsave。
RDB 如何恢复
redis.conf 文件配置了指定目录,重启 redis 恢复数据
。
RDB 持久化优缺点
优点:
压缩后的二进制文,适用于备份、全量复制,用于灾难恢复。
加载 RDB 恢复数据远快于 AOF 方式
。缺点:
无法做到实时持久化,每次都要创建子进程,频繁操作成本过高
。
保存后的二进制文件,存在老版本不兼容新版本 rdb 文件的问题。
2、AOF 持久化
针对 RDB 不适合实时持久化,redis 提供了 AOF 持久化方式来解决
。
开启:redis.conf 设置:appendonly yes (默认不开启,为no)
默认文件名:appendfilename “appendonly.aof”
AOF 持久化流程
1)
所有的写入命令(set hset)会 append 追加到 aof_buf 缓冲区中
。
2)AOF 缓冲区向硬盘做 sync 同步
。
3)随着 AOF 文件越来越大,需定期对 AOF 文件 rewrite 重写,达到压缩。
4)当 redis 服务重启,可 load 加载 AOF 文件进行恢复
。
AOP如何恢复
redis.conf 文件配置了指定目录,重启 redis 恢复数据。
AOP 配置详解
appendonly yes // 启用aof持久化方式
# appendfsync always // 每收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
appendfsync everysec // 每秒强制写入磁盘一次,性能和持久化方面做了折中,推荐
no-appendfsync-on-rewrite yes // 正在导出rdb快照的过程中,要不要停止同步aof
auto-aof-rewrite-percentage 100 // aof文件大小比起上次重写时的大小,增长率100%时,重写
auto-aof-rewrite-min-size 64mb // aof文件,至少超过64M时,重写
Redis 重启时加载 AOF 和 RDB 的顺序
(1)
当 AOF 和 RDB 文件同时存在时,优先加载 AOF
。
(2)若关闭了 AOF,加载 RDB 文件。
(3)加载 AOF/RDB 成功,redis 重启成功。
(4)AOF/RDB 存在错误,启动失败打印错误信息。