日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

Springboot實(shí)現(xiàn)Rabbitmq死信隊(duì)列以及延遲隊(duì)列的優(yōu)化

來源: 責(zé)編: 時(shí)間:2023-10-10 18:30:35 275觀看
導(dǎo)讀導(dǎo)入依賴:后續(xù)延遲隊(duì)列優(yōu)化用Springboot整合,先理解死信隊(duì)列<!--RabbitMQ依賴--> <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <ver

導(dǎo)入依賴:

后續(xù)延遲隊(duì)列優(yōu)化用Springboot整合,先理解死信隊(duì)列Gm628資訊網(wǎng)——每日最新資訊28at.com

<!--RabbitMQ依賴-->        <dependency>            <groupId>com.rabbitmq</groupId>            <artifactId>amqp-client</artifactId>            <version>5.12.0</version>        </dependency>

死信隊(duì)列

由于特定原因?qū)е玛?duì)列中的消息不能被消費(fèi),這樣的消息如果沒有后續(xù)處理就可以放入死信隊(duì)列中,例如一個(gè)訂單如果超時(shí)未被支付從而自動失效,就將這個(gè)訂單放到死信隊(duì)列中。(死信隊(duì)列中的消息是可以被消費(fèi)的)Gm628資訊網(wǎng)——每日最新資訊28at.com

Gm628資訊網(wǎng)——每日最新資訊28at.com

死信隊(duì)列產(chǎn)生的原因

消息TTL過期

就是在規(guī)定的時(shí)間內(nèi)消息沒有被消費(fèi),(和延遲隊(duì)列不同,延遲隊(duì)列時(shí)表示到達(dá)時(shí)間消息才可以被消費(fèi))Gm628資訊網(wǎng)——每日最新資訊28at.com

在生產(chǎn)者代碼中設(shè)置消息過期時(shí)間:Gm628資訊網(wǎng)——每日最新資訊28at.com

//生產(chǎn)者發(fā)送消息,將消息設(shè)置為TTL消息        AMQP.BasicProperties properties =                new AMQP.BasicProperties().builder().expiration("10000").build();

修改隊(duì)列參數(shù)argument的特殊屬性:Gm628資訊網(wǎng)——每日最新資訊28at.com

arguments.put("x-dead-letter-exchange", EXCHANGE_DIRECT_DEAD);//死信交換機(jī)arguments.put("x-dead-letter-routing-key", "routingkey_direct-dead");//死信rotingkeyarguments.put("x-message-TTL", 10000);//設(shè)置過期時(shí)間(單位毫秒)  //將死信交換機(jī)與死信隊(duì)列綁定

模擬代碼:

消費(fèi)者1Gm628資訊網(wǎng)——每日最新資訊28at.com

