redis实现分布式延迟队列

主要内容:

1. 使用redis实现分布式延迟队列(redis2.9 版本),用redis锁

2. 使用zookeeper分布式锁优化延迟队列读取

3. 使用延迟队列强制释放过期的zookeeper锁

 

用到的依赖:

spring框架

 

redis: 

redis.clients:jedis:2.9.0

 

zookeeper&curator: 

org.apache.zookeeper:zookeeper:3.4.6

org.apache.curator:curator-framework:2.12.0

org.apache.curator:curator-recipes:2.12.0

 

一. 使用redis实现分布式延迟队列

使用redis的zset功能作为延迟队列,使用时间戳unix timestamp作为score,取的时候取超过当前时间的score。

redis为2.9版本,我翻破了参考文档也没有找到一个可以原子性删除+取回zset某范围内一定数量的值的方法(头很痛),所以只能用锁来控制这个zset的访问,如果有什么好办法请告诉我。

因为可能有很多值在同一时间被取出,如果一次取出zset某时间段内所有值会造成单台机器压力过大,需要限制每次取出的最大量。

下面是一个延迟队列的例子,时间单位全部是毫秒。

import com.study.javaweb.test1.utils.JsonUtils;
import com.study.javaweb.test1.utils.StringUtils;
import com.study.javaweb.test1.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Tuple;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @Author: longjuanfeng
 * @Date: 8/13/18
 * @Description:
 */
@Component
@Slf4j
public class RedisDelayQueue {
    @Autowired
    private Jedis jedis;

    private final String delayQueuePrefix = "d_q_p:";

    private final String delayQueueLock = "d_q_l:";

    public void push(String name, Map<?, Long> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }
        String key = delayQueuePrefix + name;
        Pipeline pipeline = jedis.pipelined();
        dataList.forEach((data, delay) -> {
            if (data == null || delay == null) {
                return;
            }
            //JsonUtils把类转化为json string存储在redis
            pipeline.zadd(key, System.currentTimeMillis() + delay, JsonUtils.toJson(data));
        });
        pipeline.sync();
    }

    public <T> Map<T, Long> poll(String name, Long timeout, Integer count, Class<T> clazz) {
        String queueLock = delayQueueLock + name;
        Long waitTime = 0L;
        while (waitTime < timeout) {
            String result = jedis.set(queueLock, "1", "NX", "EX", 2000);
            if (StringUtils.isEmpty(result)) {
                TimeUtils.sleep(50L);
                waitTime += 50;
            } else {
                break;
            }
        }
        if (waitTime >= timeout) {
            return null;
        }
        try {
            String key = de
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值