参考文档-Redis快速入门指南-中文
参考文档-Redis 教程
一、启动并连接
本地启动一个redis
或者用redis cloud
免费账户,都可以。
1 | docker run --name CommonTrain -p 6379:6379 -itd redis:7.2 |
然后下载REDISINSIGHT。
二、支持的数据类型
- 字符串
string
- 哈希
hash
- 列表
list
- 集合
set
- 有序集合
sorted set
- 位图
bitmaps
- 基数统计
hyperLogLogs
参考文档-Redis快速入门指南-中文
参考文档-Redis 教程
本地启动一个redis
或者用redis cloud
免费账户,都可以。
1 | docker run --name CommonTrain -p 6379:6379 -itd redis:7.2 |
然后下载REDISINSIGHT。
string
hash
list
set
sorted set
bitmaps
hyperLogLogs
缓存击穿就是大量并发访问同一个热点数据,一旦这个热点数据缓存失效,则请求压力都来到数据库。
1 | @Override |
使用缓存预热,把数据提前放入缓存,然后根据过期时间,发布合理的定时任务,主动去更新缓存,让热点数据永不过期。
Redis之缓存穿透问题解决方案实践SpringBoot3+Docker
当一种请求,总是能越过缓存,调用数据库,就是缓存穿透。
比如当请求一个数据库没有的数据,那么缓存也不会有,然后就一直请求,甚至高并发去请求,对数据库压力会增大。
key
具有某种规则,那么可以对key增加校验机制,不符合直接返回。Redisson
布隆过滤器null
为value
,也插入redis
缓存,但设置较短的过期时间。docker-compose示例如下,redis.conf从这里下载
1 | redis: |
1 | <!-- redis --> |
1 | spring: |
要演示的代码很简单,就是一个携带courseId
请求过来,调用下面的service
函数,然后查询数据库。
1 | @Override |
当我们使用redis改造时,基本代码如下
1 | @Override |
我这里的id
没规则,所以加不了,跳过。
读取yaml
配置
1 | @Data |
配置RedissonClient
1 | @Slf4j |
把布隆过滤器加到service
,如下
1 | private RBloomFilter<String> bloomFilter; |
当数据库没有此数据,以null
为value
,也插入redis
缓存,但设置较短的过期时间。
1 | //后查询数据库 |
Redis之缓存穿透问题解决方案实践SpringBoot3+Docker
缓存雪崩,指大量的缓存失效,大量的请求又同时落在数据库。主要的一种诱因是key设置的过期时间都一样。
加锁,每次只让一个线程可以访问数据库,随后存入缓存。性能太差。
最简单有效的解决办法是设置不同的过期时间。比如
1 | int timeout = 10 + new Random().nextInt(20); |
使用缓存预热,把数据提前放入缓存,然后根据过期时间,发布合理的定时任务,主动去更新缓存。
缓存预热参考代码如下。
1 | @Component |
至于定时任务,可以使用xxl-job。具体使用方法,可以参考这个文章
Docker部署xxl-job调度器并结合SpringBoot测试
通过本文章,可以完成多级缓存架构中的Redis缓存。
在docker/docker-compose.ym
l中,添加redis服务块
1 | redis: |
在spirngboot
项目启动时,将固定的热点数据提前加载到redis
中。
pom.xml
添加如下依赖
1 | <dependency> |
application.yml
添加如下配置
1 | spring: |
新建config.RedisHandler
类,内容如下,主要是重写afterPropertiesSet
,完成缓存预热逻辑,saveItem
和deleteItemById
函数给之后的章节使用。
1 | @Component |
改进openresty
的docker/openresty1/lualib/common.lua
,如下
1 | local redis = require('resty.redis') |
item.lua
不需要用改动。
到此为止,docker-compose.yml
内容应该如下
1 | version: '3.8' |
删除原来的multiCache
,重新启动各项服务。
1 | docker-compose -p multi-cache up -d |
启动springboot
程序。
springboot
程序启动后,出现查询日志,查看redis
数据库发现自动存入了数据。
清空openresty
容器日志,访问http://localhost:8080/item.html?id=10001
,查看日志,发现两次commonUtils.read_data
都只触发到查询redis
,没到查询tomcat
。
1 | 2024-01-12 16:06:18 2024/01/12 08:06:18 [error] 7#7: *1 [lua] common.lua:59: read_data(): local cache miss, try redis, key: item:id:10001, client: 172.30.3.3, server: localhost, request: "GET /api/item/10001 HTTP/1.0", host: "nginx-cluster", referrer: "http://localhost:8080/item.html?id=10001" |
查看springboot
程序日志,也没有查询记录,说明redis
缓存命中成功。
对于redis
高可用集群,可以参考以下专栏文章。
https://blog.csdn.net/m0_51390969/category_12546314.html?spm=1001.2014.3001.5482
SpringBoot基于Redis(7.2)分片集群实现读写分离
SpringBoot
访问Redis
分片集群和Redis
哨兵模式,使用上没有什么区别。唯一的区别在于application.yml
配置上不一样。
首先,无论如何,得先有一个Redis分片集群,具体可以参考下面这篇文章
搭建完成后大致得到如下图描述的一个集群。
其次,具体如何结合Idea
和Docker
让本地开发的SpringBoot
项目访问Redis
分片集群,可以参考下面这篇文章
要注意的是,yaml
文件要从
1 | spring: |
变成
1 | spring: |
其余基本一致。
Docker-Compose部署Redis(v7.2)分片集群(含主从)
环境
目标
搭建如下图分片+主从集群。
因为Redis 7.2 docker
镜像里面没有配置文件,所以需要去redis
官网下载一个复制里面的redis.conf
博主这里用的是7.2.3
版本的redis.conf
,这个文件就在解压后第一层文件夹里。
然后构建如下文件夹结构。
1 | sharding/ |
对每个redis.conf
都做以下修改。分片集群的redis
主从的redis.conf
目前都是一样的。
1 | port 6379 |
1 | version: '3.8' |
需要注意以下几点
bridge
子网并限定了范围,如果该范围已经被使用,请更换。data
进行-v
挂载,如果要挂载,请注意宿主机对应文件夹权限问题。随后运行
1 | docker-compose -p redis-sharding up -d |
接下来所有命令都在master1
容器的命令行执行
这个命令会创建了一个集群,包括三个主节点和三个从节点,每个主节点分配一个从节点作为副本,前3个ip
为主节点,后3个为从节点,主节点的从节点随机分配。
1 | redis-cli --cluster create 172.30.2.11:6379 172.30.2.12:6379 172.30.2.13:6379 172.30.2.21:6379 172.30.2.22:6379 172.30.2.23:6379 --cluster-replicas 1 |
如果希望手动指定主从关系,看下面,否则你可以跳过这一章节了。
1 | redis-cli --cluster create 172.30.2.11:6379 172.30.2.12:6379 172.30.2.13:6379 --cluster-replicas 0 |
查看3个主节点的ID
1 | redis-cli -h 172.30.2.11 -p 6379 cluster nodes |
下面3个命令会将3个从节点加入集群中,其中172.30.2.11
可以是三个主节点的任意一个。
1 | redis-cli -h 172.30.2.21 -p 6379 cluster meet 172.30.2.11 6379 |
然后为每个从节点指定主节点。
1 | redis-cli -h 172.30.2.21 -p 6379 cluster replicate <master-ID> |
可以通过以下命令查看集群中每个节点的id、角色、ip、port、插槽范围
等信息
1 | redis-cli -h 172.30.2.11 -p 6379 cluster nodes |
往集群存入4个键值
1 | redis-cli -c -h 172.30.2.11 -p 6379 set key1 value1 |
查看每个主节点现有的键值,会发现每个节点只有一部分键值。
1 | redis-cli -h 172.30.2.11 -p 6379 --scan |
SpringBoot基于哨兵模式的Redis(7.2)集群实现读写分离
环境
先根据以下文章搭建一个Redis集群
部署完后,redis集群看起来大致如下图
需要注意的是lettuce-core
版本问题,不能太旧,否则不兼容新版的Redis
。
1 | <dependency> |
在application.yml
加入以下配置。第一个password
是用于sentinel
节点验证,第二个password
用于数据节点验证。
1 | spring: |
这里关于sentinel
的ip
问题后面会讲解。
在任意配置类中写一个Bean
,本文简单起见,直接写在SpringBoot
启动类了。
1 | @Bean |
这里的ReadFrom
是配置Redis
的读取策略,是一个枚举,包括下面选择:
MASTER
:从主节点读取MASTER_PREFERRED
:优先从master节点读取,master不可用才读取replicaREPLICA
:从slave (replica)节点读取REPLICA_PREFERRED
:优先从slave (replica)节点读取,所有的slave都不可用才读取master至于哪些节点支持读,哪些支持写,因为redis 7
默认给从节点
设置为只读,所以可以认为只有主节点有读写权限,其余只有读权限。如果情况不一致,就手动给每一个redis-server
的配置文件都加上这一行。
1 | replica-read-only yes |
写一个简单的controller
,等会用于测试。
1 | @RestController |
首先,因为所有redis
节点都在一个docker bridge
网络中,所以基于Idea
编写的项目在宿主机(Windows)中运行spirngboot
程序,不好去和redis
集群做完整的交互。
虽然说无论是sentinel
还是redis-server
都暴露了端口到宿主机,我们可以通过映射的端口分别访问它们,但是我们的程序只访问sentinel
,sentinel
管理redis-server
,sentinel
会返回redis-server
的ip
来让我们的程序来访问redis-server
,这里的ip
是docker bridge
网络里的ip
,所以即使我们的程序拿到ip
也访问不了redis-server
。
这个时候就需要将我们的项目放到一个docker
容器中运行,然后把这个容器放到和redis
同一网络下,就像下图。
具体如何快捷让Idea结合Docker去运行SpringBoot程序,可以参考下面这篇文章。
记得要暴露你的程序端口到宿主机,这样才方便测试。
浏览器访问localhost:8080/set/num/7799
查看SpringBoot
容器日志,可以看到向主节点172.30.1.2:6379
发送写请求。
1 | 01-06 07:23:59:848 DEBUG 1 --- [nio-8080-exec-6] io.lettuce.core.RedisChannelHandler : dispatching command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] |
浏览器访问localhost:8080/get/num
查看SpringBoot
容器日志,会向两个从节点之一发送读请求。
1 | 01-06 07:25:45:342 DEBUG 1 --- [io-8080-exec-10] io.lettuce.core.RedisChannelHandler : dispatching command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] |
以及还有一些额外的测试,可以自行去尝试,检验,这里列举一些,但具体不再赘述。
sentinel
完成维护和通知后,测试读数据和写数据会请求谁?sentinel
完成操作后,再关闭主节点,等待sentinel
完成操作后,测试读数据和写数据会请求谁?sentinel
完成操作后,测试读数据和写数据会请求谁?Docker-Compose部署Redis(v7.2)主从模式
环境
因为Redis 7.2 docker
镜像里面没有配置文件,所以需要去redis
官网下载一个复制里面的redis.conf
博主这里用的是7.2.3
版本的redis.conf
,这个文件就在解压后第一层文件夹里。
1 | docker pull redis:7.2 |
如下建立cluster
文件夹,并复制出三份conf
文件到如图位置。
docker-compose
文件具体内容如下。
1 | version: '3.8' |
需要注意以下几点
bridge
子网并限定了范围,如果该范围已经被使用,请更换。data
进行-v
挂载,如果要挂载,请注意宿主机对应文件夹权限问题。主节点对应的配置文件是master/redis.conf
,需要做以下修改
bind
将bind 127.0.0.1 -::1
修改为bind 0.0.0.0
,监听来自任意网络接口的连接。
protected-mode
将protected-mode
设置为no
,关闭保护模式,接收远程连接。
masterauth
将masterauth
设置为1009
,这是从节点连接到主节点的认证密码,你可以指定为其他的。
requirepass
将requirepass
设置为1009
,这是客户端连接到本节点的认证密码,你可以指定为其他的。
把上面主节点的配置文件复制粘贴,然后继续做以下更改,就可以作为从节点配置文件了
replicaof redis-master 6379
,表示本节点为从节点,并且主节点ip
为redis-master
,端口为6379
。这里你也可以把ip
填成172.30.1.2
,因为在docker-compose
中我们为各节点分配了固定的ip
,以及端口是6379
而不是映射的700x
,这些都是docker
的知识,这里不再赘述。redis在5.0引入了replica的概念来替换slave,所以后续的新版本推荐使用replicaof,即便slaveof目前仍然支持。
配置好三个节点的配置文件后,用以下命令运行整个服务
1 | docker-compose -p redis-cluster up -d |
查看主节点日志,可以看到主节点向172.30.1.3
和172.30.1.4
两个从节点同步数据,并且连接正常,以及一系列success。
1 | 2024-01-05 15:12:59 1:M 05 Jan 2024 07:12:59.008 * Opening AOF incr file appendonly.aof.1.incr.aof on server start |
接着看看从节点日志,可以看到Connecting to MASTER redis-master:6379
,向主节点连接并申请同步数据,以及一系列success。
1 | 2024-01-05 15:13:01 1:S 05 Jan 2024 07:13:01.166 * Connecting to MASTER redis-master:6379 |
用你喜欢的docker
容器连接工具或者redis
连接工具来连接主节点redis
服务,只要能进入redis-cli
就行。这里以docker容器连接为例。
1 | root@ac1ecfc4e3a5:/data# redis-cli |
1 | root@a3016db388e3:/data# redis-cli |
测试成功。
Docker-Compose部署Redis(v7.2)哨兵模式
环境
首先需要有一个redis主从集群,才能接着做redis哨兵。具体可以参考下面这篇文章
Docker-Compose部署Redis(v7.2)主从模式(之后简称”主从模式博文
“)
和主从模式不同的是,redis sentinel
(哨兵)会更改你的conf
文件,无论是redis server
节点还是sentinel
节点本身,都可能被修改,所以这里需要注意文件权限问题。不然会一直警告Sentinel was not able to save the new configuration on disk
。
有兴趣可以参考以下几个帖子,或者接着本文做就行了。
总的来说,需要对主从模式博文
里提到的文件夹结构做一定改善和添加,具体如下:
1 | cluster/ |
其中redis.conf
和docker-compose.yaml
和主从模式博文
内容暂时保持一致,其余的都是新增的,暂时保持空白即可。
保持不变
对于上述三个sentinel.conf
内容都填入以下
1 | sentinel monitor mymaster 172.30.1.2 6379 2 |
意思分别是
sentinel monitor
指定要监控的主节点。这包括一个用户定义的名称(如 mymaster
)、主节点的地址、端口号和一个”仲裁”阈值,后者表示要进行故障转移所需的最小 Sentinel
投票数量。Sentinel
判断主节点是否下线所需的时间Sentinel
需要这个密码来连接主节点和副本节点Sentinel
的工作目录1 | version: '3.8' |
需要注意以下几点
主从模式博文
不同,这里所有的配置文件挂载都采用文件夹挂载
而非单文件挂载
bridge
子网并限定了范围,如果该范围已经被使用,请更换。data
进行-v
挂载,如果要挂载,请注意宿主机对应文件夹权限问题。172.30.1.2
,如果更改请注意sentinel.conf
中也需要更改。在运行之前,记得备份一下所有的conf文件,因为sentinel会修改挂载到容器的conf。
1 | docker-compose -p redis-cluster up -d |
查看其中一个sentinel节点的日志,可以看到监听端口是26379,同时监测主节点mymaster 172.30.1.2 6379
,以及添加了172.30.1.4 6379
和172.30.1.3 6379
两个从节点,并且感应到了位于172.30.1.13 26379
和172.30.1.12 26379
两个同为sentinel
节点的服务。
1 | 2024-01-05 18:06:40 1:X 05 Jan 2024 10:06:40.758 * Running mode=sentinel, port=26379. |
直接让redis-master
容器停止运行,查看sentinel
日志,可以看到sentinel
监测到master
节点挂掉后,选举了172.30.1.3
为新的主节点,并将其余两个作为slave
节点。
1 | 2024-01-05 18:10:08 1:X 05 Jan 2024 10:10:08.896 # +sdown master mymaster 172.30.1.2 6379 |
接着让我们看看172.30.1.3
的日志,也就是redis-replica1
的日志,可以看到与主节点连接失败后,它开启了主节点模式MASTER MODE enabled
。
1 | 2024-01-05 18:10:03 1:S 05 Jan 2024 10:10:03.812 * Reconnecting to MASTER 172.30.1.2:6379 |
并且还有redis-replica2
的日志,里面会显示将数据同步请求地址变成了172.30.1.3
而不是先前的172.30.1.2
。
接着连接redis-replica1
容器看看,发现这个节点以前作为从节点时是只读
节点,现在可以写入数据了。
1 | root@1eefea35001f:/data# redis-cli |
并且会发现另外两个节点变成只读
了,同时,即使先前的主节点又恢复正常了,它不会去夺回master
地位。
测试成功。