public class Consumer01 {    public static final String EXCHANGE_DIRECT = "exchange_direct";//普通交換機(jī)的名稱    public static final String EXCHANGE_DIRECT_DEAD = "exchange_direct_dead";//死信交換機(jī)的名稱    public static final String QUEUE_PLAIN = "queue_plain";//普通隊(duì)列的名稱    public static final String QUEUE_PLAIN_DEAD = "queue_plain_dead";//死信隊(duì)列的名稱    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {        Channel channel = RabbitMqUtils.createChannel();        //聲明死信交換機(jī)和普通交換機(jī)        channel.exchangeDeclare(EXCHANGE_DIRECT, BuiltinExchangeType.DIRECT);        channel.exchangeDeclare(EXCHANGE_DIRECT_DEAD, BuiltinExchangeType.DIRECT);        //聲明普通隊(duì)列(綁定普通隊(duì)列與死信交換機(jī)的關(guān)系,在通過rotingkey綁定死信隊(duì)列        Map<String, Object> arguments = new HashMap<>();        arguments.put("x-dead-letter-exchange", EXCHANGE_DIRECT_DEAD);//死信交換機(jī)        arguments.put("x-dead-letter-routing-key", "routingkey_direct-dead");//死信rotingkey        //設(shè)置過期時(shí)間(單位毫秒)        arguments.put("x-message-TTL", 10000);        channel.queueDeclare(QUEUE_PLAIN, false, false, false, arguments);        //聲明死信隊(duì)列        channel.queueDeclare(QUEUE_PLAIN_DEAD, false, false, false, null);        //普通交換機(jī)和隊(duì)列的綁定        channel.queueBind(QUEUE_PLAIN, EXCHANGE_DIRECT, "routingkey_direct");        //死信交換機(jī)和死信隊(duì)列的綁定        channel.queueBind(QUEUE_PLAIN_DEAD, EXCHANGE_DIRECT_DEAD, "routingkey_direct-dead");        //模擬超時(shí)時(shí)間消息未被消費(fèi)        Thread.sleep(1000000);        channel.basicConsume(QUEUE_PLAIN, true, (consumerTag, message) -> {            System.out.println("Consumer01.main接受到消息:" + new String(message.getBody()));        }, (consumerTag, sig) -> {        });    }}

生產(chǎn)者Gm628資訊網(wǎng)——每日最新資訊28at.com

public class Produce {    public static void main(String[] args) throws IOException, TimeoutException {        Channel channel = RabbitMqUtils.createChannel();        //生產(chǎn)者發(fā)送消息,將消息設(shè)置為TTL消息        AMQP.BasicProperties properties =                new AMQP.BasicProperties().builder().expiration("10000").build();        for (int i = 0; i < 10; i++) {            String message = i + "";            channel.basicPublish(Consumer01.EXCHANGE_DIRECT,"routingkey_direct",properties,message.getBytes(StandardCharsets.UTF_8));        }    }}

消費(fèi)者2Gm628資訊網(wǎng)——每日最新資訊28at.com

public class Consumer2 {    public static void main(String[] args) throws IOException, TimeoutException {        Channel channel = RabbitMqUtils.createChannel();        channel.basicConsume(Consumer01.QUEUE_PLAIN_DEAD, true, (consumerTag, message) -> {            System.out.println("Consumer2.main接受死信隊(duì)列的消息:" + new String(message.getBody()));        }, (consumerTag, sig) -> {        });    }}/**輸出結(jié)果:Consumer2.main接受死信隊(duì)列的消息:0Consumer2.main接受死信隊(duì)列的消息:1Consumer2.main接受死信隊(duì)列的消息:2Consumer2.main接受死信隊(duì)列的消息:3Consumer2.main接受死信隊(duì)列的消息:4Consumer2.main接受死信隊(duì)列的消息:5Consumer2.main接受死信隊(duì)列的消息:6Consumer2.main接受死信隊(duì)列的消息:7Consumer2.main接受死信隊(duì)列的消息:8Consumer2.main接受死信隊(duì)列的消息:9    */

隊(duì)列達(dá)到了最大長度

將RabbiMQ的隊(duì)列的argument屬性的鍵設(shè)置為 x-max-length 表示隊(duì)列可以容納的最大條數(shù)Gm628資訊網(wǎng)——每日最新資訊28at.com

消息被拒絕

將自動應(yīng)答設(shè)為falseGm628資訊網(wǎng)——每日最新資訊28at.com

在消費(fèi)者調(diào)一個(gè)Channel.basicReject,設(shè)置參數(shù)requeue為false,表示不重新排隊(duì),將消息丟到死信隊(duì)列Gm628資訊網(wǎng)——每日最新資訊28at.com

延遲隊(duì)列優(yōu)化

延遲隊(duì)列就是講一個(gè)消息延遲發(fā)送,例如消息在隊(duì)列中10s后才能被取出,可以通過RabbitMQ的插件或者死信隊(duì)列來實(shí)現(xiàn)Gm628資訊網(wǎng)——每日最新資訊28at.com

用死信隊(duì)列實(shí)現(xiàn)延遲隊(duì)列的思路:Gm628資訊網(wǎng)——每日最新資訊28at.com

在于死信隊(duì)列綁定的普通隊(duì)列不設(shè)置消費(fèi)者,利用TTL延遲消息,當(dāng)TTL時(shí)間過期后,到達(dá)死信隊(duì)列被消費(fèi)這樣就形成一個(gè)延遲隊(duì)列。Gm628資訊網(wǎng)——每日最新資訊28at.com

延遲隊(duì)列的使用場景:①典型的就是流量削峰,對于不重要的消息,可以延遲消費(fèi),有助于減輕數(shù)據(jù)庫的壓力,強(qiáng)化分布式系統(tǒng)的高可用和并發(fā)性能。②還可以實(shí)現(xiàn)一個(gè)消息提醒,例如用戶三天未登錄發(fā)送一個(gè)消息提醒。Gm628資訊網(wǎng)——每日最新資訊28at.com

Gm628資訊網(wǎng)——每日最新資訊28at.com

在實(shí)際生產(chǎn)中可能存在很多不同的延遲時(shí)間要求,不可能每一個(gè)延遲要求就創(chuàng)造一個(gè)隊(duì)列,我們可以用生產(chǎn)者實(shí)現(xiàn)延遲信息,而隊(duì)列不設(shè)置TTL就可以根據(jù)生產(chǎn)的延遲消息進(jìn)行延遲發(fā)送。Gm628資訊網(wǎng)——每日最新資訊28at.com

但是此方法雖然實(shí)現(xiàn)了一個(gè)隊(duì)列就可以轉(zhuǎn)發(fā)不同延時(shí)時(shí)間的消息,但是有缺陷,隊(duì)列中的消息是排隊(duì)發(fā)送的,也就是說如果我第一條消息發(fā)送20s延時(shí),接著第二條消息發(fā)送2s延時(shí)。最后卻是20s消息先消費(fèi),而2s消息后消費(fèi),因?yàn)镽abbitMQ在檢測一條消息時(shí)發(fā)生了20s的阻塞。如下:Gm628資訊網(wǎng)——每日最新資訊28at.com

###GET http://localhost:8080/ttl/sendExpirationMessage/aaaaa/20000###GET http://localhost:8080/ttl/sendExpirationMessage/bbbbb/2000最后輸出結(jié)果是先消費(fèi)aaaa后消費(fèi)bbbb

可以通過RabbitMQ的插件實(shí)現(xiàn)延時(shí)隊(duì)列,此方法沒有這缺陷Gm628資訊網(wǎng)——每日最新資訊28at.com

從官網(wǎng)上下載對應(yīng)版本的延遲插件,下載后如圖:交換機(jī)類型會多出一個(gè) x-delayed-messageGm628資訊網(wǎng)——每日最新資訊28at.com

Gm628資訊網(wǎng)——每日最新資訊28at.com


Gm628資訊網(wǎng)——每日最新資訊28at.com

在我們自定義的交換機(jī)中,這是一種新的交換機(jī)類型,該類型消息支持延遲投遞機(jī)制,消息傳遞后并不會立即投遞到目標(biāo)隊(duì)列中,而是存儲在mnesia(一個(gè)分布式數(shù)據(jù)系統(tǒng))表中,當(dāng)達(dá)到投遞時(shí)間時(shí),才會投遞到目標(biāo)隊(duì)列中。Gm628資訊網(wǎng)——每日最新資訊28at.com

代碼實(shí)例:Gm628資訊網(wǎng)——每日最新資訊28at.com

配置類:Gm628資訊網(wǎng)——每日最新資訊28at.com

@Configurationpublic class RabbitDelayedConfig {    //延遲交換機(jī)    public static final String DELAYED_EXCHANGE = "delayed.exchange";    //延遲隊(duì)列b    public static final String DELAYED_QUEUE = "delayed.queue";    //延遲交換機(jī)和隊(duì)列的routingkey    public static final String DELAYED_ROTINGKEY = "delayed.routingkey";    //public CustomExchange(String name, String type, boolean durable, boolean autoDelete, Map<String, Object> arguments) {    //		super(name, durable, autoDelete, arguments);    //		this.type = type;    //	}    @Bean    public CustomExchange delayedExchange() {        Map<String, Object> arguments = new HashMap<>();        //定義延遲消息類型由那種交換機(jī)規(guī)則處置        arguments.put("x-delayed-type", "direct");        return new CustomExchange(DELAYED_EXCHANGE, "x-delayed-message", false, false, arguments);    }    @Bean    public Queue delayedQueue() {        return QueueBuilder                .nonDurable(DELAYED_QUEUE)                .build();    }    @Bean    public Binding delayedBinding() {        return BindingBuilder.bind(delayedQueue()).to(delayedExchange()).with(DELAYED_ROTINGKEY).noargs();    }}

生產(chǎn)者:Gm628資訊網(wǎng)——每日最新資訊28at.com

/*延遲交換機(jī)發(fā)送消息*/    @GetMapping("/sendDelayedMessage/{message}/{delayedTTL}")    public void sendDelayedMessage(@PathVariable String message, @PathVariable Integer delayedTTL) {        log.info("當(dāng)前時(shí)間:{},發(fā)送一條延遲時(shí)間為{}的延遲消息給延遲隊(duì)列:{}", new Date().toString(), delayedTTL, message);        rabbitTemplate.convertAndSend(RabbitDelayedConfig.DELAYED_EXCHANGE,                RabbitDelayedConfig.DELAYED_ROTINGKEY,                message,                msg -> {                    msg.getMessageProperties().setDelay(delayedTTL);//設(shè)置消息的延遲消息時(shí)間                    return msg;                });    }

消費(fèi)者:Gm628資訊網(wǎng)——每日最新資訊28at.com

@Slf4j@Componentpublic class DelayedQueueConsumer {    @RabbitListener(queues = RabbitDelayedConfig.DELAYED_QUEUE)    public void queue(Message message) {        log.info("接受到延遲隊(duì)列的消息,當(dāng)前時(shí)間:{},消息:{}",new Date().toString(),new String(message.getBody()));    }}

本文鏈接:http://www.www897cc.com/showinfo-26-12687-0.htmlSpringboot實(shí)現(xiàn)Rabbitmq死信隊(duì)列以及延遲隊(duì)列的優(yōu)化

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 福利來啦,一鍵部署:輕松掌握Docker及Docker-Compose的安裝方法

下一篇: 自己動手用Python實(shí)現(xiàn)一個(gè)保衛(wèi)果實(shí)小游戲【完整版】

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 磐石市| 林州市| 利辛县| 苏尼特右旗| 沂南县| 中牟县| 祁东县| 宁河县| 玉龙| 徐水县| 阳江市| 瓦房店市| 密云县| 上栗县| 通渭县| 大安市| 平江县| 桂平市| 台前县| 弥勒县| 镇巴县| 板桥市| 疏勒县| 鲜城| 辛集市| 黑水县| 镇康县| 凤凰县| 齐河县| 民和| 静宁县| 红河县| 庆元县| 霍林郭勒市| 色达县| 淮北市| 安龙县| 江源县| 龙门县| 兴隆县| 华容县|