Redis (REmote DIctionary Server) 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库
数据间没有必然的关联关系
内部采用单线程机制进行工作
高性能,官方提供测试数据,50个并发执行100000 个请求,读的速度是110000 次/s,写的速度是 81000次/s。
多数据类型支持 字符串类型 string 列表类型 list 散列类型 hash 集合类型 set 有序集合类型 sorted_set
持久化支持。可以进行数据灾难恢复
信息添加
//set name xinxin(name-->key xinxin-->value) set key value
信息查询
//get name (获取name-->key中的value值) 若不存在,返回空(nil) get key
清除屏幕信息
clear
退出客户端命令行模式
quit exit按钮
帮助
// help set 获取set命令帮助文档 // help @string 获取string组中所有命令信息名称 help 命令名称 help @组名
redis 数据存储格式
redis 自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储
数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串
key的语法:
在一个项目中,key最好使用统一的命名模式
key区分大小写 key不要太长,尽量不要超过1024字节。
不仅消耗内存,也会降低查找的效率
key不要太短,太短可读性会降低
value值类型可以是以下五种string 、 hash、 list 、 set 、sorted_set
存储的数据:单个数据
存储数据的格式:一个存储空间保存一个数据
存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用
// 添加/修改数据(set name xinxin (若该key已有,则视为修改)) set key value //获取数据(get name) get key //删除数据(del name) del key //添加/修改多个数据 mset key1 value1 key2 value2 …(m代表Multiple) //获取多个数据 mget key1 key2 … //获取数据字符个数(字符串长度)(strlen name) strlen key //追加信息到原始信息后部(如果原始信息存在就追加,否则新建) append key value //按照范围获取(GETRANGE name 0 3 --->name(key)的value值根据下标从0-3输出) GETRANGE key 开始下标 结束下标 //替换(SETRANGE name 3 多多 -->将name(key)的value值中下标为3的改为多多) SETRANGE key 位置 value //先get然后在set(getset name 大雄 -->获取name的值并修改为大熊) getset key value /*案例一 多张表存储同类型数据,但对应的主键id必须保持统一(redis中key来实现), */ //设置数值数据增加指定范围的值 //incr age(执行增1) incrby age increment 2(执行增2) incrbyfloat age 3.2(执行增3.2) incr key incrby key increment incrbyfloat key increment //设置数值数据减少指定范围的值 //decr age(执行减1) decrby age increment 2(执行减2) decr key decrby key increment /*案例二 控制时效性 (redis支持设置过期--->例如:验证码) redis 控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作 */ //设置数据具有指定的生命周期(过期的key也会没有了) //setex name 3 xinxin (name(键)的value值xinxin 3秒后过期) setex key seconds(秒) value psetex key milliseconds(毫秒) value //设置key的过期时间(EXPIRE name 3 --->对key中已有value值进行设置过期时间) EXPIRE key seconds //查看key的剩余时间 /*案例三 Tips 3:redis应用于各种结构型和非结构型高热度数据访问加速 key 的设置约定===数据库中的热点数据key命名惯例 表名:主键名:主键值:字段名 */ 主页高频访问信息显示控制,例如新浪微博大V主页显示粉丝数与微博数量 关注数focuss 粉丝数fans 微博数blogs 解决方案 //在redis中为大V用户设定用户信息,以用户主键和属性值作为key,后台设定定时刷新策略即可 eg: user:id:3506728370:fans → 12210947 eg: user:id:3506728370:blogs → 6164 eg: user:id:3506728370:focuss → 83 //在redis中以json格式存储大V用户信息,定时刷新(也可以使用hash类型) eg: user:id:3506728370 → {"id":3506728370,"name":"春晚","fans":12210862,"blogs":6164, "focus":83} eg: order:id:9527:name : 馨馨 //注意事项 数据操作不成功的反馈与数据正常操作之间的差异 ① 表示运行结果是否成功 (integer) 0 → false 失败 (integer) 1 → true 成功 ② 表示运行结果值 (integer) 3 → 3 3个 (integer) 1 → 1 1个 数据未获取到 (nil)等同于null 数据最大存储量 512MB 数值计算最大范围(java中的long的最大值) 9223372036854775807
对象类数据的存储如果具有较频繁的更新需求操作会显得笨重
hash哈希特点
新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
需要的存储结构:一个存储空间保存多个键值对数据
hash类型:底层使用哈希表结构实现数据存储
hash存储结构优化
如果field数量较少,存储结构优化为类数组结构
如果field数量较多,存储结构使用HashMap结构
//添加/修改数据 hset key field value /*添加,但是有则不添加,无则添加(只做新增、不做修改,有的话则保存失败,不会做覆盖修改) 没有 */ hsetnx key field value //获取数据 hget key field hgetall key //删除数据 hdel key field1 [field2] //添加/修改多个数据 hmset key field1 value1 field2 value2 … //获取多个数据 hmget key field1 field2 … ///获取哈希表中字段的数量(键值对的个数) hlen key //获取哈希表中是否存在指定的字段 hexists key field //获取哈希表中所有的字段名或字段值 hkeys key hvals key //设置指定字段的数值数据增加指定范围的值 hincrby key field increment hincrbyfloat key field increment /* 案例2:购物车(种类、个数编辑) */ 解决方案 以客户id作为key,每位客户创建一个hash存储结构存储对应的购物车信息 将商品编号作为field,购买数量作为value进行存储 添加商品:追加全新的field与value 浏览:遍历hash 更改数量:自增/自减,设置value值 删除商品:删除field 清空:删除key
存对象(key--->对象名,value--->值)
既灵活也方便查询
数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
list类型:保存多个数据,底层使用双向链表存储结构实现
使用场景:如朋友圈点赞等
//添加/修改数据 lpush key value1 [value2] …… //左侧存 rpush key value1 [value2] … //右侧存 //获取数据 lrange key start stop / lindex key index //键指定下标的元素内容 llen key //获取并移除数据 lpop key //左侧删第一个 rpop key //右侧删第一个 //通过下标截取指定的长度,这个list已经被改变了,只剩下截取的元素 ltrim key start end //lset将列表中指定下标的值替换为另外一个值,更新操作 lset key 下标 新数据 # 如果不存在列表我们去更新就会报错 //将某个具体的value插入到列中的某个元素的前面或者后面! LINSERT mylist before "world" "other" //给world前插入other LINSERT mylist after "world" "other" //规定时间内获取并移除数据 b代表block阻塞 //bloop mylist 30 左侧删第一个,如果没有则阻塞30s(看30s内是否有可供删除的),如果有直接删除 blpop key1 [key2] timeout brpop key1 [key2] timeout eg:lpush list1 a b lpop list1 ===a lpop list1 ===b lpop list1 ===nil 立刻响应为空,但如果是blpop会阻塞,也就是会等,现在没数据不意味着未来没有 blpop list1 30 获取数据,有则返回,没有则等待30秒
无序且唯一
新的存储需求:存储大量的数据,在查询方面提供更高的效率
需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
set 类型数据操作的注意事项 1.set 类型无序且不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份 2.set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
//添加数据 sadd key member1 [member2] //获取全部数据 smembers key //删除数据 srem key member1 [member2] //获取集合数据总量 scard key //判断集合中是否包含指定数据 sismember key member /* 案例1 热品推荐、微博类别勾选 */ 解决方案 //随机获取键中给定个数的数据 srandmember key [count] //随机删除键中给定个数的数据 spop key [count] Tips 1: redis 应用于随机推荐类信息检索,例如热点歌单推荐,热点新闻推荐,热卖旅游线路,应用APP推荐, 大V推荐等 /* 案例2 脏数据的清理 */ 解决方案 //求两个集合的交、并、差集 sinter key1 [key2] sunion key1 [key2] sdiff key1 [key2] //主导集合key1 - key2 //求两个集合的交、并、差集并存储到指定集合(新集合名destination)中 sinterstore destination key1 [key2] sunionstore destination key1 [key2] sdiffstore destination key1 [key2] //将指定数据从原始集合中剪贴到目标集合中 smove source destination member
有序且唯一
新的存储需求:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
需要的存储结构:新的存储模型,可以保存可排序的数据
sorted_set类型:在set的存储结构基础上添加可排序字段
//添加数据 // zadd key score1 member1 [score2 member2] //获取全部数据 //[WITHSCORES]可以除了数据还显示分值 zrange key start(开始索引) stop(结束索引) [WITHSCORES] zrevrange key start stop [WITHSCORES] //删除数据 zrem key member [member ...] //获取集合数据总量 zcard key
Jedis 是通过java代码连接操作Redis 数据库工具
2.编写测试
RedisTemplate 专用对象 key value泛型都是object
StringRedisTemplate 专用字符串key value均是String
spring中数据访问层提供的技术,对原来一些原生技术进行二次封装,提供相关操作。对原生的jedis的早期封装。
步骤
导入启动器坐标
配置yml文件信息
装配两个模板类
RedisTemplate key value泛型都是object
StringRedisTemplate key value泛型都是string
注意:
1.两者数据各自存,各自取,数据不互通。
RedisTemplate不能取StringRedisTemplate存入的数据
StringRedisTemplate不能取RedisTemplate存入的数据
2.序列化策略不同:
RedisTemplate采用JDK的序列化策略(JdkSerializationRedisSerializer)保存的key 和value 都是采用此策略序列化保存的存储时,先将数据序列化为字节数组,再存入Redis数据库。查看Redis会发现,是字节数组的形式类似乱码读取时,会将数据当做字节数组转化为我们需要的数据,以用来存储对象,但是要实现 Serializable接口
StringRedisTemplate采用String的序列化策略(StringRedisSerializer)保存的key和 value都 是采用此策略序列化保存的当存入对象时,会报错:can not cast into String 存储和读取,都为可读的数据
3.两者的关系是StringRedisTemplate继承RedisTemplate
4.使用场景: 当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那 么你就使 用StringRedisTemplate即可。
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取 出一个对 象,那么使用RedisTemplate是更好的选择。
五大数据类型
redisTemplate.opsForValue();//操作字符串
redisTemplate.opsForList();//操作List
redisTemplate.opsForSet();//操作Set
redisTemplate.opsForZSet();//操作ZSet
redisTemplate.opsForHash();//操作Hash
自定义配置类
redis作缓存 查询 ---> 先查redis(有则返回,无则查数据库再存入redis中) 新增 ---> 新增数据库(不必要写入redis中,不一定查) 修改 ---> 修改数据库以及redis中的数据 删除 ---> 删除数据库以及redis中的数据
步骤
导入radis启动器坐标
配置yml文件(redis连接ip端口)
spring: datasource: username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/xinxin?serverTimezone=GMT redis: host: localhost port: 6379 mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3. 编写Redisconfig类(实现序列化反序列化功能)
4. 编写redis工具类并注入容器(注入Redisconfig类),未来对redis做操作,直接调用工具类方法(在该类中,方法已被设计好,并进行二次分装)
5. 编写mapper接口方法并注入(@Mapper),编写service类 逻辑代码并注入(@Service)
6. 编写controller类(@RestController注解只返回Json结果,不关注视图页面,注入业务类对象
6.1查询
6.2删除
6.3修改
6.4 新增
redis.windows.conf文件
端口、密码、日志级别、持久化、集群等等
持久化:Redis支持持久化的非关系型数据库,可以将数据系统化存在物理磁盘,可以数据快速恢复,不怕redis服务宕机等问题。
RDB 持久化是通过创建 Redis 数据库在某一时刻的快照(snapshot)来实现的。在指定的时间间隔内,Redis 会将内存中的数据集快照写入到磁盘中,以此来实现数据的持久化。
将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据 (RDB 数据快照)
性能高:RDB 持久化是在 Redis 主线程之外进行的,不会对 Redis 的性能产生太大影响。
文件体积小:通过压缩和二进制的方式存储数据,文件体积相对较小,便于备份和传输。
数据安全性较低:在两次快照之间发生故障,会导致这期间的数据丢失。
启动时间长:在 Redis 重启时,需要加载 RDB 文件到内存中,如果 RDB 文件较大,则启动时间较长。
在 Redis 配置文件(通常是 redis.conf
)中,可以通过以下参数来配置 RDB 持久化:
# 设置自动生成 RDB 快照的条件 save 900 1 # 900 秒内至少有一个 key 被改变,则进行快照 save 300 10 # 300 秒内至少有 10 个 key 被改变,则进行快照 save 60 10000 # 60 秒内至少有 10000 个 key 被改变,则进行快照 # RDB 文件名 dbfilename dump.rdb # RDB 文件保存目录 dir ./
AOF 持久化是通过记录每次写命令到文件来实现的。当 Redis 执行写命令时,该命令会被追加到 AOF 文件的末尾。Redis 重启时,会重新执行 AOF 文件中的命令来恢复数据。
将数据的操作过程进行保存,日志形式,存储操作过程,关注点在数据的操作过程(AOF)
数据安全性高:即使服务器故障,也不会丢失太多数据(取决于 AOF 文件的写入策略)。
可读性强:AOF 文件以纯文本形式存储,易于理解和阅读。
文件体积大:相对于 RDB 文件,AOF 文件体积可能较大。
恢复速度慢:在 Redis 重启时,需要重放 AOF 文件中的所有命令,这可能需要较长时间。
在 Redis 配置文件(redis.conf
)中,可以通过以下参数来配置 AOF 持久化:
# 开启 AOF appendonly yes # AOF 文件名 appendfilename "appendonly.aof" # AOF 写入策略 # no:表示不执行 fsync,由操作系统保证数据同步到磁盘,速度最快,安全性最低 # always:表示每次写入命令都执行 fsync,速度最慢,但最安全 # everysec:表示每秒执行一次 fsync,性能和安全性的折中方案 appendfsync everysec # AOF 重写机制 # AOF 文件会随着时间变得越来越大,Redis 提供了 AOF 重写机制来压缩文件 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
Redis 提供了 RDB 和 AOF 两种持久化机制,每种机制都有其优缺点和适用场景。在实际应用中,可以根据需要选择其中一种或同时使用两种机制来确保数据的持久化和安全。同时,也可以通过合理配置相关参数来优化持久化过程的性能和安全性。
RDB持久化记录的是数据内容,恢复直接把快照读取到内存中 AOF持久化记录的是数据的指令,恢复时指令需重新运行
RDB全量复制 AOF每次/每秒操作一次
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
XX :具有时效性的数据 -1 :永久有效的数据 -2 :已经过期的数据或被删除的数据或未定义的数 问:过期的数据真的删除了吗? 答:不是的
创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
优点:节约内存,到时就删除,快速释放掉不必要的内存占用 缺点:占用内存开销,CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
总结:用处理器性能换取存储空间(拿时间换空间)
数据到达过期时间,不做处理。等再次访问时候,才会删除。等下次访问该数据时如果未过期,返回数据发现已过期,删除,返回不存在
优点:节约CPU性能,发现必须删除的时候才删除
缺点:占用内存空间,内存压力很大,出现长期占用内存的数据
总结:用存储空间换取处理器性能(拿空间换时间)
周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度 ,可人为控制。
优点1:CPU性能占用设置有峰值,检测频度可自定义设置
优点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
总结:周期性抽查存储空间 (随机抽查,重点抽查)
删除策略对比
定时删除 节约内存,无占用 不分时段占用CPU资源,频度高 拿时间换空间
惰性删除 内存占用严重 延时执行,CPU利用率高 拿空间换时间
定期删除 内存定期随机清理 每秒花费固定的CPU资源维护内存 随机抽查,重点抽查
Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。l来判断所存新数据在内存空间内能不能存储。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储 空间。清理数据的策略称为逐出算法(删除旧数据给新数据腾空间)。
占用物理内存的比例,默认值为0,表示不限制,生产环境中根据需求设定,通常设置在50%以上。
选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能。因此采用随机获取数据的方式 作为待检测删除数据
检测易失数据(可能会过期的数据集server.db[i].expires )
① volatile-lru:挑选最近最少使用的数据淘汰
② volatile-lfu:挑选最近使用次数最少的数据淘汰 `
④ volatile-random:任意选择数据淘汰
检测全库数据(所有数据集server.db[i].dict )
⑤ allkeys-lru:挑选最近最少使用的数据淘汰
⑥ allkeys-lfu:挑选最近使用次数最少的数据淘汰
⑦ allkeys-random:任意选择数据淘汰 放弃数据驱逐
⑧ no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发错误OOM(Out Of Memory)达到最大内存后的,对被挑选出来的数据进行删除的策略
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,导致数据库崩溃。带来巨大压力。
解决方案:
给不同的Key的TTL添加随机值 (需有效期不一致)
利用Redis集群提高服务的可用性
给缓存业务添加降级限流策略
给业务添加多级缓存
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
解决方案:
互斥锁 (数据安全、性能差)
逻辑过期
互斥锁与逻辑过期对比
互斥锁
优点:无额外内存消耗,保证一致性、实现简单
弊端:线程需要等待,性能受影响
逻辑过期
优点:线程无需等待、
缺点:不保证一致性、有额外内存消耗、实现复杂
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这 些请求都会打到数据库。
解决方案:
缓存空对象
优点:实现简单,维护方便
缺点: 额外的内存消耗 可能造成短期的不一致
布隆过滤
优点:内存占用较少,没有多余key
缺点: 实现复杂 存在误判可能