<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:淘寶七天自動確認收貨,可以怎么實現(xiàn)?

          共 3821字,需瀏覽 8分鐘

           ·

          2022-05-11 09:01

          前常見的應用軟件都有消息的延遲推送的影子,應用也極為廣泛,例如:
          • 淘寶七天自動確認收貨。在我們簽收商品后,物流系統(tǒng)會在七天后延時發(fā)送一個個消息給支付系統(tǒng),通知支付系統(tǒng)將款打給商家,這個過程持續(xù)七天,就是使用用了消息中間件的延遲推送功能。
          • 12306 購票支付確認頁面。我們在選好票點擊確定跳轉(zhuǎn)的頁面中往往都會有倒計時,代表著 30 分鐘內(nèi)訂單不確認的話將會自動取消訂單。其實在下訂單那一可刻開始購票業(yè)務系統(tǒng)就會發(fā)送一個延時消息給訂單系統(tǒng),延時30分鐘,告訴訂蛋單系統(tǒng)訂單未完成,如果在30分鐘內(nèi)完成了訂單,則可以通過邏輯代碼判斷來忽忽略掉收到的消息。
          在上面兩種場景中,如果使用下面兩種傳統(tǒng)解決方案無疑大大降低了系統(tǒng)的整體性能和吞吐量:
          • 使用redis 給訂單設(shè)置過期時間,最后通過判斷 redis 中是否還有該訂單來決定訂訂單是否已經(jīng)完成。這種解決方案相較于消息的延遲推送性能較低,因為redis 都是存儲于內(nèi)存中,當遇到惡意下單或者刷單的將會給內(nèi)存帶來巨大壓力。
          • 使用傳統(tǒng)的數(shù)據(jù)庫輪詢來判斷數(shù)據(jù)庫表中訂單的狀態(tài),這無疑增加了IO次數(shù),性性能極低。
          • 使用jvm原生的DelayQueue ,也是大量占用內(nèi)存,而且沒有持久化策略,系統(tǒng)統(tǒng)宕機或者重啟都會丟失訂單信息。

          ?

          ?1?
          消息延遲推送的實現(xiàn)

          在RabbitMQ 3.6.x 之前我們一般采用死信隊列+TTL過期時間來實現(xiàn)延遲隊列,這里不做過多介紹。

          在 RabbitMQ 3.6.x 開始,RabbitMQ 官方提供了延遲隊列的插件,可以下載放置到 RabbitMQ 根目錄下的 plugins 下。


          首先創(chuàng)建交換機和消息隊列,application.properties 中配置與上一篇文章相同。

          import?org.springframework.amqp.core.*;
          import?org.springframework.context.annotation.Bean;
          import?org.springframework.context.annotation.Configuration;

          import?java.util.HashMap;
          import?java.util.Map;

          @Configuration
          public?class?MQConfig?{

          ????public?static?final?String?LAZY_EXCHANGE?=?"Ex.LazyExchange";
          ????public?static?final?String?LAZY_QUEUE?=?"MQ.LazyQueue";
          ????public?static?final?String?LAZY_KEY?=?"lazy.#";

          ????@Bean
          ????public?TopicExchange?lazyExchange(){
          ????????//Map?pros?=?new?HashMap<>();
          ????????//設(shè)置交換機支持延遲消息推送
          ????????//pros.put("x-delayed-message",?"topic");
          ????????TopicExchange?exchange?=?new?TopicExchange(LAZY_EXCHANGE,?true,?false,?pros);
          ????????exchange.setDelayed(true);
          ????????return?exchange;
          ????}

          ????@Bean
          ????public?Queue?lazyQueue(){
          ????????return?new?Queue(LAZY_QUEUE,?true);
          ????}

          ????@Bean
          ????public?Binding?lazyBinding(){
          ????????return?BindingBuilder.bind(lazyQueue()).to(lazyExchange()).with(LAZY_KEY);
          ????}
          }

          在Exchange的聲明中可以設(shè)置exchange.setDelayed(true)來開啟延遲隊列,也可以設(shè)置為以下內(nèi)容傳入交換機聲明的方法中,因為第一種方式的底層就是通過這種方式來實現(xiàn)的。

          //Map?pros?=?new?HashMap<>();
          /設(shè)置交換機支持延遲消息推送
          ?//pros.put("x-delayed-message",?"topic");
          ?TopicExchange?exchange?=?new?TopicExchange(LAZY_EXCHANGE,?true,?false,?pros);

          發(fā)送消息時需要指定延遲推送的時間,這里在方法中傳入?yún)?shù)?new MessagePostProcessor()?是為了獲得?Message對象,因為需要借助?Message對象的api 來設(shè)置延遲時間。

          import?com.anqi.mq.config.MQConfig;
          import?org.springframework.amqp.AmqpException;
          import?org.springframework.amqp.core.Message;
          import?org.springframework.amqp.core.MessageDeliveryMode;
          import?org.springframework.amqp.core.MessagePostProcessor;
          import?org.springframework.amqp.rabbit.connection.CorrelationData;
          import?org.springframework.amqp.rabbit.core.RabbitTemplate;
          import?org.springframework.beans.factory.annotation.Autowired;
          import?org.springframework.stereotype.Component;

          import?java.util.Date;

          @Component
          public?class?MQSender?{

          ????@Autowired
          ????private?RabbitTemplate?rabbitTemplate;

          ????//confirmCallback?returnCallback?代碼省略,請參照上一篇

          ????public?void?sendLazy(Object?message){
          ????????rabbitTemplate.setMandatory(true);
          ????????rabbitTemplate.setConfirmCallback(confirmCallback);
          ????????rabbitTemplate.setReturnCallback(returnCallback);
          ????????//id?+?時間戳?全局唯一
          ????????CorrelationData?correlationData?=?new?CorrelationData("12345678909"+new?Date());

          ????????//發(fā)送消息時指定?header?延遲時間
          ????????rabbitTemplate.convertAndSend(MQConfig.LAZY_EXCHANGE,?"lazy.boot",?message,
          ????????????????new?MessagePostProcessor()?{
          ????????????@Override
          ????????????public?Message?postProcessMessage(Message?message)?throws?AmqpException?{
          ????????????????//設(shè)置消息持久化
          ????????????????message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
          ????????????????//message.getMessageProperties().setHeader("x-delay",?"6000");
          ????????????????message.getMessageProperties().setDelay(6000);
          ????????????????return?message;
          ????????????}
          ????????},?correlationData);
          ????}
          }

          觀察?setDelay(Integer i)底層代碼,也是在header中設(shè)置x-delay。等同于手動設(shè)置header message.getMessageProperties().setHeader("x-delay", "6000");

          /**
          ?*?Set?the?x-delay?header.
          ?*?@param?delay?the?delay.
          ?*?@since?1.6
          ?*/

          public?void?setDelay(Integer?delay)?{
          ????if?(delay?==?null?||?delay?0
          )?{
          ????????this.headers.remove(X_DELAY);
          ????}
          ????else?{
          ????????this.headers.put(X_DELAY,?delay);
          ????}
          }


          ?2?
          消費端進行消費

          import?com.rabbitmq.client.Channel;
          import?org.springframework.amqp.rabbit.annotation.*;
          import?org.springframework.amqp.support.AmqpHeaders;
          import?org.springframework.stereotype.Component;

          import?java.io.IOException;
          import?java.util.Map;

          @Component
          public?class?MQReceiver?{

          ????@RabbitListener(queues?=?"MQ.LazyQueue")
          ????@RabbitHandler
          ????public?void?onLazyMessage(Message?msg,?Channel?channel)?throws?IOException{
          ????????long?deliveryTag?=?msg.getMessageProperties().getDeliveryTag();
          ????????channel.basicAck(deliveryTag,?true);
          ????????System.out.println("lazy?receive?"?+?new?String(msg.getBody()));

          ????}
          ????```

          ##?測試結(jié)果[#](https://www.cnblogs.com/haixiang/p/10966985.html#3724420099)

          ```java
          import?org.junit.Test;
          import?org.junit.runner.RunWith;
          import?org.springframework.beans.factory.annotation.Autowired;
          import?org.springframework.boot.test.context.SpringBootTest;
          import?org.springframework.test.context.junit4.SpringRunner;

          @SpringBootTest
          @RunWith(SpringRunner.class)
          public?class?MQSenderTest?
          {

          ????@Autowired
          ????private?MQSender?mqSender;

          ????@Test
          ????public?void?sendLazy()?throws??Exception?{
          ????????String?msg?=?"hello?spring?boot";

          ????????mqSender.sendLazy(msg?+?":");
          ????}
          }

          果然在 6 秒后收到了消息?lazy receive hello spring boot:

          作者:海向

          來源:https://www.cnblogs.com/haixiang/p/10966985.html

          往期推薦

          終于搞明白Tomcat的構(gòu)成組件,以及是如何運作的了!

          支付系統(tǒng)架構(gòu)設(shè)計詳解

          突發(fā)狀況,數(shù)據(jù)庫表被鎖,抓瞎了?

          使用HTTP Client踩到的一個坑,你一定要避免

          捕獲了一只發(fā)生概率小于萬分之一的Bug



          如果你覺得這篇文章不錯,那么,下篇通常會更好。備注“公眾號”添加微信好友(微信號:zhuan2quan)。

          ▲?按關(guān)注”程序新視界“,洞察技術(shù)內(nèi)幕


          瀏覽 58
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美三级特黄一区 | 欧美永久免费性爱视频 | 大香蕉在线观看成人 | 国产三级三级三级三级看三级 | 操逼视频入口 |