離線資料推送問題(訊息佇列)

程式設計一生發表於2017-04-07

  每天晚上9點多我要起身下班的時候,抬眼看到周圍還在公司的也就只有幾個剛畢業的小鮮肉了,就感覺自己也好年輕啊。雖然不止感覺,其實本來也不老。但是轉眼又一想,我晚飯都不吃,每天多比人家工作了好幾個小時,但是水平的提高一點也不成正比啊,是不是方法不當啊。唯一成正比的,我確實把身體鍛鍊好了,騎自行車40公里來上班,中間不停,騎得飛快,整個路程總體還是往高處走的,到公司休息一下正常上班,一點兒感覺都沒有。有一種無知叫做不知道什麼事情是不可能的,想到就去做了。

  直到中午和我們同事90後MM去吃飯,她最近想在網上做些小生意。我才想到:女孩子最大的劣勢在於專注。朋友圈裡好多有正式工作的女孩在弄微商,我卻沒見過一個技術特別好的男同事在弄副業的。我可以同時做很多的事情,確實所有的事情都沒有做深入到極致。人所能達到的境界不是和付出的時間成正比,而是和對自己的要求成正比。人的優秀程度是和野心成正比的。我的知足常樂的心,在生活中是件好事,但是工作中卻是自己最大的挑戰了。和之間同事聊天,他說每天進步一點點就好。我說如果我現在每天只是進步一點點,那麼以後的進步就更慢了。這幾年中沒有一個質的飛越,過幾年就更難衝破前進的壁壘,最後是自己以為自己在進步,別人看你只是原地打轉。

  今天發生的問題:訊息佇列報錯,實時訊息沒有傳送成功,重啟後問題消失。

 

繼續看其他的錯誤日誌:

訊息佇列採用公司統一的apache qpidd叢集。報錯的lesocms.video.guoguang.queue這個消費佇列。問題很清楚,生產者在我這邊,消費者在搜尋部門。生產的東西消費者沒被消費掉,佇列積壓了。消費的問題不管是他們消費程式掛了還是消費慢,都已經交給搜尋部門去處理了,我這邊要解決遇到這種問題怎麼處理。

  問題1:佇列滿了之後嘗試了幾次後close,只能靠人工重啟重置連線的問題

  解決方法: 找到幾個關鍵的異常點

Caused by: org.apache.qpid.transport.SessionException: timed out waiting for sync: complete = -1, point = 0

Exception when sending message:timed out waiting for sync: complete = -1, point = 0

Caused by: org.apache.qpid.transport.SessionClosedException: session closed

Caused by: javax.jms.JMSException: Exception when sending message:session closed

異常剛開始的日誌:

定位到剛開始異常的行:

找到異常前後的日誌:

發現越往後的日誌裡,新增大量的 create class:com.letv.mms.transmission.task.sub.SwiftSendMsgTask

我專門查了一下 create class:com.letv.mms.transmission.task.sub.SwiftSendMsgTask的新建數量:

 出問題的這天不斷的新建,正常穩定的時候是沒有新加的。SwiftSendMsgTask是我當初自己設計的一個物件連線池,目的在於如果訊息的傳送和正常向訊息佇列裡組裝訊息是同步的,會造成第一實行性不能保證,因為有的專輯下面有幾萬個視訊,必須組裝成一個訊息傳送,這個訊息組裝就要好幾分鐘。第二,組裝過程中資料庫連線池等待時間過長會自動關閉。所以我就直接非同步發訊息,從物件連線池中取出一個處理髮訊息的處理物件扔進去,直接處理下一個。如果處理訊息的空閒物件不夠用我就直接新建一個放到連線池裡。一直想好好總結一下離線資料的程式,因為這個程式整個架構基本上很原始,資源的排程分配都是程式自己控制的,基本沒用什麼現成的技術。細節處處處體現精巧,每個設計都解決了特定的問題,但是總體去說這個程式,我卻很難把這個程式的獨到之處用語言表達出來。言歸正傳:

