對(duì)于MQ消費(fèi)使用redis緩沖限流處理

一、好言

事實(shí)是這樣,假如你不懂我,那錯(cuò)的永遠(yuǎn)是我,不必驚訝,連解釋都是多余。

二、背景

由于消費(fèi)MQ,會(huì)存在有就消費(fèi),可能會(huì)有并發(fā)的存在,在后臺(tái)引起的問題,所以需要多MQ的消費(fèi)做處理 ,然后我們將MQ消息消費(fèi)后,丟進(jìn)redsi,然后從開啟線程,從redis中取數(shù)據(jù)進(jìn)行消費(fèi),下面給出的是set和隊(duì)列的兩種方式。

三、內(nèi)容

3.1 SET的處理方式
 @PostConstruct
public void dealTask() throws Exception {
        ScheduledExecutorService es = Executors.newScheduledThreadPool(100);
        es.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                logger.info("================");
                Long flag = stringRedisTemplate.opsForValue().increment(RedisConstant.TASK_SWITCH_POWER,1);
                if(flag == 1 ){//這個(gè)標(biāo)識(shí)用來(lái)控制集群,每次只有等于1的進(jìn)入,取完數(shù)據(jù)或者沒有數(shù)據(jù)都需要將該
值重新置為0
                    ZSetOperations<String, VO> zSetOperations = objectredisTemplate.opsForZSet();
                    Long count = zSetOperations.size(RedisConstant.NAME_TASK_KEY);
                    if(count > 0){
                        Set<VO> zsetRangeData = zSetOperations.range(RedisConstant.NAME_TASK_KEY,0L, 
count - 1);
                        zSetOperations.remove(RedisConstant.NAME_TASK_KEY, 
zsetRangeData.toArray());
                        stringRedisTemplate.opsForValue().set(RedisConstant.TASK_SWITCH_POWER, "0");
                        Iterator iterable = zsetRangeData.iterator();
                        while (iterable.hasNext()){
                            try {
                               //TODO處理業(yè)務(wù)
                            }catch (Exception e){
                                //出異常在把該信息添加進(jìn)去set
                                zSetOperations.add(RedisConstant.NAME_TASK_KEY, 
ZSetUtil.converToSet(vo));
                            }
                        }
                    }else{
                        stringRedisTemplate.opsForValue().set(RedisConstant.TASK_SWITCH_POWER, "0");
                    }
                }
            }
        },0,1, TimeUnit.SECONDS);
    }

接收端接收消息然后丟入redis,當(dāng)然你可以是指redis大小數(shù)量,超過上限則可以直接丟棄

               ZSetOperations<String, VO> zSet = redisTemplate.opsForZSet();
                if(zSet.size(RedisConstant.NAME_TASK_KEY) + 1  >= 
MAX_CHANNEL_MQ_TASK_SIZE){
                    logger.info("到達(dá)上限,丟棄消息 = "+messgage);
                    return;
                }
                zSet.add(RedisConstant.NAME_TASK_KEY, ZSetUtil.converToSet(messgage));

ZSetUtil.java

   public static Set<ZSetOperations.TypedTuple<VO>> converToSet(VO data){
        Set<ZSetOperations.TypedTuple<VO>> set = new HashSet<>(1);
        ZSetOperations.TypedTuple typedTuple;
        Long score = System.currentTimeMillis();
        typedTuple = new DefaultTypedTuple(data, score.doubleValue());
        set.add(typedTuple);
        return set;
    }
3.2、隊(duì)列方式

隊(duì)列方式先push然后pop出來(lái),每次處理一條數(shù)據(jù)。


消息接收端

 ListOperations listOperations = redisTemplate.opsForList();
 redisTemplate.opsForList().leftPush(RedisConstant.NAME_TASK_KEY,msg);

開啟定時(shí)任務(wù)從redis中取數(shù)據(jù)

    @PostConstruct
    public void dealNameTask(){
     ScheduledExecutorService es = Executors.newScheduledThreadPool(10);
        es.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                ListOperations listOperations = objectredisTemplate.opsForList();
                VO vo = (VO)listOperations.rightPop(RedisConstant.NAME_TASK_KEY);
                try {
                    if(null != vo){
                        //Todo處理業(yè)務(wù)
                    }else{
                        Thread.sleep(1000);
                    }
                }catch (Exception e){
                    //出現(xiàn)異常在push進(jìn)redis
                    listOperations.leftPush(RedisConstant.NAME_TASK_ZSET_KEY,vo);
                }
            }
        },0,1, TimeUnit.SECONDS);
    }

相對(duì)來(lái)說(shuō),push會(huì)簡(jiǎn)單多了,只是set可以排序,并且也可以按照順序來(lái)取。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,933評(píng)論 18 139
  • 1.1 資料 ,最好的入門小冊(cè)子,可以先于一切文檔之前看,免費(fèi)。 作者Antirez的博客,Antirez維護(hù)的R...
    JefferyLcm閱讀 17,110評(píng)論 1 51
  • 本文轉(zhuǎn)載自http://dataunion.org/?p=9307 背景介紹Kafka簡(jiǎn)介Kafka是一種分布式的...
    Bottle丶Fish閱讀 5,491評(píng)論 0 34
  • 背景介紹 Kafka簡(jiǎn)介 Kafka是一種分布式的,基于發(fā)布/訂閱的消息系統(tǒng)。主要設(shè)計(jì)目標(biāo)如下: 以時(shí)間復(fù)雜度為O...
    高廣超閱讀 12,884評(píng)論 8 167
  • 今天的表現(xiàn)有點(diǎn)傻逼了。 1.發(fā)車不及時(shí),沒有按照一輛接一輛發(fā)車出去,導(dǎo)致有客滯留 2.算都算錯(cuò),被人取笑,沒有加上...
    一個(gè)人的獨(dú)行閱讀 164評(píng)論 0 0