一、技术
- spring-boot
- redission
二、实现
在发送邮件过程中,先校验,当前key中值的数量,如果超过配置的数量,则切换,每次发送成功则向redis中的sort_set新增一个值
代码实现
public void add(String key) {
RSetCache<Long> set = redissonClient.getSetCache(key);// 根据key查找sort_set,如果存在则获取,不存在则新增
Random random = new Random();
set.add(new Date().getTime() + random.nextInt(100), expire, TimeUnit.HOURS);//向sort_set添加记录,并且设置超时时间为expire个小时
set.expire(expire, TimeUnit.HOURS);//设置当前key的超时时间
}
RSetCache<String> set = redissonClient.getSetCache(key);
if (set.size() < upperLimit) {
return;
}
三、原理
项目启动初始化RedissonClient过程时
public RedissionClient createRedissionClient(){
Config config = new Config();
config.useSentinelServers()
.setMasterName(masterName)
.addSentinelAddress(address)
.setConnectTimeout(30000)
.setTimeout(10000)
.setRetryAttempts(5)
.setRetryInterval(3000);
s = Redisson.create(config); //1
}
会先创建Redission对象
public static RedissonClient create(Config config) {
Redisson redisson = new Redisson(config);
if (config.isReferenceEnabled()) {
redisson.enableRedissonReferenceSupport();
}
return redisson;
}
Redission初始化过程时
protected Redisson(Config config) {
this.config = config;
Config configCopy = new Config(config);
connectionManager = ConfigSupport.createConnectionManager(configCopy);//连接redis
evictionScheduler = new EvictionScheduler(connectionManager.getCommandExecutor());//创建定时器
writeBehindService = new WriteBehindService(connectionManager.getCommandExecutor());
}
当我们调用redissonClient.getSetCache时
@Override
public <V> RSetCache<V> getSetCache(String name) {
return new RedissonSetCache<V>(evictionScheduler, connectionManager.getCommandExecutor(), name, this);
}
创建RedissonSetCache对象
public RedissonSetCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) {
super(commandExecutor, name);
if (evictionScheduler != null) { //判断定时器是不是为空
evictionScheduler.schedule(getName(), 0);//如果不为空则执行
}
this.evictionScheduler = evictionScheduler;
this.redisson = redisson;
}
org.redisson.eviction.EvictionScheduler#schedule(java.lang.String, long)
public void schedule(String name, long shiftInMilliseconds) {
EvictionTask task = new ScoredSetEvictionTask(name, executor, shiftInMilliseconds);
EvictionTask prevTask = tasks.putIfAbsent(name, task); // 添加到任务池中
if (prevTask == null) {//如果不存在,则第一次执行下任务
task.schedule();
}
}
org.redisson.eviction.EvictionTask#schedule,每5秒执行一次。
public void schedule() {
scheduledFuture = executor.getConnectionManager().getGroup().schedule(this, delay, TimeUnit.SECONDS);//设置定时器 5秒执行1次
}
定时器会执行org.redisson.eviction.ScoredSetEvictionTask#execute方法,删除score >0 and score < 当前时间戳的数据
@Override
RFuture<Integer> execute() {
return executor.writeAsync(name, LongCodec.INSTANCE, RedisCommands.ZREMRANGEBYSCORE, name, 0, System.currentTimeMillis() - shiftInMilliseconds);
}
总结:Reidssion是通过定时器定时删除sort_set中过期的value,其中插入的时候,score为当前时间戳 + 过期时间,所以vaule的score都是为未来的时间。