默认情况下,我们使用的布隆过滤器它的错误率是 0.01 ,默认的元素大小是 100。但是这两个参数也
是可以配置的。
我们可以调用 bf.reserve 方法进行配置。
第一个参数是 key,第二个参数是错误率,错误率越低,占用的空间越大,第三个参数预计存储的数
量,当实际数量超出预计数量时,错误率会上升。
之前说的新闻推送过滤、电话号码过滤是一个应用场景
缓存穿透问题,又叫缓存击穿问题。
假设我有 1亿 条用户数据,现在查询用户要去数据库中查,效率低而且数据库压力大,所以我们会把请
求首先在 Redis 中处理(活跃用户存在 Redis 中),Redis 中没有的用户,再去数据库中查询。
现在可能会存在一种恶意请求,这个请求携带上了很多不存在的用户,这个时候 Redis 无法拦截下来请
求,所以请求会直接跑到数据库里去。这个时候,这些恶意请求会击穿我们的缓存,甚至数据库,进而
引起“雪崩效应”。
为了解决这个问题,我们就可以使用布隆过滤器。将 1亿条用户数据存在 Redis 中不现实,但是可以存
在布隆过滤器中,请求来了,首先去判断数据是否存在,如果存在,再去数据库中查询,否则就不去数
据库中查询。
Pipeline(管道)本质上是由客户端提供的一种操作。Pipeline 通过调整指令列表的读写顺序,可以大幅度的节省 IO 时间,提高效率。
怎么理解这个呢?假设A用户在客户端做写入缓存操作和读取缓存操作,B用户也在客户端做写入缓存操作和读取缓存操作。如果没有使用Piepline技术,那么A、B用户写操作和读操作一共需要使用4个网络来回。使用Pipeline进行指令调整,可以把写操作放入同一个网络来回进行写,读取操作放入同一个网络来回进行读取,大幅度节省网络IO,提高效率。
2.简单限流简单限流思路其实很简单,就是在一个限流周期的时间窗口允许执行的操作次数,这边自己编写的一个代码如下,能达到基本的限流需求。
package org.taoguoguo.limit; import org.taoguoguo.redis.Redis; import redis.clients.jedis.Jedis; import redis.clients.jedis.Pipeline; import redis.clients.jedis.Response; /** * @author taoguoguo * @description RateLimiter Redis简单限流 * @website https://www.cnblogs.com/doondo * @create 2021-04-21 21:49 */ public class RateLimiter { private Jedis jedis; public RateLimiter(Jedis jedis) { this.jedis = jedis; } /** * 限流方法 * @param user 操作用户,相当于限流的对象 * @param action 具体的操作 * @param period 时间戳 限流的周期 * @param maxCount 限流次数 * @return */ public boolean isAllowed(String user, String action, int period, int maxCount){ //1.首先生成一个key,数据用zset保存 String key = user + "-" + action; //2.获取当前时间戳 long nowTime = System.currentTimeMillis(); //3.建立管道 Pipeline pipelined = jedis.pipelined(); //开启任务执行 pipelined.multi(); //4.将当前操作先存储下来 pipelined.zadd(key, nowTime, String.valueOf(nowTime)); //5.移除时间窗之外的数据 假设我要统计30S内的操作次数 先移除当前时间之前的统计时间周期内的操作次数 pipelined.zremrangeByScore(key, 0, nowTime- period * 1000); //6.统计周期内剩下的key Response<Long> response = pipelined.zcard(key); //7.将当前key设置一个过期时间,过期时间就是时间窗 pipelined.expire(key, period+1); //执行任务 pipelined.exec(); //关闭管道 pipelined.close(); return response.get() <= maxCount; } public static void main(String[] args) { Redis redis = new Redis(); redis.execute(j -> { RateLimiter rateLimiter = new RateLimiter(j); for (int i = 0; i < 20; i++) { boolean allowed = rateLimiter.isAllowed("taoguoguo", "addOrder", 5, 3); System.out.println(allowed); } }); } } 3.Redis-Cell 限流Redis4.0 开始提供了一个 Redis-Cell 模块,这个模块使用漏斗算法,提供了一个非常好用的限流指令。
漏斗算法就像名字一样,是一个漏斗,请求从漏斗的大口进,然后从小口出进入到系统中,这样,无论
是多大的访问量,最终进入到系统中的请求,都是固定的。
使用漏斗算法,需要我们首先安装 Redis-Cell 模块:https://github.com/brandur/redis-cell
安装步骤
安装redis-cell插件
wget https://github.com/brandur/redis-cell/releases/download/v0.2.4/redis-cell- v0.2.4-x86_64-unknown-linux-gnu.tar.gz tar -zxvf redis-cell-v0.2.4-x86_64-unknown-linux-gnu.tar.gz mkdir redis-cell mv libredis_cell.d ./redis-cell mv libredis_cell.so ./redis-cell