記得有次開會,組裡誰說線上出了什麼什麼問題,不過倒是沒有異常。我不負責那個專案具體不知道,我只是笑著說:“那可能不是真的沒有異常,而是異常日誌沒打好哦。”經常發現自己這句話說的很有道理。上面異常日誌截圖裡面都把.cpp檔案的異常都列印出來了,完全可以按圖索驥。但是自己就是個寫程式碼的自己知道,異常的說明文字未必準確,最好還是要查原始碼。查BasicMessageProducer的原始碼發現,首先這個session是AMQSession。那麼它close了,為什麼使用到的時候沒新建?org.springframework.jms.connection.CachingConnectionFactory的原始碼裡看到reconnectOnException預設是true,也就是說丟擲了這個Jms異常理論上是會新建的,除非新建不成功,不成功是因為SwiftSendMsgTask的新建數量太多,超過了設定的<property name="sessionCacheSize" value="700"></property>。那麼我要解決的就是SwiftSendMsgTask在異常後不要新建那麼多的問題了。

  將原有的一個物件池分成兩個,一個是無限制的物件池,使用時即建立。因為這個離線服務半夜有個跑全量的,我會起1000多個執行緒來跑,但是每次處理資料的執行緒池是50,因為這個環節要涉及大量CPU計算資料庫連線,雖然是高配物理機,而且資料庫是專門將線上資料實時複製的一個從庫,專門使用(執行緒數不大於100的時候效率高)。但是是24核CPU,計算量大,執行緒數大於50會有CPU跑滿的風險。但是每個執行緒會生成獨立的資料檔案,然後進行gz壓縮。gz壓縮很耗時,但是消耗的IO資源,釋放了CPU,平時的時候跑全量時會存在600多個同時在壓縮,所以對這個的物件池無限制。他們問我:為啥你的程式執行的那麼快,我的數量小,反而慢了那麼多?因為你拷貝完我那一版之後我改了程式碼[哭笑], 我把很多執行緒中不需要返回結果的,和大迴圈中的項都扔到另外的執行緒池裡去啦。

  發訊息的單獨放到一個有限制的執行緒池裡去管理。本來cacheSize是700,但是發現正常情況下就算資料量突增,100個都不解決問題的話(其實正常情況下會5個負責發訊息的,因為訊息體最大是4M,發訊息是很快的,非同步的,扔到exchange中即可,實時也沒有什麼併發量),媒資程式那邊就掛了,異常不會到達這邊,折中一下資源,將cacheSize設定為100。程式中建立物件的時候,如果物件池的activeNum個數超過或者等於91個(因為最多會有8個sleeping的),則不會再新建。配了日誌報警,到達40個系統會給我發報警郵件。

  問題2:為什麼資料量會突增

  答案:諮詢了一下德偉:最近接了一批短視訊。實時的量發生了劇增。所以消費的能力突然不夠也是正常的。目前消費者有兩個:一個專輯的,一個視訊的。但是生產者只有一個,如果專輯或者視訊一個發生了突增,會影響到另一個。另外,專輯有的訊息體特別大,極端情況下,一個佇列也就是能放100多個訊息。所以決定將專輯和視訊分開,已經和搜尋部門的同事達成協議。並提醒他們將佇列承載量採用最高配(500M)。因為發現他們那邊現在不是這麼做的[汗]。

  問題3:沒有收到訊息佇列溢位的報警

  答案:諮詢了管MQ叢集的同事,報警沒加上[汗]。
   

  相信問題解決到這個程度,下次再遇到這種問題,搜尋的哥哥們下次就不會第一時間來找我了。下次溝通估計就是我出差回來給他們帶吃噠[勝利][勝利]

 如需轉載,請註上我的原文連結: http://www.cnblogs.com/xiexj/p/6677694.html  謝謝哦~~

相關文章