redis 辅助工具包 redis-aux

AFL-3.0
Java Lua
跨平台
2020-01-06
1016644172

黑龙江福彩网_[官网首页]主要有两个模块——布隆过滤器、基于注解限流。目前的功能基于redisTemplate

用法:

这里用maven作为工具管理包演示,添加jitpack源、添加下面的依赖

    <repositories>
        <repository>
            <id>jitpack.io</id>
            <url>http://jitpack.io</url>
        </repository>
     </repositories>
<dependency>
	    <groupId>com.github.97lele</groupId>
	    <artifactId>redis-aux</artifactId>
	    <version>0.2.1</version>
	</dependency>

布隆过滤器演示:

在启动类上添加启用工具包的注解

@EnableRedisAux

三个属性,分别为

1.需要支持lambda表达式添加的实体路径

2.是否开启支持@Trancational注解,需要和数据库事务配合使用

3.是否开启限流功能

配置好redis

spring:
 redis:
   port: 6379
   host: 127.0.0.1

添加方法

只有两种,一种是通过构建操作对象来添加,一种是通过解析lambda表达,获取其字段上的注解信息来添加

若要调用SFunction为参数的方法需要在EnableRedisAux配置扫描路径

主要是exceptedInsertions,fpp这里两个参数,分别为预计插入的个数,允许的错误率,后来补上了两个功能,一个是是否支持扩容,另一个是键的存活时间

演示,添加主要分为普通添加

@Test
    void simpleTest() {
    String key = "testAdd";
        AddCondition addCondition = AddCondition.of().keyName(key);
        BaseCondition baseCondition = addCondition.asBaseCondition();
        bloomFilter.add(addCondition, "hello");
        System.out.println("contain he:"+bloomFilter.mightContain(baseCondition,"he"));
        System.out.println("contain hello:"+bloomFilter.mightContain(baseCondition,"hello"));
        //多值操作
        bloomFilter.addAll(addCondition,Arrays.asList("h","a","c"));
        System.out.println("before reset:"+bloomFilter.mightContains(baseCondition,Arrays.asList("a","b","c")));
        //重置,注意如果开启了增长,对应新的布隆过滤器们也会重置
        bloomFilter.reset(baseCondition);

        System.out.println("after reset:"+bloomFilter.mightContains(baseCondition,Arrays.asList("a","hello","qq")));
        System.out.println("before delete:"+redisTemplate.hasKey(key));
        //删除,也会把增长相关的删除
        bloomFilter.remove(baseCondition);
        System.out.println("after delete:"+redisTemplate.hasKey(key));
    }

 

结果

 

 

 

lambda演示,需要实体类实现getter和序列化接口,并且添加上前缀名,否则默认为类名,需要操作的属性上面添加BloomFilterProperty注解,该注解可填充属性有以下,key如果不填按字段名处理

 double fpp() default 0.03;
    long exceptionInsert() default 1000;
    String key() default "";
    long timeout() default -1L;
    TimeUnit timeUnit() default TimeUnit.SECONDS;
    boolean enableGrow() default false;
    double growRate() default 0.7;

 

@BloomFilterPrefix
public class TestEntity {
    @BloomFilterProperty(enableGrow = true,exceptionInsert = 5,timeout = 30)
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

基于lambda的测试代码

@Test
    public void lambdaTest() throws InterruptedException {
      bloomFilter.addAll(TestEntity::getName, Arrays.asList(13, 14, 15, 16));
        System.out.println(bloomFilter.mightContain(TestEntity::getName, 15));
        System.out.println(bloomFilter.mightContains(TestEntity::getName, Arrays.asList(13, 200)));
    }

结果

扩容测试

 @Test
    public void growTest() {
        String key = "testGrow";
        String key2 = "testGrow2";
        AddCondition addCondition2 = AddCondition.of().keyName(key2).exceptionInsert(5L);
        AddCondition addCondition=AddCondition.of().keyName(key).exceptionInsert(5L).enableGrow(true).timeout(30L);
        bloomFilter.addAll(addCondition2, Arrays.asList(1, 2, 3, 4));
        bloomFilter.addAll(addCondition2, Arrays.asList(5, 6, 7, 8));
        bloomFilter.addAll(addCondition2, Arrays.asList(9, 10, 11, 12));
        bloomFilter.addAll(addCondition2, Arrays.asList(13, 14, 15, 16));
        System.out.println("withOutGrow"+bloomFilter.mightContains(addCondition2.asBaseCondition(), Arrays.asList(13, 200)));
        bloomFilter.addAll(addCondition, Arrays.asList(1, 2, 3, 4));
        bloomFilter.addAll(addCondition, Arrays.asList(5, 6, 7, 8));
        bloomFilter.addAll(addCondition, Arrays.asList(9, 10, 11, 12));
        bloomFilter.addAll(addCondition, Arrays.asList(13, 14, 15, 16));
        System.out.println("withGrow:"+bloomFilter.mightContains(addCondition.asBaseCondition(), Arrays.asList(13, 200)));
    }

 

键过期测试

