Redis及其他缓存
1.NOSQL、Redis概述,通用命令,redis五大数据类型,三大特殊数据类型
NOSQL概述:
(NOT ONLY SQL-不仅仅是SQL),泛指非关系型数据库,为解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用问题
常见nosql:redis,hbase。
和关系型数据的对比区别:数据之间没有关联关系,数据存储在内存中,操作数据相对较快。关系型数据库数据之间存在关联关系,数据存储在磁盘中,操作数据非常耗时。
优点:成本低、查询速度快、支持多种数据格式(基本数据类型、集合、对象、图片、文档等格式)、扩展性相对关系型数据库较好。
非关系型数据库优势:复杂查询较方便,事务的支持导致安全性很高。
总结:关系型数据库和非关系型数据库并非对立而是互补的关系,从而弥补对方的劣势。一般将数据存储在关系型数据库中,非关系型数据库中备份关系型数据库的数据(热点数据、高频访问且不常修改的数据)。
主流的nosql:
key-value存储数据库:redis。典型用于内容缓存,处理大量数据的高访问负载
列存储数据库:Hbase。典型用于分布式的文件系统
文档型数据库:Mongdb。典型用于web应用
图形数据库:Neo4J。典型用于社交网络
Redis概述:
C语言开发的高性能键值对数据库,在内存中就是一个Map集合。支持多种键值数据类型。key为字符串,value可是任意类型。
value类型分类:
字符串类型-String:Map<String,String>
散列类型-hash:Map<String,Map<String,String>>
列表类型-list:Map<String,List<String>> 数据可重复
集合类型-set:Map<String,Set<String>> 数据不可重复
有序集合类型-sortedset:Map<String,sortedset<String>> 数据不可重复,支持排序
应用场景:缓存、聊天室好友在线列表、任务队列(秒杀、抢购、12306抢票)、应用排行榜、网站访问统计、数据过期处理、分布式集群架构中session分离
相关指令
数据库操作指令:
启动redis,默认16个库(编号从0至15),select 编号 选择指定库
清空当前库:FLUSHDB
清空全部库:FLUSHALL
客户端显示中文:./redis-cli -p 700 --raw
操作key相关指令:
DEL KEY[KEY...] 删除单个或多个Key,返回删除数量,不存在的key忽略
EXISTS KEY;判断key是否存在,存在返回1,否则返回0
EXPIRE KEY seconds;为key设置生存时间,秒为单位,生存时间为0自动删除。成功返回1
KEYS PATTERN;查找符合pattern的key
MOVE KEY DB;将Key移动到指定db中
PEXPIRE KEY milliseconds;为key设置生存时间,毫秒为单位。成功返回1,否则返回0
PEXPIREAT KEY milliseconds-timestap;为Key设置生存时间,以毫秒为单位设置过期的时间戳
TTL KEY ;以秒为单位,返回指定key的剩余存活时间
PTTL KEY ;以毫秒为单位,返回指定key的剩余存活时间
RANDOMKEY;随机返回一个key
RENAME KEY NEWKEY;将Key命名修改为newkey
TYPE KEY ;返回KEY对应VALUE的类型。none(key不存在),string,list(列表),set(集合),zset(有序集合),hash(哈希表)
5种数据类型
String:基础存储类型,在redis中二进制安全,存入和取出数据相同,最大容纳数据长度512M。
常用命令:
set key value;例如:set company "sunny";key存在则进行覆盖,返回 OK
get key;返回key对应的值
del key;删除 key
哈希类型-hash:适合存储值对象信息,value是一个键值对,key 无序
常用命令
hset key field value 为指定key设置field/value键值对。给同一个field设置,后者会覆盖前者
hmset key1 field/value key2 field/value 为多个key设定field/value
hget key field 返回指定Key中field的值
hmget key field1 field2 field3 返回指定Key中多个field的值
hdel key field [field … ] 删除1个或多个字段,返回被删除字段的个数
hgetall key 获取Key的所有数据
列表类型-list:有序可重复,类似双端队列的数据结构,可作为redis实现消息队列的数据结构
常用命令:
lpush key values[value1 value2…] 在指定key关联的list头部添加这些元素,如果key不存在,则新建元素。添加成功,返回元素个数
lpop key 返回key关联链表的头部元素
rpop key 从尾部弹出元素
lrange key start end 输出该key的所有数据。示例:lrange key 0 10;输出key对应list的索引0至索引10的数据,即前11个元素
列表类型-set(无序且不可重复)
常用命令:
sadd key values[value1、value2…] 向key对应set中添加数据
smembers key 显示key对应set中所有数据
srem key members[member1、member2…] 删除key对应set中指定数据
有序列表类型-zset(sortedSet,可排序,可保证不重复),value中的每个元素都会关联一个double类型的份数,redis中正式通过分数来为元素实现从小到大的排序
特点:可排序的set集合,相当于java中的treeSet
常用命令:
zadd key values[value1、value2…] 向key对应set添加元素
zrange key start end 通过索引区间返回指定范围内的元素,升序
zrevrange key start end 通过索引区间返回指定范围内的元素,降序
zrange key start end [withscores] 通过索引区间返回指定范围内的元素及其对应score数字,升序
zrevrange key start end [withscores] 通过索引区间返回指定范围内的元素及其对应score数字,降序
redis通用命令
key pattern ;pattern表示格式,作用是获取与pattern匹配的Key。* 表示任意1个或多个字符,?表示任意1个字符
exists key ;判断key是否存在,存在返回1 否则返回0
type key ;返回key对应的value数据类型。none、string、list、set、zset、hash
expire key time;设置key的存活时间
3种特殊数据类型
Hyperloglog 基数统计算法,类似于set数据类型,允许容错,使用此类型。不允许容错使用set即可
Bitmap 位存储,操作二进制位来记录。
Geospatial 地理位置
2.redis持久化机制、RDB持久化、AOF持久化
REDIS持久化概述:
redis高性能原因是因为将数据保存在内存中,为了保证redis重启后数据不丢失,将数据从内存保存到硬盘中,过程称为持久化。
持久化支持RDB和AOF两种方式,可以单独使用1种,也可以将2种进行结合使用。
默认支持RDB持久化,无序配置。此机制是在固定时间间隔将内存的数据集快照写入磁盘。
AOF持久化以日志的形式记录服务器所处理的写操作,在redis启动之初会读取此文件来重建redis数据库。以保证重启后数据完整。
持久化可通过配置来禁用
可同时使用RDB和AOF持久化
RDB持久化,也称快照(Snapshot)
RDB持久化特点:将内存种数据以一定时间间隔,将内存数据写入硬盘中,默认持久化的方式,保存的文件以.rdb为后缀
快照生成方式:客户端方式(BGSAVE和SAVE指令)、服务器配置自动触发
客户端方式之BGSAVE操作(并行操作):客户端使用BGSAVE命令创建快照,当redis服务器收到客户端发送的BGSAE命令,服务器会调用fork创建1个子线程,
子线程负责快照写入磁盘,主线程继续处理命令请求
客户端方式之SAVE操作(串行操作):客户端使用SAVE命令创建快照,redis服务器收到客户端发送的SAVE命令,服务器在快照完毕之前不会响应其他命令。此模式不常用
配置自动触发:和Mysql的redo机制类似。如果在redis.conf种设置了save配置选项,redis会在选项满足之后自动触发一次BGSAVE命令,如果设置多个save配置选项,
其中一个满足,也会执行一次BGSAVE命令
服务器接受客户端shutdown指令:服务器收到客户端的shutdown指令后,会执行一个save命令,阻塞所有客户端,不再执行任何客户端命令,并再save命令执行完毕后关闭服务器
配置生成快照名称和位置:
修改生成快照名称:dbfilename dump.rdb
修改生成位置 dir./
RDB(快照)持久化的缺点:
无法保证系统高可用性质,即无法避免最大程度的数据丢失。因为一旦在持久化之前出现服务宕机,未来得及保存进入磁盘的数据就会丢失
AOF只追加日志文件
特点:可将客户端执行的所有set命令记录到日志文件中,AOF持久化会将被执行的写命令保存到AOF文件的末尾,以此来记录数据变化;
恢复内存数据,只需要将AOF文件中包含的写命令从头到尾执行一次即可;
redis服务器启动之初会读取该文件,来重新构建redis数据库,从而保证数据完整
开启AOF持久化:
redis.conf默认配置中的AOF持久化机制是关闭的,需要配置中开启。
开启步骤:修改 appendonly yes 开启持久化;修改appendfilename "appendonly.aof"; 指定生成文件名称
日志追加频率:
always:每次写操作,都写入磁盘,可最大程度减少数据的丢失,但是此同步策略需要对磁盘大量操作,因此redis处理速度会受到磁盘性能的限制。谨慎使用
everysec:每秒执行一次同步,显式的将多个命令存入磁盘。使用此方式和不使用此方式时性能相差无几,同时每秒一次即便系统崩溃也只会丢失1S的数据。 推荐使用
no:由操作系统决定何时同步。不会对性能带来影响,但是会丢失不定量数据。不推荐
修改同步频率:通过 appendfsync always/everysec/no 指定
AOF文件的重写
AOF(日志文件)的缺点:持久化文件越来越大,为了压缩AOF持久化文件,redis提供了AOF重写(ReWriter)机制
AOF重写可在一定程度上减小AOF文件的体积
触发重写方式
客户端方式触发重写:执行 BGREWRITEAOF 命令,不会阻塞redis服务
服务端方式配置自动重写:修改redis.conf文件中的 auto-aof-rewrite-percentage和auto-aof-rewrite-min-size。
例如:auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb。在开启AOF持久化时,当AOF文件大于64M,并且AOF文件比上次重写后体积大了至少几倍,自动触发
重写原理:将内存中的数据库用命令的方式重写生成了一个AOF文件,来替换原来的文件
重写流程:
持久化总结
RDB和AOF两种方案可同时使用,也可单独使用,也可都不使用。使用那种取决于用户的数据和应用决定
无论是使用RDB还是AOF,持久化文件都是保存在磁盘的,有必要除了持久化外,还应该对持久化文件进行备份(最好备份在多个地方)
RDB和AOF的选择问题:
对数据非常敏感,选择AOF。但是文件体积较大,恢复速度较慢
数据呈现阶段有效性,选择rdb,可做到阶段内数据无丢失,恢复速度较快。但是利用RDB实现紧凑的持久化会使得redis性能降低很多
总之如果不能承受数分钟以内的数据丢失,对业务数据非常敏感选择AOF;可以承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选择RDB。
灾难恢复选用RDB
双重保险策略,同时开启AOF和RDB,重启后先使用AOF进行数据恢复,降低丢失数据,两者同时开启,数据恢复时会选择忽略RDB,选择AOF进行恢复,从而避免数据不一致或重复问题
3.java操作redis、jedis连接池、使用redis缓存不常修改的数据
jedis基本使用:
redis不仅可通过命令操作,主流语言都有客户端支持。官方推荐java客户端使用jedis和redisson。企业中jedis使用居多
实现步骤:引入jedis依赖;创建jedis对象;调用jedis对方的方法实现对string、list、set、zset、hash的操作
jedis连接池的基本概念:jedis资源的创建和消费非常消耗性能,jedis提供了池化技术,jedispool在创建时初始化一些连接资源存储到池中,使用jiedis连接资源时间无需创建,从连接池中获取,使用完毕后将jedis还给连接池,供其他请求使用。使用GenericObjectPoolConfig 和JedisPool来创建连接池
4.spring boot整合redis核心api
springboot data redis 提供了stringredistemplate和redistemplate,stringredistemplate是redistemplate的子类。
区别在于stringredistemplate的key和value只能是string,而redistemplate的key和value可以是object任意类型的数据。
使用redistemplate默认是将对象序列化到redis中,因此放入的对象必须实现对象序列化接口 serializable
实现步骤:引入依赖;配置连接;使用redistemplate进行操作
5.redis事务、watch锁、redis实现分布式锁、数据的删除策略、淘汰策略
redis事务
定义:一系列预定义命令保证成一个整体(队列),执行时一次性按照添加顺序依次执行,中途不会中断或干扰。
本质:一组命令的集合
没有隔离级别的概念,所有命令在事务中并未直接执行,只有在执行exec命令时才会执行
redis单条命令保证原子性,事务不保证原子性
执行步骤:开启事务(multi),执行操作,提交事务(exec)
事务操作
开启事务 multi (设定事务开启位置,后续所有指令均加入到事务中)
取消事务 discard 终止当前事务的定义,在multi之后,exec之前
执行事务 exec 设定事务的结束位置,同时执行事务,与multi成对出现。可保证事务的一致性
注意事项:定义事务中,命令存在语法错误,则事务中所有命令都不会执行;
如果命令格式语法正确,但是无法正确执行,则正确的命令会执行,运行错误的命令不会执行(例如对list执行incr),已经执行完毕的命令对应数据不会自动回滚,需要自行回滚。
watch锁:
问题:线程1监听某个key,当事务还未执行完,事务2操作了这个key,watch会通知线程1事务失败
基于特定条件的事务执行:假如对已售空的商城进行补货,多个采购员都可以进行,为了避免数据重复操作,所以在操作某一数据前,先锁定要操作的数据,一旦发生变化,终止当前事务
基于特定条件的事务执行(锁):对key添加监视锁,在执行exec操作前,如果Key发生了变化,则终止事务执行。watch key1[kye2...].取消所有key的监视 unwatch;
watch锁操作:
悲观锁:认为什么时候都会出问题,无论做什么都会加锁
乐观锁:认为什么时候都不会出现问题,所以不会加锁,更新数据时候判断一下,在此期间是否有人更改此数据(获取version,更新的时候比较version)
redis中数据的删除策略
定时删除、惰性删除、定期删除
淘汰策略
6.mybatis自身本地缓存结合redis实现分布式缓存
redis实现分布式缓存
缓存:计算机内存中的一段数据
内存中数据特点:读写快、断电立即丢失
缓存解决的问题:提高网站吞吐量,网络运行效率快,解决数据库访问压力
数据库中极少修改的数据适合使用缓存,更多用于数据查询
本地缓存和分布式缓存的区别:本地缓存保存在应用服务器内存中(mybatis的一级和二级缓存就是本地缓存);分布式缓存存储在应用服务器之外的数据
集群:将一种服务创建多个节点,放在一起共同对系统提供服务的过程称为集群
分布式:多个不同服务集群共同对系统提供服务的系统称为分布式系统。
利用mybatis自身本地缓存结合redis缓存实现分布式缓存:todo
7.主从复制简介、工作流程、常见问题
主从复制简介
redis集群实现高可用:避免单机redis服务故障,准备多台服务器,互相连通,将数据复制多个副本保存在多个服务器上,连接在一起,并保证数据式同步的。
即便其中1台服务宕机,其他服务器依然可以继续提供服务,实现redis的高可用,同时实现数据冗余备份。
主从复制定义:即将master中的数据及时、有效的复制到slave中.master支持读写,在进行写时间,将出现变化的数据自动同步至slave。
主从复制作用:
读写分离:master负责写,slave负责读取,提高服务器的读写负载能力
负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求变化,改变slave数量,通过多个从节点分担数据读取负载,大大提高了redis服务器并发量和吞吐量
故障恢复:master出现问题,slave提供服务,实现快速的故障恢复
数据冗余:实时数据热备份,持久化之外的一种数据冗余方式,slava和master数据同步
高可用基石:基于主从机制,构建哨兵模式和集群,实现redis高可用方案
主从复制流程
建立连接:准备阶段,slave连接master。
连接的三种方式:
客户端发送命令:slaveof masterip masterport;
驱动服务器参数:redis-server -slaveof masterip masterport
服务器配置:slaveof masterip masterport
断开连接:slaveof no one;断开连接后之前接受数据不会删除,只是不在接收新的master数据
数据同步: master数据同步slave
命令传播:master后续执行写入操作,将数据同步slave
8.哨兵机制Sentinel、哨兵原理
哨兵机制sentinel
哨兵概念:是redis的高可用性解决方案,由1个或多个sentinel实例构成的sentinel系统可监视多个主服务器,以及这些主服务器下的所有子服务器。
当被监视的主服务器下线时,自动将下线主服务器中的某个从服务器升级为新的主服务器。简单来说哨兵就是带有自动故障转移功能的主从架构。
哨兵是一个分布式系统,用于对主从结构中的每台服务器进行监控,当master出现故障时,选择新的master,并将所有slave连接到新的master
哨兵作用
监控:不断检查master和slave是否正常运行,master存活检测,master和slave运行情况检测
通知:当被监控的服务器出现问题时,向其他(哨兵、客户端)发送通知
自动故障转移:如果master宕机,断开master和slave的连接,从slave中选取一个作为新的master,将其他slave和新的master建立连接,并告知客户端新的master地址
注意:哨兵也是一台服务器,只是不提供服务。通常哨兵配置数量为单数。(避免选举master同票)
启动哨兵机制
配置多个哨兵:将redis中的sentinel.conf拷贝2份,在sentinel.conf中修改端口,以及设置master的端口地址,最后通过 redis-sentinel sentinel-端口号.conf即可启动哨兵
哨兵机制原理
主从切换:哨兵在主从切换中经历了 监控、通知、故障转移 3个阶段。
监控阶段:启动哨兵服务之后,哨兵之间会互相监控,包括master及master下所有的slave节点信息。多个哨兵之间可相互通信,之间通过发布订阅来互相通知
通知阶段:哨兵之间相互通知,哨兵通知客户端
故障转移阶段:某个哨兵向master服务器发送指令,此时master没反应,也拿不到信息,哨兵意识到master宕机,将此消息告知另外2个哨兵,另外两哨兵也向master发送请求,也得不到响应,此时master确定下线,随后多个哨兵中会选出一个领头的哨兵将master清楚,并在slave中选出一个新的master,将slave切换为新的master
9.redis集群原理、缓存预热、缓存击穿、缓存穿透、缓存雪崩的解决方案
集群架构
集群架构概念
概念产生背景:业务发展过程中遇到的瓶颈。redis提供服务OPS可达到10万/S,当前业务ops已达到10万/s;内存单机容量为256G,当前业务需求内存容量为1T。使用集群可解决上述问题
集群:将同一个服务的多个节点放在一起,共同对系统提供服务的过程称为集群。换言之集群就是将若干台网络连接起来,并提供统一的管理方式,对外呈现单机的服务效果。
分布式:有多个不同服务集群共同对系统提供服务的系统称为分布式系统
集群架构作用:
分散单台服务器的访问压力,实现负载均衡
分散单台服务器的存储压力,实现可扩展性
降低单台服务宕机带来的宕机灾难
redis集群原理
所有redis节点彼此互联,通过二进制协议优化传输速度和带宽,每个redis节点都包含自己的master和slave,
集群中节点宕机是集群中超过半数的节点检测失效时才失效
客户端只需要连接集群中任意一个节点即可
客户端执行set命令时,会通过CRC16算法,计算出其哈希槽的位置,根据该位置存储到对应的node节点。执行get操作时,会根据哈希槽的位置,去指定节点内读取数据。
故障转移将宕机的master节点的哈希槽由选出来的slave来接管,不会新创建哈希槽
redis集群搭建
https://blog.csdn.net/m0_37989980/article/details/107778257 二
redis企业解决方案
缓存预热
定义:系统启动前,提前将相关的缓存数据直接加载到缓存系统,避免用户先查询数据库,再将数据缓存的问题!
解决问题:解决用户请求先查询数据库,再将数据缓存的问题
作用:用户直接查询事先被预热的缓存数据,加快查询速度
解决方案:
统计访问频率较高的热点数据,并将统计数据分类,根据级别排序,优先加载级别较高的热点数据,热点数据主从预热
脚本程序固定触发脚本预热
缓存雪崩
定义:同一时间大面积的缓存失效,后面的请求都会直接请求数据库,造成数据库短时间内接收大量请求而崩溃
后果:数据库服务器崩溃
原因:较短时间内,缓存中较多的key集中过期
解决方案(道):
更多的页面静态化处理(模板+动态数据)、构建多级缓存架构、针对慢SQL进行执行计划分析,进而优化SQL、
限流降级短时间内牺牲用户体验,限制一部分请求,降低应用服务器压力,请求低速运转后再逐步放开访问
解决方案(术):
数据有效期策略调整,根据业务有效期进行分类错峰,过期时间使用固定时间+随机值的方式,稀释集中过期的key
超热数据使用永久key
缓存击穿
定义:缓存中没有但数据库中有的数据,一般是缓存时间到期,此时大量并发请求同一条数据,缓存中没有,查询数据库,从而造成数据库崩溃
原因:缓存中某一个热点key过期,该Key访问量巨大,多个请求都压在这个Keys上,但是均为命中,redis短时间内发起了大量对数据库中同一数据的访问
解决方案(术):
设置热点数据永不过期、现场调整Key的过期时间、后台定时刷新热点key有效期
缓存穿透(布隆过滤器解决)
定义:缓存和数据库中都没有的数据,导致所有请求都落在数据库上,造成数据库短时间接到大量请求而崩掉
示例:例如数据库及缓存中的数据都是从id为0开始自增,有人恶意请求id=-1的数据,即缓存穿透
解决方案:
接口层增加校验,如用户鉴权校验,id基础校验,小于等于0的直接拦截
缓存和数据库中都没取到,可以设置为key-null,有效期短一点,30秒左右,可防止用户针对同一个key进行暴力攻击
使用布隆过滤器,判断请求的key是否存在
布隆过滤器:
定义:是一个很长的二进制向量(bit数组)和一系列哈希函数(hash),用于检索一个元素是否在一个集合中。
优点:因为基于位数组和哈希算法,空间效率和查询时间远超一般算法
缺点:有一定的误识别率和删除困难,但是可以通过增加位数组大小和hash函数来降低误识别率(无法避免)
添加数据过程:初始化之后,位数组中值都为0,当增加变量,会通过多个hash函数将元素映射到位数组中各个位上,将对应位置设置为1
查询数据过程:通过多个hash函数将元素映射到位数组中各个位上,如果各个位都是1,则元素可能存在,但如果其中有位不为1,则元素一定不存在
缓存降级
定义:流量骤增,造成响应速度较慢,可对非核心缓存业务进行降级
目的:保证核心服务可用。有些服务无法降级(如加入购物车、结算)
服务降级目的:防止redis故障,导致数据库一起发生雪崩问题,因此可对不重要的缓存数据,采用服务降级策略。
例如redis出现问题,不去数据库查询数据,而是直接返回默认值(兜底默认值)
10.布隆过滤器解决缓存穿透问题
人工智能学习网站:https://www.captainai.net/itcoke/
目的:redis实现布隆过滤器
使用场景:准确判断某个数据是否在大数据集合中,并且不占用内存
简介:一种数据结构,一串很长的二进制向量组成,可看作一个二进制数组,初始默认值都是0
添加数据:通过多个hash函数,计算出在二进制数组中的位置,将其设置为1
判断数据是否存在:将元素通过hash函数算出在二进制数组中的位置,看其是否为1,如果都为1则可能存在,否则一定不存在
优点:二进制数据,占用内存极少,插入和查询速度很快
缺点:随着数据增加,误判率增加;无法判断数据一定存在;无法删除数据
redis实现布隆过滤器:
在redis中,bitmaps提供了一套命令来操作类似字符串中的每一位(setbit、getbit、bitcount等),因此redis实现布隆过滤器底层是通过bitmap数据结构。
Redission是在java中操作redis的库,因此可利用Redission来实现布隆过滤器,也可用guava来实现布隆过滤器