你知道JDK的延迟队列吗?
最近,在搞redis的时候,有个问题让人头大:redis过期数据内存占用过大,没有及时清理(redis觉得内存还没大到影响命令执行速度的时候,是不会触发大批量清理的),因此内存已经大到13G了。
但是我们可以不借助redis清除策略去清理,去访问每一个过期的key,先通过scan来安全扫描redis的key,再ttl检测key是否过期,过期数据删除,这样就能清楚redis的过期key内存,保证redis的安全运行。
为了保证key的del速度均匀,不影响线上业务。这里借助延迟队列来实现:DelayQueue
将每次扫描得到的过期key放入到延迟队列的item中,并随机设置一个大范围内将来的删除时间(保证时间点分布均匀)。
开启另外一个单线程池来执行删除item中的key
DelayQueue的Item类
延迟元素类需要实现Delaye接口,覆盖compareTo,getDelay方法。这样的元素类对象才会被延迟队列识别并处理。
class Item implements Delayed ,Runnable{
/* 触发时间*/
private long time;
String name;
public Item(String name, long time, TimeUnit unit) {
this.name = name;
this.time = System.currentTimeMillis() + (time > 0? unit.toMillis(time): 0);
}
@Override
public long getDelay(TimeUnit unit) {
return time - System.currentTimeMillis();
}
@Override
public int compareTo(Delayed o) {
Item item = (Item) o;
long diff = this.time - item.time;
if (diff >= 0) {// 改成>=会造成问题
return 1;
}else {
return -1;
}
}
@Override
public String toString() {
return "Item{" +
"time=" + time +
", name='" + name + '\'' +
'}';
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.format("name:{%s}, time:{%s}\n",this.name, LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));
}
}
测试模块
public class DelayedQueneTest {
static ExecutorService executor = Executors.newSingleThreadExecutor();
public static void main(String[] args) throws InterruptedException {
Item item1 = new Item("item1", 5, TimeUnit.SECONDS);
Item item2 = new Item("item2",10, TimeUnit.SECONDS);
Item item3 = new Item("item3",15, TimeUnit.SECONDS);
DelayQueue<Item> queue = new DelayQueue<>();
queue.put(item1);
queue.put(item2);
queue.put(item3);
System.out.println("begin time:" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
System.out.println("2323".split(",")[0]);
executor.submit(queue.take());
executor.submit(queue.take());
executor.submit(queue.take());
// for (int i = 0; i < 3; i++) {
// Item take = queue.take();
// System.out.format("name:{%s}, time:{%s}\n",take.name, LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));
// }
}
}
好的,今天延迟队列的分享就到这里了,大家可以实现下redis过期key清理的方案。
正文到此结束