線上消息堆積與感想
環(huán)境介紹
1.應(yīng)用服務(wù)器部署在阿里云
2.消息中間件使用阿里云RocketMQ
前兩天線上發(fā)生了MQ消息堆積的情況,在我的知識(shí)認(rèn)知里,消息堆積的原因是消費(fèi)者消費(fèi)能力差,無法及時(shí)消費(fèi)消息,才會(huì)導(dǎo)致消息堆積.
那么有哪些因素會(huì)導(dǎo)致消費(fèi)者消費(fèi)能力差呢? 我目前的理解有三種情況
因素
1:Dubbo的RPC調(diào)用時(shí)間太久
2:查詢數(shù)據(jù)庫或者插入數(shù)據(jù)太久
3:業(yè)務(wù)中還有其他耗時(shí)操作,比如發(fā)送郵件
記得以前看博客的時(shí)候,似乎看到過說發(fā)送郵件耗時(shí)久導(dǎo)致消息堆積的情況, 而現(xiàn)在就發(fā)生在自己身上,真是冥冥之中自有安排.
發(fā)生消息堆積,查看阿里云上的線程堆棧信息,如下

從線程堆棧上來看,線程在發(fā)送郵件,準(zhǔn)確說在連接. 根據(jù)代碼分析以及一段時(shí)間的觀察線程,斷定就是發(fā)送郵件的邏輯導(dǎo)致的.臨時(shí)注釋掉這段代碼,重新發(fā)布,問題解決.
其實(shí)發(fā)送郵件并不會(huì)耗時(shí)太久, 而根據(jù)阿里云ARMS上的錯(cuò)誤顯示,消息消費(fèi)失敗總耗時(shí)2min. 為什么發(fā)送郵件(準(zhǔn)確說是連接)會(huì)這么久. 因?yàn)槟嵌伟l(fā)送郵件的代碼在本地測試,只耗時(shí)1s左右.
<dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4</version></dependency>
import javax.mail.Authenticator;import javax.mail.BodyPart;import javax.mail.Message;import javax.mail.Message.RecipientType;import javax.mail.MessagingException;import javax.mail.Multipart;import javax.mail.PasswordAuthentication;import javax.mail.Session;import javax.mail.Transport;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeBodyPart;import javax.mail.internet.MimeMessage;import javax.mail.internet.MimeMultipart;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.Properties;public static void main(String[] args) {long start = System.currentTimeMillis();try {// 配置僅為了文章說明,并不是真實(shí)配置Mail mail = new Mail("[email protected]", "password");mail.addToAddress(Mail.ReceiveType.TO, "[email protected]");mail.setMailInfo(Mail.Mode.TEXT_MAIL, "這是測試數(shù)據(jù)", "這是測試數(shù)據(jù)");mail.send();} catch (Throwable e) {System.out.println(e.getMessage());}long end = System.currentTimeMillis();System.out.println(end - start);}
我把上面的代碼在線上機(jī)器測試,發(fā)現(xiàn)耗時(shí)的確在2min. 為了描述, 我這里以我自己的阿里云服務(wù)器做演示.

測試了兩次,耗時(shí)都在1min.
接下來通過strace命令查看系統(tǒng)調(diào)用, 看下具體耗時(shí)在哪個(gè)系統(tǒng)調(diào)用上.
關(guān)于如何使用strace命令查看系統(tǒng)調(diào)用,在我之前的文章中也有過一些介紹

郵件發(fā)送默認(rèn)使用25號端口,搜索下關(guān)鍵字25
grep -iE 'connect.*25' strace*

在連接郵件服務(wù)器25號端口的時(shí)候,超時(shí)了.
為什么本地耗時(shí)1s, 而在阿里云上的機(jī)器就耗時(shí)這么久呢? 原因只要一個(gè)

阿里云默認(rèn)禁用了25號端口,所以導(dǎo)致連接超時(shí).
在本次事件中,還發(fā)現(xiàn)一個(gè)情況

消息已經(jīng)消費(fèi)成功,可是MQ Broker依然投遞消息. 簡單咨詢了阿里云客服,也沒給我個(gè)具體原因.
●常見消費(fèi)者消費(fèi)慢的因素有哪些?
●消費(fèi)慢的時(shí)候,要查看下線程堆棧,觀察線程都在干啥
●你會(huì)使用strace命令查看系統(tǒng)調(diào)用嗎?

如上圖,目前給我的感覺,作為一個(gè)Java碼農(nóng)或者工程師,系統(tǒng)上應(yīng)該要對以上四個(gè)都要熟悉.
你不僅要會(huì)使用Java層面的Map,Thread,AQS等等, 當(dāng)它調(diào)用到native方法時(shí)候,你還要去JVM層面追蹤查看具體的實(shí)現(xiàn),JVM層面可是C或者C++語言. 還有它最終調(diào)用到的系統(tǒng)調(diào)用是哪個(gè). 而絕大多數(shù)人都停留在Java層面,當(dāng)然這個(gè)層面達(dá)到精通也很難. 了解JVM的更少了, 能夠繼續(xù)向下了解C和Linux的那就鳳毛麟角了.
你掌握的技術(shù),一個(gè)剛畢業(yè)的學(xué)生在2個(gè)月或者半年就掌握了,但是別人掌握的知識(shí),你未必在1-2年能掌握. 這或許就是人與人之間的區(qū)別. 你是哪種人呢?
