APNS(全稱:Apple Push Notification Service),主要是用於往蘋果設備推送push消息通知!
基本流程:
今天要聊的問題集中在第4個環節,我們自己的服務器往蘋果的消息中心推送通知。
現狀:
歷史原因,push的代碼散落在各個應用中,隨着新消息通道不斷接入,開發、維護成本較高,開始考慮構建push中心,
封裝dubbo接口對外提供服務,對外屏蔽各種差異,將所有的push業務逐步收擾到push中心。
過程漫長,開始接入的是個人業務,每天的調用量不大,服務器還表現正常;
8月底,BI的推送管理後臺開始對接進來併發布上線,由於BI是針對各種營銷活動批量推送的,一次任務少則幾萬,多則上千萬,
此時服務器開始暴露一些問題。
下面開始介紹優化過程:
1)第一次線上問題暴露,現象:短信報警,查看dubbo註冊中心無provider服務,登錄線上機器,load飆高到了40,ps看了jvm進程在,但dubbo日誌裏,服務註冊失敗。
查看gc,一直觸發Full gc,old空間卻釋放不了
解決:重啓集羣。之前的策略是發送過來的數據會封裝到一個線程任務裏,由ThreadPoolExecutor慢慢消化,懷疑一次發送的token過多(一次400),生產速度快於消費速度,導致對象積累。聯繫BI的稀土同學,將一次任務的數量調整爲100,並且每次調用接口後休眠100ms。
2)另外查看了jvm的參數,修改啓動腳本,將原來的堆大小由1G調整爲2G,新生代由原來的300M調整爲1G
-Xms2g -Xmx2g -Xmn1g -XX:+UseParallelOldGC
瞭解BI的機器配置,24核cpu 64G內存,配置很高但只有一臺,採用的是dubbo默認的隨機路由方式,1對多,擔心負載不均衡,
注:線上dubbo註冊中心觀察過,並不是所有的機器同時宕機,而是一個逐步的過程
調整路由策略,改爲輪詢方式:
更多內容可以參考 dubbo的開發手冊
<dubbo:reference id="***" interface="******" loadbalance="roundrobin" />
3)這次持續的時間長了點,不過在任務跑了4個小時後,系統的old區佔用到70%多,開始擔心一會Full GC是否會正常回收。
由於採用的是UseParallelOldGC 並行回收方式(適用於吞吐量大應用類型),不象CMS可以設置空間使用比例主動觸發回收。
但我們可以通過dump內存快照方式手動觸發一次Full GC
jmap -dump:live,format=b,file=heap.bin <pid>
開始安裝mat插件,分析內存快照,具體可參考《MAT使用教程》
發現有大量的SSLSocketImpl實例對象無法回收,整個鏈路佔了heap 50%+
4) 這個問題比較棘手,因爲我們使用的是一個外部開源框架;
只能網上先查查資料,看看有沒有其他人遇到過類似問題;
很不幸沒有找到現成答案,幸運的是在github上找到了源代碼。
https://github.com/fernandospr/javapns-jdk16
不過也只有代碼,並沒有過多文檔介紹,不過這不重要
自己動手,豐衣足食。
分析代碼,發現兩處疑點:
a)NotificationThreads 裏面會根據預傳的線程數量,創建n個線程,每個線程負責往一定數量設備發送消息,主線程爲了收集n個線程的最終發送結果,NotificationThreads繼承了ThreadGroup,並將對象實例傳到每個子線程構造器中,對主線程wait,當所有的子線程執行完畢後,通過notifyAll喚醒所有進程,繼續後面的流程。
貌似沒有什麼明顯問題,但是mat的分析結果ThreadGroup裏面有大量其它線程,擔心會有干擾。決定採用一種更靠譜更安全的方式,通過CountDownLatch來控制。
b)在子任務結束後(無論是正常結束還是非正常結束),在finally裏面進行後續操作,關閉socket連接;
另外 對 countDownLatch數量減1
重新打包並上傳maven倉庫(注意:需要修改pom配置文件)
<dependency>
<groupId>com.github.fernandospr</groupId>
<artifactId>javapns-jdk16</artifactId>
<version>2.3.1-SNAPSHOT</version>
</dependency>
本地運行單元測試,可以成功推送消息
c)線上集羣部署了一臺機器,開始beta測試,運行一個1200W的推送任務
經過258次YGC後,年老代的空間使用率 依然很低,只有2%+
另外觀察S0、S1、E發現,一次YGC後 to交換區基本能滿足存放存活對象,不會有大量對象晉升到old區。
任務跑完後,gc情況,YGC 602次,沒有觸發Full GC
另外性能監控顯示已經發送了800多萬 條消息(注:圖中統計的是接口調用次數,每次接口調用傳100個用戶token),響應時間正常。
總結:
a)線上報警,無論load彪的有多高,又或cpu使用率100%,千萬不要慌,先保留一臺問題機器,其它的機器全部重啓,保證不影響外部使用
b)要從整個鏈路全面分析問題,多和身邊的同事溝通討論,也許會碰撞出靈感。
最後,非常感謝 錯刀、金磚 ,處理過程中,提供了很多幫助!