Redis
linux 下载
wget http://download.redis.io/releases/redis-5.0.5.tar.gz
- 压缩包需要安装gcc
yum -y install gcc
//解压redis安装包
tar -Zxvf redis-5.0.5.tar.9Z
//解玉之后进人到redis-5.0.5日录
cd redis-5.8.5
//编译
make MALLOC=1ibe
//安装
make install
##当我们完成redis安装之后,就可以执行redis相关的指令
redis-server 启动redis
redis-cli #打开客户端
#查看指定端口
lsof -i:6379
#杀掉6136
kill -9 6136
redis配置
- 使用redis-server指令启动redis服务的时候,可以在指令后添加redis配置文件的路径,以设置redis是
以何种配置进行启动
redis-server redis-6388.conf&## redis以redis-6388.conf文件中的配置来启动
如果不指定配置文件的名字,则按照redis的默认配置启动(默认配置≠redis.gnf
我们可以通过创建redis根目录下redis.conf 来创建多个配置文件,启动多个redis服务
redis-server redis-6388.conf &
redis-server redis-6381.conf &
常用配置
#设置redis实例(服务)为守护模式,默认值为no,可以设置为yes
daemonize nO
#发直当前red1s实例启动之后保存进程id的文件(在redis.conf 配置里修改)
pidfile /var/run/redis_6379.pid
#设置redis实例的启动端口(默认6379)
port 6379
#设置当前redis实例是否开启保护模式
protected-mode yes
#设置允许访间当前redis实例的ip地址列表
bind 127.0.0.1
#设置连接密码
requirepass 123456
#设直redis买例中数据库的个数(默认16个,编号0-15
databases 16
#设置最大并发数量
maxclients
#设置客户端和redis建立连接的最大空闲时间,设置为9表示不限制
timeout 0
Redis应用场景
1>写操作较少,但是会频繁查询的数据适合做缓存
2>数据一致性要求不高也可以
-
缓存:在绝大多数的互联网项目中,为了提供数据的访问速度、降低数据库的访问压力,我们可以使用redis作为缓存来实现
-
点赞、排行榜、计数器等功能:对数据实时读写要求比较高,但是对数据库的一致性要求并不是太高的功能场景
-
分布式锁:基于redis的操作特性可以实现分布式锁功能
-
分布式会话:在分布式系统中可以使用redis实现session (共享缓存)·消息中间件:可以使用redis实现应用之间的通信
Redis的优点
-
redis是基于内存结构,性能极高(读110000次/秒,写81000次/秒)
-
redis基于键值对存储,但是支持多种数据类型
-
redis的所有操作都是原子性,可以通过lua脚本将多个操作合并为一个原子操作(Redis的事务)
-
reids是基于单线程操作,但是其多路复用实现了高性能读写
Redis的缺点
-
缓存数据与数据库数据必须通过两次写操作才能保持数据的一致性·
-
使用缓存会存在缓存穿透、缓存击穿及缓存雪崩等问题,需要处理
-
redis可以作为数据库使用进行数据的持久存储,存在丢失数据的风险
string
flushall //清空数据
set key value #设置值/修改值 如果key存在则进行修改
get key //取值
mset k1 v1 k2 v2 //批量添加
mget k1 k2 //
setex key time(seconds) value //添加键值对,并设置过期时间
sentnx key value //如果key不存则添加、在如果key存在则添加失败(不做修改操作)
apend key value //在指定key对应value拼接字符串
strlen key //获取key对应的字符串长度
hash(类似于map)
hgetall key //获取hash中所有的键值对
hkeys key //获取hash中所有键
hvals key //获取hash中所有值
hexists key field //检查有没有field的键值对
hlen key //获取hash中键值对的个数
hentnx key field value //向key对应的hash结构中添加f-v,如果field在hash中已经存在则添加失败
zset(有序)
zadd key score member //存储数据(score存储位置必须是数值,可以是float类型的任意数字;member元素不允许重复)
zrange key start top ##查看key对应的有序集合中索引[start,stop]数据--按照score值由小到大(start和 stop指的不是score,而是元素在有序集合中的索引)
zscore key member #查看member元素在key对应的有序集合中的素引
zcard key //获取key对应的zset中的个数
zcount key min max //获取key对应的zset中, score在[min , max]范围内的member个数
zrem key member //从key对应的zset中移除指定的member
zrevrange key start stop //查看key对应的有序集合中索引[start, stop]数据--按照score值由大到小
set(无序集合)
sadd key v1 v2 v3 //可添加多个
smembers key //遍历key对应的集合中所有的元素
spop key //随即从key对应的集合中获取一个值
sinter key1 key2 //交集
sunion key1 key2 //并集
sdiff key1 key2 //差集
srem key value //从key对应的集合中移除指定的value
list(队列)
存
lpush key value //左添加
rpuhs key value //右添加
取
lpop key //左取
rpop key //右取
修改
lset key index value //修改key对应的列表的索引位置的数控(所哟从左往右,从0开始)
lset key 0 7
查看key对应的列表中索引从start开始到stop结束的所有值
lrange key 0 7
lindex key index //查看key对应列表中index索引对应的值
lien key //获取对应的元数个数
ltrim key start stop //从key对应的列表截取key在【0,5】范围的值,不在此范围一律清除
过期时间操作
过期时间操作
TTL 接口定义:TTL key
接口描述:获取key的过期时间。如果key存在过期时间,返回剩余生存时间(秒);如果key是永久的,返回-1;如果key不存在或者已过期,返回-2。
PTTL 接口定义:PTTL key
接口描述:获取key的过期时间。如果key存在过期时间,返回剩余生存时间(毫秒);如果key是永久的,返回-1;如果key不存在或者已过期,返回-2。
PERSIST 接口定义:PERSIST key
接口描述:移除key的过期时间,将其转换为永久状态。如果返回1,代表转换成功。如果返回0,代表key不存在或者之前就已经是永久状态。
SETEX 接口定义:SETEX key "seconds" "value"
接口描述:SETEX在逻辑上等价于SET和EXPIRE合并的操作,区别之处在于SETEX是一条命令,而命令的执行是原子性的,所以不会出现并发问题。
Redis的持久化
RDB策略
在满足redis操作条件时,将内存中的数据以数据快照的形式存储到rdb文件中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BFgrUDWW-1666622329353)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220901193240323.png)]
-
原理:RDB是redis默认的持久化策略,当redis中的写操作达到指定次数,同时距离上一次持久化到达的指定时间就会将redis内存中的数据生成数据快照,保存在指定的rdb文件中,
-
默认触发持久化条件:(可以修改配置文件)
- 900s一次:当操作次数达到1次,900s就会进行持久化
- 300s一次:当操作次数达到10次,300s就会进行持久化
- 60s 100000次:当操作次数达到10000次,60s就会进行持久化
-
RDB持久化细节分析
缺点
- 如果redis出现故障,存在数据丢失的风险,丢失上一次持久化之后的操作数据
- 耐久性差:相对aof的异步策略来说,因为rdb的复制是全量的,即使是fork的子进程来进行备份,当数据量很大的时候对磁盘的消耗也是不可忽视的,尤其在访问量很高的时候,fork的时间也会延长,导致cpu吃紧,耐久性相对较差。
优点
1.体积更小:相同的数据量rdb数据比aof的小,因为rdb是紧凑型文件
2.恢复更快:因为rdb是数据的快照,基本上就是数据的复制,不用重新读取再写入内存
3.性能更高:父进程在保存rdb时候只需要fork一个子进程,无需父进程的进行其他io操作,也保证了服务器的性能。
AOF
Apeend Only File,当达到设定触发条件时,将redis执行的写操作指令存储在aof文件中、redis默认没有开启aof持久话配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UuP91wEg-1666622329354)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220901200221918.png)]
- 原理:redis将每一个成功的写操作写入到aof文件中,当redis重启的时候就执行aof文件中的指令以恢复数据(存储的是指令)
- 配置
#开启AAOF
appendfsync yes
#设置触发条件(3选1)
appendfsync always #只要进行成功的写操作,就执行aof
appendfsync everysec #没秒进行一次aof
appendfsync no #让redis执行决定aof
#设置aof文件路径
appendfilename “appendonly.aof”
-
aof细节分析
- 可以通过拷贝aof文件进行redis数据移植
- aof存储的指令,而且会对指令进行整理;而RDB直接生成数据快照,在数据量不大时RDB比较快
- aof是对指令文件进行增量跟新,更适合实时持久化
- redis官方建议同时开启2种持久化策略,如果同时存在aof和rdb文件的情况下,aof优先
aof的优点
- 数据一致性。
- 即使出现宕机,也不会破坏日志文件中已经存在的内容。
- 数据安全性(持久性)。
aof的缺点
1.性能相对较差:它的操作模式决定了它会对redis的性能有所损耗
2.aof的恢复数据速度比rdb慢。因为aof文件通常大于rdb
缓存穿透:大量的请求一个数据库中不存在的数据,首先在redis中无法命中,最终所有的请求都会访问数据库,同样会导致数据库访问压力变大
(1) **对空值缓存:**如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
(2) 设置可访问的名单(白名单):
使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
(3) 采用布隆过滤器:(布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。)
将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。
(4) **进行实时监控:**当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务
缓存击穿:首先在redis中无法命中,最终所有的请求都会访问数据库,同样会导致数据库访问压力变大
**(1)预先设置热门数据:**在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
**(2)实时调整:**现场监控哪些数据热门,实时调整key的过期时长
(3)使用锁:
(1) 双重检测锁,对写入redis的同时加锁并查一次redis进行写入。
(2) 先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key
(3) 当操作返回成功时,再进行load db的操作,并回设缓存,最后删除mutex key;
(4) 当操作返回失败,证明有线程在load db,当前线程睡眠一段时间再重试整个get缓存的方法。
雪崩:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
(1) **构建多级缓存架构:**nginx缓存 + redis缓存 +其他缓存(ehcache等)
(2) 使用锁或队列*
用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况
(3) 设置过期标志更新缓存:
记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
(4) 将缓存中的数据设置成不同的过期时间
Redis高级应用
使用redis作为缓存数据库使用目的是为了提升数据加载速度、降低对数据库的访问压力,我们需要保证redis
的可用性。
- 主从配置
- 哨兵模式
- 集群配置
主从配置
主从配置:在多个redis实例建立起主从关系,当主redis中的数据发生变化,从redis中的数据也会同步变
化。
- 通过主从配置可以实现redis数据的备份(‘从redis就是对‘主redis’的备份’),保证数据的安全性;
- 通过主从配置可以实现redis的读写分离
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMh6DPpP-1666622329355)(D:\桌面\bug集\扩展\typora-img\image-20220928103039843.png)]
#修改redis-master.conf 端口及远程访间设置 需要保持一致
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e51i6c7x-1666622329355)(D:\桌面\bug集\扩展\typora-img\image-20220928130105835.png)]
#把redis-master.conf里6380改到redis-slave2.conf变成6382
sed 's/6380/6382/g' redis-master.conf > redis-slave2.conf
#在 从的文件里 设置‘跟从’ 127.0.0.1 6380
slaveof 127.0.0.1 6380
哨兵模式
哨兵模式:用于监听主库,当确认主库宕机之后,从备库(从库)中选举一个转备为主
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EeMkc409-1666622329356)(D:\桌面\bug集\扩展\typora-img\image-20220928153954895.png)]
-
哨兵模式配置
#首先实现三个redis实例之间的主从配置(如上) sentinel deny-scripts-reconfig yes sentinel monitor mymaster 127.0.0.1 6380 2 sentinel down-after-milliseconds mymaster 30000 #创建并启动三个哨兵 redis-sentinel sentinel.conf #确认宕机时间 30000 30秒 sentinel down-after-milliseconds mymaster 30000
集群配置
高可用:保证redis一直处于可用状态,即时出现了故障也有备用方案保证可用性
高并发:一个redis头例园经口以文持多达1lw并发读操作或者8.1w并发与操作,但是如果对于自更高并发需求的应用来说,我们可以通过读写分离
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MZy8lLN7-1666622329356)(D:\桌面\bug集\扩展\typora-img\image-20220928164223221.png)]
redis集群
- Redis集群中每个节点是对等的,无中心结构
- 数据按照slots分布式存储在不同的redis节点上,节点中的数据可共享,可以动态调整数据的分布
- 可扩展性强,可以动态的增删节点,最多可扩展至1000+节点
- 集群的每个节点通过主备(哨兵模式)可以保证其高可用性
集群搭建
[root@localhost redis-5.0.5]# mkdir cluster-conf
[root@localhost redis-5.0.5]# cat redis.conf |grep -v '#' |grep -v '^$' >cluster-conf/redis-7001.conf
[root@localhost cluster-conf]# vim redis-7001.conf
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I8S7NGyU-1666622329357)(D:\桌面\bug集\扩展\typora-img\image-20220928170522969.png)]
#拷贝文件
[root@localhost cluster-conf]# sed 's/7001/7002/g' redis-7001.conf > redis-7002.conf
[root@localhost cluster-conf]# sed 's/7001/7003/g' redis-7001.conf > redis-7003.conf
[root@localhost cluster-conf]# sed 's/7001/7004/g' redis-7001.conf > redis-7004.conf
[root@localhost cluster-conf]# sed 's/7001/7005/g' redis-7001.conf > redis-7005.conf
[root@localhost cluster-conf]# sed 's/7001/7006/g' redis-7001.conf > redis-7006.conf
#启动redis实例
[root@localhost cluster-conf]# redis-server redis-7001.conf
#查看redis实例
[root@localhost cluster-conf]# ps -ef|grep redis
#启动集群 127.0.0.1 47.96.11.185(必须是公网才可以被别人访问)
[root@localhost cluster-conf]# redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1
#集群管理
#查看集群状态
[root@localhost cluster-conf]# redis-cli --cluster info 127.0.0.1:7003
springboot应用连接集群
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId
<artifactId>spring-boot-starter-data-redis</artifactId
</dependency>
-
配置集群节点
spring:
redis:
cluster:
nodes:47.96.11.185 :7891,47.96.11.185:7602,47.96.11.185:7693
max-redirects: 3
redis淘汰策略
# volatile-lru -> 从设置了过期时间的数据中淘汰最火未使用的数据
# allkeys-lru -> 从所有数据中淘汰最久未使用的数据
# volatile-lfu -> 从设直过期时日的数据中淘汰使用最少的数据
# allkeys-lfu -> 从所有数据中淘法使用最少的数据
# volatile-random ->从设直了过期时间的数据中随机淘汰一批数据
# allkeys-random -> 从所有数据中随机淘汰一批数据
# volatile-ttl -> 淘汰过期时间最短的数据
# noeviction -> 不海浓什何数据,当内仔不可时自楼·郴出异吊
理解两个算法名词:
LrU:最久最近未使用
LfU:最近最少使用
使用Redis实现分布式会话
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtzuK5nx-1666622329358)(D:\桌面\bug集\扩展\typora-img\image-20221002203719989.png)]
把token写入到redis 在配置 拦截器 对受限资源进行拦截 对不受限资源进行续命
//配置拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private TonckInterceptor tonckInterceptor;
@Autowired
private SettimeInterceptor settimeInterceptor;
@Override
public void addInterceptors (InterceptorRegistry registry) {
registry. addInterceptor(tonckInterceptor)
.addPathPatterns("/t_goods/**")//设置受限资源
// .addPathPatterns("/shoppingcart/**")
.excludePathPatterns("/users/**")//不受限资源
;
registry.addInterceptor(settimeInterceptor).addPathPatterns("/**");
}
}
@Autowired
private SettimeInterceptor settimeInterceptor;
@Override
public void addInterceptors (InterceptorRegistry registry) {
registry. addInterceptor(tonckInterceptor)
.addPathPatterns("/t_goods/**")//设置受限资源
// .addPathPatterns(“/shoppingcart/“)
.excludePathPatterns(”/users/”)//不受限资源
;
registry.addInterceptor(settimeInterceptor).addPathPatterns(“/**”);
}
}