 @Test
    void timeOutTest() {
        bloomFilter.add(AddCondition.of().keyName("a1").timeout(30L).timeUnit(TimeUnit.SECONDS), 1);
        bloomFilter.addAll(AddCondition.of().keyName("a4").timeUnit(TimeUnit.SECONDS).timeout(10L), Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
        bloomFilter.add(AddCondition.of().keyName("a2").timeout(11L).timeUnit(TimeUnit.SECONDS), 1);
        bloomFilter.add(AddCondition.of().keyName("a3").timeout(22L).timeUnit(TimeUnit.SECONDS), 1);
        System.out.println(bloomFilter.mightContain(BaseCondition.of().keyName("a1"), 1));
        try {
            TimeUnit.SECONDS.sleep(35L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(redisTemplate.keys("a*").size());
    }

 

开启支持事务

清空redis的键

service代码,一个有错,一个无错

package com.example.demo.service;

import com.example.demo.dao.UserTicketMapper;
import com.example.demo.entity.UserTicket;
import com.trendy.util.redis.aux.bloomfilter.autoconfigure.RedisBloomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * @author: lele
 * @date: 2020/1/4 下午11:51
 */
@Service
public class TestService {

    @Autowired
    private UserTicketMapper userTicketMapper;

    @Autowired
    private RedisBloomFilter redisBloomFilter;

    @Transactional(rollbackFor = Exception.class)
    public void wrong() {
        AddCondition addCondition = AddCondition.of().keyPrefix("news").keyName("user2").exceptionInsert(500L).fpp(0.001);
        redisBloomFilter.add(addCondition,"推送1");
        userTicketMapper.insert(new UserTicket().setCreateTime(LocalDateTime.now()).setTicketId(1L).setUserId(2L));
        int i = 1 / 0;

    }

    @Transactional(rollbackFor = Exception.class)
    public void right() {
        AddCondition addCondition = AddCondition.of().keyPrefix("news").keyName("user1").exceptionInsert(500L).fpp(0.001);
        redisBloomFilter.add(addCondition,"推送3");
        userTicketMapper.insert(new UserTicket().setCreateTime(LocalDateTime.now()).setTicketId(1L).setUserId(2L));

    }
}

访问两个接口查看redis、mysql的结果

 

确实只有一个成功的,即user1有值(enableRedisAux的事务默认不开启)

 

限流功能:

目前支持三种限流模式——滑动窗口限流、漏斗限流、令牌桶限流

使用方式

在接口上添加注解,aop会进行拦截并做相应的处理,相关注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@LimiterType(mode = RateLimiter.FUNNEL_LIMITER)
public @interface FunnelLimiter {

    /**
     * 漏斗容量
     * @return
     */
    double capacity();
    /**
     *每秒漏出的速率
     * @return
     */
    double passRate();
    /**
     *时间单位
     * @return
     */
    TimeUnit timeUnit() default TimeUnit.SECONDS;
    /**
     *每次请求所需加的水量
     * @return
     */
    double addWater();

    Class failStrategy() default FailStrategy.DefaultStrategy.class;

    String msg() default "";



}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@LimiterType(mode = RateLimiter.TOKEN_LIMITER)
public @interface TokenLimiter {

    /**
     * 令牌桶容量
     * @return
     */
    double capacity();

    /**
     * 令牌生成速率
     * @return
     */
    double rate();

    /**
     * 速率时间单位,默认秒
     * @return
     */
    TimeUnit rateUnit() default TimeUnit.SECONDS;

    /**
     * 每次请求所需要的令牌数
     * @return
     */
    double need();

    /**
     * 是否阻塞等待
     * @return
     */
    boolean isAbort() default false;

    /**
     * 阻塞超时时间
     * @return
     */
    int timeout() default -1;

    /**
     * 单位,默认毫秒
     * @return
     */
    TimeUnit timeoutUnit() default TimeUnit.MILLISECONDS;

    Class failStrategy() default FailStrategy.DefaultStrategy.class;

    String msg() default "";



}
package com.trendy.util.redis.aux.limiter.annonations;

import com.trendy.util.redis.aux.limiter.core.FailStrategy;
import com.trendy.util.redis.aux.limiter.core.RateLimiter;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * @author: lele
 * @date: 2020/1/2 下午4:11
 */


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@LimiterType(mode = RateLimiter.WINDOW_LIMITER)
public @interface WindowLimiter {
    /**
     * 持续时间,窗口间隔
     * @return
     */
    int during();

    TimeUnit timeUnit() default TimeUnit.SECONDS;

    /**
     * 通过的请求数
     * @return
     */
    long value();

    Class failStrategy() default FailStrategy.DefaultStrategy.class;

    String msg() default "";



}

其中令牌桶限流通过sleep提供阻塞等待功能,但是超时会返回false,而failStrategy可以由用户自定义并指定返回的结果,这里默认返回"too much request",而msg则是会拼接到返回信息里面去,支持spel表达式,失败策略要声明为public,否则无法实例化导致报错

demo:

@RestController
public class TestController {

    @GetMapping("ha")
    @WindowLimiter(during = 10, value = 5)
    public String test() {
        return "hihi1";
    }
    @GetMapping("ha2/{userName}")
    @FunnelLimiter(capacity = 5,passRate = 0.5,addWater = 1,msg = "#userName",failStrategy = TestStragy.class)
    public Result<String> test2(@PathVariable("userName")String userName) {
        return Result.success("ok");
    }
    @GetMapping("ha3")
    @TokenLimiter(capacity = 5,rate = 0.5,need = 1)
    public String test3() {
        return "hihi3";
    }
    @GetMapping("ha4")
    @TokenLimiter(capacity = 1,rate = 0.5,need = 1,isAbort = true,timeout = 2000)
    public String test4() {
        return "hihi4";
    }
    @GetMapping("ha5")
    @TokenLimiter(capacity = 1,rate = 0.5,need = 1,isAbort = true)
    public String test5() {
        return "hihi5";
    }



}
public class TestStragy implements FailStrategy {

        @Override
        public Object handle(String msg) {
           return Result.success(String.format("对不起:%s,挤不进去太多人了",msg));
        }
    }

关于redis布隆过滤器的大致思路:http://blog.csdn.net/weixin_37703281/article/details/103936753

的码云指数为
超过 的项目
加载中

评论(10)

臭水沟
臭水沟
没法动态调整限流值?
1
1016644172 软件作者
因为动态调整可能要加多个限流组的概念并且做相关的页面啥的,暂时还没时间做
1
1016644172 软件作者
后台做了动态配置的,暴露了相关接口,但管理界面估计得抽空再写了
1
1016644172 软件作者
最新的用法请查看软件文档
超级大丁丁
超级大丁丁
Spring boot1.5支持吗
1
1016644172 软件作者
理论上是支持的,我在本地1.5版本也可以跑,如果不能跑的话,可能有依赖冲突
超级大丁丁
超级大丁丁
年后测试下,感谢你的辛勤付出
1
1016644172 软件作者
哈哈,兴趣而已,疫情严重,勤洗手,出门记得戴口罩
lemos
lemos
开发语言?
1
1016644172 软件作者
肯定是java。。只是之前编辑漏掉了

暂无资讯

暂无问答

centos7 安装 redis

centos7 安装 redis CENTOS7下安装REDIS and 一、安装redis 1、下载redis安装包 wget http://download.redis.io/releases/redis-5.0.6.tar.gz 2、解压压缩包 tar -zxvf redis-5.0.6.tar.gz 3...

2019/10/01 21:40
124
0
Ubuntu 安装 Redis (非源码Build方式)

安装redis : apt-get install redis-server # 安装完会自动自动 使用命令 ps -aux|grep redis 查看是否启动 ---------------------------------- redis 服务操作方式 /etc/init.d/redis-serv...

2018/07/18 10:36
46
0
Ubuntu 14.04下安装和配置redis数据库

工具/原料 Ubuntu 系统电脑一台 网络 方法/步骤 以root权限登录,切换到/usr目录下. 接下来输入命令,apt-get install redis-server,如图: 安装完成后,Redis服务器会自动启动,我们检查Red...

2015/09/15 15:00
808
0
centos7安装redis

1. 安装依赖 yum install gcc 2. 下载安装包 wget http://download.redis.io/releases/redis-5.0.7.tar.gz 3. 解压 tar xzf redis-5.0.7.tar.gz 4. 进入redis解压目录并编译 > cd redis-5.0...

2019/11/26 00:08
72
0
redis_3.0.7_sds.c_sdsull2str()

# 源代码 ~~~ int sdsull2str(char *s, unsigned long long v) { char *p, aux; size_t l; /* Generate the string representation, this method produces * an reversed string. */ p = s; ...

2018/02/07 14:34
37
0
linux命令杂记

linux命令杂记

2014/01/20 15:55
446
0
Redis简单数据恢复

本文只考虑APPEND ONLY MODE关闭的数据备份恢复问题,即在配置文件中appendonly no。 Redis的默认配置中关于备份快照SNAPSHOT的规则是: save 900 1 save 300 10 save 60 10000 含义是,比如...

2015/07/01 15:48
51
0

没有更多内容

加载失败,请刷新页面

返回顶部
顶部

页面底部区域 foot.htm