日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 如何判定消息已在队列_Java面试—消息队列

發布時間:2025/3/20 java 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 如何判定消息已在队列_Java面试—消息队列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

消息隊列面試題

題目來自于中華石杉,解決方案根據自己的思路來總結而得。題目主要如下:

1. 為什么要引入消息隊列?

消息隊列的引入可以解決3個核心問題:

  • 解耦
  • 異步
  • 削峰
  • 解耦
    在一個項目中,如果一個模塊A產生的一個關鍵數據,需要調用其他模塊接口服務;而需要調用的接口很多,又不確定之后是否還需要將數據傳給其他模塊的接口時。這時可以使用消息隊列,使用了消息隊列之后,模塊A不需要在對接各個模塊,而是直接對接消息隊列。這樣一來。當其他的模塊需要這個數據時,也不用再修改A數據,而是去到MQ中訂閱這個Topic。使得模塊A與其他模塊之間耦合度降低。
  • 異步
    在一個項目中,如果模塊A的請求處理需要20ms,而模塊A又依賴了模塊B,模塊C ,模塊D 。在A請求處理結束后,A需要調用
    模塊B,C,D的對應請求處理,這時B請求處理需要100ms,C 需要200ms,D 需要400ms。這樣一來,總體一個請求的總時長為
    20 + 100 + 200 + 400 = 720 ms 遠遠大于模塊A的請求處理時間。另一方面,模塊B 模塊C 模塊D之間 并沒有順序關系。
    這時可以引入消息隊列 ,模塊A在請求處理結束后,將自己的數據發送給消息隊列MQ,由B,C ,D去消息隊列獲取數據,自行處理
    模塊A在處理完成后直接返回給客戶端處理結果,而不需要等待B,C,D處理結束,如此一來,一個請求處理的就只需要計算
    模塊A的處理時間=20ms,大大提高了用戶體驗。
  • 削峰
    如果一個系統只能一秒鐘處理5000個請求(MySQL一般只能2000QPS),而在特殊時期就只要1個小時的時間段內,請求量暴漲,一秒鐘來了1W個請求。從而系統會之間宕機。但這種情況可能在平時不會發生,不需要升級相應的服務器配置。
    問題在于在1小時的時間段,如何把請求從10000QPS 下降到5000QPS 使得系統能夠正常運轉而不發生宕機。
    這時候可以引入消息隊列,假設模塊A負責處理請求,模塊B負責將數據持久化到數據庫。模塊A在接受到請求時,把請求交給消息隊列,由消息隊列來緩解對應的請求壓力,類似于Buffer建立一個緩沖區,模塊B根據自己的請求處理速度去到消息隊列中去消費數據。這樣一來就解決了對應特定時間段的削峰問題。
  • 要結合實際項目來說明:
    體現上述的三個點。
  • 2. MQ有什么缺點?

    任何技術都是一把雙刃劍,在引入消息隊列的同時必定也會伴隨著相應的問題,正如《人月神話》中所說,沒有銀彈。消息隊列的引入會帶來3個核心的問題:

  • 系統可靠性降低
    在引入MQ時,MQ作為了中間層,這就使得模塊與對應的MQ是緊耦合的關系。一旦MQ宕機,下游服務即使正常運行,但整個系統卻無法使用。這個問題的解決方式是 MQ的高可用,使得MQ高可用,不會那么容易宕機達到5個9。
  • 系統復雜度提高
    引入MQ,需要考慮的問題變復雜,隨之而來的問題是
  • 消息丟了怎么辦
  • 重復消費消息問題
  • 消息的順序問題
    這幾個問題都有對應的解決方案。
  • 處理結果的最終一致性問題
    引入MQ會導致處理結果的最終一致性問題,因為模塊A與其他模塊之間解耦,從而模塊A不知道其他模塊的處理結果
    這就導致模塊A以為處理結果OK,但實際上可能模塊B處理結果失敗,這也是異步化所帶來的最終一致性問題。
  • 3. 你都了解過哪些MQ? 他們之間有什么區別嗎?

    這個問題可以延伸為技術選型問題,關于這個問題可以認為憑什么你選擇了這個MQ,而沒有選擇其他MQ。對應可以擴展為spring-security 與shiro 都是安全框架都實現了Oauth2協議,而且shiro是輕量級的,為什么你選擇了Spring-Security這個安全框架這個問題比較考察技術廣度。

    首先我了解過的MQ有:activeMQ,RabbitMQ,RocketMQ,Kafka

    activeMQRabbitMQRocketMQKafka并發量萬級萬級十萬級萬級處理時長毫秒微妙毫秒毫秒開發語言JavaErLangJavaJava Scala功能完備完備完備 且提供了插件與管理界面完備完備常用場景小型項目demo**大數據領域日志處理、實時計算社區活躍度較低高高高

    activeMQ社區活躍度較低,不建議使用。RabbitMQ社區活躍度高,更新版本頻繁,但使用開發語言為ErLang , 當有定制化需求無法進行擴展RocketMQ 阿里出品,但存在著后續項目不更新情況,這就使得企業自行維護相應的功能或者定制化功能Kafka 大數據領域 主要用來進行實時計算,日志采集的消息隊列,功能相比于其他MQ少,但是kafka是大數據領域公認的消息隊列如果對功能有要求,小公司可以選擇RabbitMQ, 有技術團隊的大公司可以使用RocketMQ,大數據生態為了與其他組件配合所以使用Kafka

    4. 如何保證MQ的高可用

  • RabbitMQ的HA
    RabbitMQ的解決方式為=>集群模式 + 鏡像
  • 普通集群模式:queue創建之后,如果沒有其它policy(策略),則queue就會按照普通模式集群。對于Queue來說,消息實體只存在于其中一個節點,A、B兩個節點僅有相同的元數據,即隊列結構,但隊列的元數據僅保存有一份,即創建該隊列的rabbitmq節點(A節點),當A節點宕機,你可以去其B節點查看,./rabbitmqctl list_queues發現該隊列已經丟失,但聲明的exchange還存在。當消息進入A節點的Queue中后,consumer從B節點拉取時,RabbitMQ會臨時在A、B間進行消息傳輸,把A中的消息實體取出并經過B發送給consumer,所以consumer應平均連接每一個節點,從中取消息。該模式存在一個問題就是當A節點故障后,B節點無法取到A節點中還未消費的消息實體。如果做了隊列持久化或消息持久化,那么得等A節點恢復,然后才可被消費,并且在A節點恢復之前其它節點不能再創建A節點已經創建過的持久隊列;如果沒有持久化的話,消息就會失丟。這種模式更適合非持久化隊列。只有該隊列是非持久的,客戶端才能重新連接到集群里的其他節點,并重新創建隊列。假如該隊列是持久化的,那么唯一辦法是將故障節點恢復起來。鏡像集群模式:核心在于:鏡像集群會同步消息該模式解決了上述問題,其實質和普通模式不同之處在于,消息實體會主動在鏡像節點間同步,而不是在consumer取數據時臨時拉取。該模式帶來的副作用也很明顯,除了降低系統性能外,如果鏡像隊列數量過多,加之大量的消息進入,集群內部的網絡帶寬將會被這種同步通訊大大消耗掉。所以在對可靠性要求較高的場合中適用,一個隊列想做成鏡像隊列,需要先設置policy,然后客戶端創建隊列的時候,rabbitmq集群根據“隊列名稱”自動設置是普通集群模式或鏡像隊列。但這不是分布式存儲,而是多節點主備存儲。相比于Kafka的分布式架構會多消耗資源。

  • Kafka實現高可用
  • Kafka的高可用主要是通過Kafka通過把每個Topic中的消息分成多個Partition,每個Partition做一個集群。而每一個Partition內部集群通過選舉得到一個leader,其他是follower,leader復制消息的讀寫,并把消息復制到follower。Kafka在發送消息時,只有當每個partition的follower復制到了消息才確認消息已經被存儲。

    5. 如何保證消息不會丟失?

  • RabbitMQ方式
    1.1 生產者方面
    • 開啟RabbitMQ的事務方式txSelect()。當生產者寫入消息失敗時,采取重試機制。但這個寫入是同步的。
    • 使用confirm方式: 其中confirm也可以使用三種方式:
    • 普通confirm
    • 批量confirm
    • 異步confirm 設置監聽器
    channel.confirmSelect(); //普通confirm if (channel.waitForConfirms()) { System.out.println("消息發送成功" ); } //批量confirm 失敗會報錯 channel.waitForConfirmsOrDie(); //異步監聽confirm channel.addConfirmListener(new ConfirmListener() { @Override public void handleNack(long deliveryTag, boolean multiple) throws IOException { System.out.println("未確認消息,標識:" + deliveryTag); } @Override public void handleAck(long deliveryTag, boolean multiple) throws IOException { System.out.println(String.format("已確認消息,標識:%d,多個消息:%b", deliveryTag, multiple)); }});

    1.2 RabbitMQ方面RabbitMQ在內存緩存消息,當MQ宕機時,會發生消息丟失現象。這一點需要RabbitMQ將消息持久化到硬盤上。減小消息丟失的可能1.3 消費者方面RabbitMQ默認是autoAck=true,這樣就使得消費者在接受到消息時,立馬告知MQ我消費了數據,但還沒有來得及處理。所以需要把autoAck=false,之后當消息處理完成之后手動提交。

    2 kafka方面

  • 生產端
    數據丟失發送在leader向follower同步消息的時候,leader宕機使得消息丟失。
    解決方案是設置4個參數:
  • replication.factor = n > 1 設置partition有多少個副本數
  • kafka咋服務端設置mini.sync.replicas=1 即一個leader至少保證有一個follower存活
  • producer在發送消息時,設置acks=all 設置所有消息必須全部寫入replication后返回成功。
  • retries=Integer.MAX 把重試次數調制最大
  • 消費端
    在消費者端關閉自動確認消息,這樣需要手動確認 保證消息不會丟失。
  • 6. 如何保證消息不會重復消費?

  • 在消費者消費消息時,把對應的唯一值放入HashSet 或者Redis來避免同一條消息消費多次
  • 使用數據庫的唯一鍵約束來報錯處理
  • 7. 如何保證消費者消費消息時消息的順序性?

    消息隊列本身就是為了把多個任務解耦并行化處理,如果要保證消息的順序消息,實際上就是取消并行處理,改成串行處理。

  • RabbitMQ
    將一組消息放入同一個queue,這樣就只會有一個consumer來消費這個queue中的數據,在consumer內部采用隊列的方式來處理順序消息
  • Kafka
    生產者寫消息時,每次寫入一個topic,將partition對應key值修改同一key,這樣消息只會進入一個partition,也只有一個消費者在進行消費,之后也采用內存隊列的方式順序處理消息。
  • 8. 消息隊列積壓太多,目前消費者處理太慢,如何改進?

    目前的消費者難以在短時間內處理這么多條消息,考慮引入多個消費者,但引入這多個消費者只用于消費當前消息,并不是長期使用。假定長期使用的消費者為A、B、C 訂閱的Topic是Order。新申請3 * 10~20 = 30~60個機器 作為新的消費者組GroupNew。 GroupNew 訂閱新的Topic - OrderFast,從這個topic中獲取消息并消費。將原有長期使用的消費者組修改代碼,不處理消息 直接將消息寫入到新的Topic - OrderFast

    9. 消息隊列的機器磁盤快被消息寫滿了怎么辦?

  • 可以采取上述方案,不同的是寫入到另外一臺MQ中,而不是在本機的Topic
  • 下一個消息直接丟棄不處理,到消息隊列機器恢復之后,將生產者與消費者之間通過代碼查詢出對應的缺失部分,再進行補償式操作。
  • 10. 消息隊列消費消息太慢,消息過期失效怎么辦?

  • 生產環境設置消息不過期
  • 如果已經過期失效,那么需要查出過期失效的消息,重新進行補償式操作
  • 總結

    以上是生活随笔為你收集整理的java 如何判定消息已在队列_Java面试—消息队列的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。