Java發送郵件必帶超時時間配置

  • 2019 年 10 月 3 日
  • 筆記

前言

只有光頭才能變強。

文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/ZhongFuCheng3y/3y

在線上遇到了一個發送郵件的問題,記錄一下。

一、先說背景

某一天,小王跟我回饋:「麻煩檢查一下線上郵件的發送情況,我這查出來發送失敗啦」

我去DB查了一下近期的郵件發送情況,表示:「看著都挺正常的,線上沒有異常的情況。可能郵件在redis裡邊堆積了,還沒消費」

select * from email order by id desc limit 100

先來說一下我這邊發郵件的大致實現方式:

处理邮件消息的方式

這樣做有什麼好處?把Redis當做一個消息隊列,把請求全部扔到Redis上,這能削峰。機器A/B/C的執行緒會在一定的間隔內向Redis拉取消息,然後調用郵件介面進行發送。

而我這邊會在頁面上提供一個功能給業務方查詢各類消息是否發送成功,由於發送郵件是一個非同步的操作,而前同事在編寫的時候又追求實時性。

  • 目前的邏輯是:如果push到Redis是成功的,並且Redis裡邊沒有堆積著消息(說明機器A/B/C能及時處理掉這封郵件),那就認為這封郵件發送成功。

PS:(如果系統不存在問題,其實這個實現也是OK的。因為郵件的發送量一般不會太大(Redis不會堆積消息),並且發送郵件的成功率也是挺高的。

回到問題上,由於有上面的一個背景,所以我就猜測:是不是小王在查結果時,這封郵件還堆積在Redis上,所以就直接返回失敗了。果不其然,我去查了一下Redis,還有200封郵件沒消息。

於是我就問小王:「你這發了多少封郵件啊?」小王表示:「20分鐘500封,1qps都不到」。我想了一下:「那我們這有四台機器,按道理是不會堆積那麼多的」。

於是跑去線上伺服器看一下消費的日誌,發現只有一台機器在消費Redis的數據。又去看了一下錯誤的日誌是不是有大量的錯誤資訊,但並沒找到錯誤的日誌...

於是去查了一下機器的監控資訊,也沒發現異樣。那問題就來了:為啥就只有一台機器在消費Redis的消息呢?其他三台機器的日誌和監控資訊都沒異常。

二、解決

從日誌和機器的資訊都判斷不出有什麼問題,這時我又想起在Java中的一個命令:jstack

jstack命令主要用來查看Java執行緒的調用堆棧的,可以用來分析執行緒問題(如死鎖)。

jstack詳細用法以及教程:https://www.cnblogs.com/kongzhongqijing/articles/3630264.html

於是我就去執行了一下jstack命令,在資訊中搜了一下"Email",真被我搜出來了:

发邮件卡住了

那就好辦了,只要搜一下:「Java 發送郵箱 執行緒 阻塞」此類的關鍵字,應該就有解決方案了。

解决方案

最後,發現是因為在發送郵件的時候沒有配置超時時間,導致某些執行緒在發送郵件的時候阻塞掉了(具體原因不明)

  • mail.smtp.connectiontimeout:連接時間限制,單位毫秒。是關於與郵件伺服器建立連接的時間長短的。默認是無限制。
  • mail.smtp.timeout:郵件接收時間限制,單位毫秒。這個是有關郵件接收時間長短。默認是無限制。
  • mail.smtp.writetimeout:郵件發送時間限制,單位毫秒。有關發送郵件時內容上傳的時間長短。默認同樣是無限制。

最後

樂於輸出乾貨的Java技術公眾號:Java3y。公眾號內有200多篇原創技術文章、海量影片資源、精美腦圖,關注即可獲取!

转发到朋友圈是对我最大的支持!

覺得我的文章寫得不錯,點贊!

Tags: