缓存
Redis是什么大家都知道,一个非关系型数据库。大部分情况下我们使用Redis做缓存。使用缓存的情况一般是这样的:
![24256343c33de9e569e4ade25eb3f216.png](https://i-blog.csdnimg.cn/blog_migrate/fbab1d0c739a743a024848bb913280bf.jpeg)
Redis缓存
“
(1)从Redis缓存中获取数据,如果存在数据,直接返回值。
(2)如果不存在,执行数据库的查询方法
(3)将数据库中的值放入缓存,并返回值
”
代码如下:
![4a68804aba51b5132208b89a3832401b.png](https://i-blog.csdnimg.cn/blog_migrate/2e4a1c4225f642b669ec9d5985f23887.jpeg)
当然我们也可以使用Spring的缓存注解@Cacheble。我们要在配置类上面开启缓存注解@EnableCaching,使用如下:
![7d2554262d588b66221eb90758beae42.png](https://i-blog.csdnimg.cn/blog_migrate/082c8bc5afe66636d08928bcfa8e3724.jpeg)
有兴趣的童鞋可以看看我写的这篇文章:
“
利用AOP自定义Redis缓存注解
”
这篇文章里我重新开发了缓存注解,增加了两个功能:设置超时时间和设置并发请求数。可以实现不同场景设置不同参数。
队列
上面其实就是我们常用的场景,那么Redis除了做缓存,还可以做什么呢?
我们还可以使用Redis做队列。
![cb7d9f29cc982685abcb4be960b77c82.png](https://i-blog.csdnimg.cn/blog_migrate/4d957085a0910c5fa559522831da9b12.jpeg)
Redis队列
那么我们什么时候可以使用Redis的队列功能呢?
![80e9b0ae62858af1d49fa0c62f8e8e0a.png](https://i-blog.csdnimg.cn/blog_migrate/58fc18dff5283e841042d68e2c44ddf0.jpeg)
示例代码如上。
关于具体使用情形,可以看看我写的这篇文章:
“
我的多线程爬虫项目实战
”
这篇文章的爬虫项目中,爬取的时候可能因为网络等原因,爬取的那一条数据会失败。这时我会记录失败的url或code,并将爬取异常的url或code存入Redis队列。
我在后台重新启动一个线程,自旋的形式将Redis的队列中的数据阻塞式取出。然后再一次爬取。
![88dfa2821f17ca0f6e33f4d3d6ca5bb5.png](https://i-blog.csdnimg.cn/blog_migrate/142d14e7370848cb95c4f5583d214512.jpeg)
Redis爬虫
签到统计
我们可以使用Redis的Bitmap存储签到数据。
Bitmap是一个二进制的数组,长度不限(当长度为20亿时,占用内存200多MB)。数组内的值为0或1。
使用Redis的Bitmap,速度很快,在高并发情况下有更优良的性能。而且占用空间很小,Bitmap大约可以存储个bit位(bit数组大约五六亿的长度)。
例如:sign:1:202009 表示id为1的用户2020年9月的签到记录。
![462a570eef99874b81bb784303ce3c30.png](https://i-blog.csdnimg.cn/blog_migrate/e9ca0717731dcec91fb3e50c4ee5a2c1.jpeg)
Java示例代码如下:
jedis.bitfield(buildSignKey(userId, date), "GET", type, "0");
具体使用情况可以看看我写的这篇文章:
“
我做了个签到功能,架构师用Bitmap优化了
”
原子扣减库存
在秒杀系统中,使用Redis来存储库存数量,当用户发起抢购请求时,先判断Redis中的库存是否可用。如果可用,将抢购请求放入分布式队列中,采用异步方式处理后续操作,并完成下单。同时在Redis中作库存扣减。
![4d366c1618342958961ca413453e2407.png](https://i-blog.csdnimg.cn/blog_migrate/098afc5db25baa6af5826ccca2d9e456.jpeg)
Redis库存扣减
示例代码如下:
![97ad1870c9f4f0480c61c94c944d90b0.png](https://i-blog.csdnimg.cn/blog_migrate/a95ffd52b2d9b147990490dcafa8544b.jpeg)
有兴趣的童鞋可以看看我写的这篇文章:
“
一次阿里面试,我被问到了如何设计秒杀系统
”
Redis分布式锁
现在的系统都是集群部署,每个服务都不是单节点的了。比如库存服务,可能部署到3台机器上分别命名为节点1,节点2,节点3。库存服务(使用数据库如MySQL)需要扣减库存,扣减库存肯定需要锁吧,如果使用Lock或者synchronized,只能锁住自己的节点。而从前台访问是随机路由到这3台节点的。如果线程一进来使节点1上了锁,当线程二进来可能访问到的是节点2,这时节点2还没有上锁,那么库存就会扣减错误。而库存扣减还是一个核心操作,现在居然有Bug,想想就可怕。
Redis分布式锁实现思路如下:
“setnx + 过期时间 用lua脚本保证原子性锁持有心跳检测(防止未解锁,锁失效问题)线程自选获取锁”
我们也可以使用已有的轮子Redisson框架。
![13ebd223b08f9f957d0d8f4e5d6b7ce0.png](https://i-blog.csdnimg.cn/blog_migrate/b2ab710886e6356ba76fb4f252c04716.jpeg)
Redis延迟队列
Redis的zset可以用于作延迟队列,score为延迟的时间点,获取时顺序获取端口的值,如果当前时间戳等于score则可取出。
![64eecbd0d52d0d510e5e2051160ec3ed.png](https://i-blog.csdnimg.cn/blog_migrate/8b7058af978b725fca36390575eb6372.jpeg)
示例代码见上图。
其他
Redis还有很多更丰富的功能。比如生成全局的id号(原子自增)、微博点赞次数统计(原子自增)、布隆过滤器(Bitmap)、排行榜实现(zset)、地理位置查询(GEO)、生产者消费者(Stream)、发布订阅。
有兴趣的可以看看我的这篇文章:
“
Redis进阶:
https://mp.weixin.qq.com/s?__biz=Mzg4NDMyNTIwMw==&mid=2247483916&idx=1&sn=09d4e1f6d57bbb5ace4d54278b7fdbdb&chksm=cfb8ac30f8cf2526940e5a8bbc45e7a439ff72e1259954335a3fd1ac177c223d4c346b547143&token=1167723115&lang=zh_CN&scene=21#wechat_redirect
”
这篇文章就写到这里啦,欢迎大家留言自己在项目中如何使用Redis的。