郵件服務器-POP3服務器郵件索引/UIDL簡單、高效的緩存方案

對於POP3服務器來說,最重要的衡量標準就是單臺服務器所能承擔的用戶服務,這其中會涉及用戶併發數、網絡帶寬流量等因素影響。

POP3服務目前在國內的企業郵箱應用裏面是一個比較普及的功能,畢竟outlook、foxmail客戶端做的確實很不錯,而且這麼多年的用戶習慣,還是習慣把郵件拉到自己的本地辦公電腦上來操作和查找,當然,爲了在多地點的訪問,用戶又習慣在服務器保留副本,至少在出差或是家裏還是可以通過webmail來處理一下郵件,畢竟不能總是揹着辦公電腦跑,其實這就帶來一個問題,用戶的 UIDL 列表會很多,在10W這級別算是正常(關於降低 UIDL 列表,也有兩種方案,以後再介紹吧),那麼如何高效的爲用戶送 UIDL 列表就成爲POP3服務器的一個性能指標。

其實高性能網絡服務器的幾個改進重點,無外乎幾種手段,採用異步模型,增加用戶併發訪問能力,增加緩存(內存、SSD、磁盤),提高數據的快速獲取和響應,對於用戶認證這塊,估計現在大家基本都是 Memcached/Redis 了,那麼對於POP3這種特殊服務,其實還有一個地方需要緩存,並且可以顯著提高POP3的響應性能,那就是 STAT/UIDL 緩存。

現在市場的郵件服務器的索引實現基本上也就這幾種方式,二進制結構化文件、bdb/sqlite/gdbm用戶級數據庫文件、MySQL/PostgreSQL幾種方式吧,當然開源的Mailbox/Maildir還是原始的無索引方式,不過Dovecot已經自己增加了二進制結構文件緩存(這個以後研究一下),所以在將用戶郵件索引加載爲 STAT/UIDL 緩存時,可以採用有一個簡單、高效的方式,爲沒一個用戶建立一個 STAT/UIDL 緩存文件(當然是在 TMP/HASHDIR 下,這個就不介紹了),在文件內直接將 STAT和UIDL列表直接存儲在裏面,以供POP3會話使用,那麼爲什麼採用這樣的方式存儲呢?現在主要說明一下,首先文件系統的實現是非常穩定和安全的,文件的定位訪問也是非常快速的,而且一個用戶一個緩存文件,就直接隔離了用戶數據,然後最重要的就是,這種方式可以靈活的部署緩存方式,我們可以指定這個緩存以內存(/dev/shm)、SSD、磁盤來存儲,採用每種方式,就完全取決於服務器的物理狀況,這樣調整起來非常容易和方便。

下面介紹一下這個緩存文件在POP3會話中的使用方式,在STAT狀態時,進行 popcache.loads() 加載緩存,如果無緩存的話,就直接通過索引服務器接口直接獲取狀態信息(存在會話句柄中),繼續進行 UIDL 狀態(LIST/UIDL),此時也是直接通過索引服務器接口獲取(存在會話句柄中),接下來用戶會進行 RETR/DELE 等很多操作,這個過程都是和服務器的實際郵件文件操作,最後,用戶會發送 QUIT 結束會話,此時將最終的狀態信息和UIDL列表信息進行 popcache.dumps() 存儲到緩存文件,這樣用戶在下一次(通常情況是30s、1分鐘)的 CHECK 操作中,就不需要進行索引服務器信息加載,如果緩存文件在內存或SSD中,這個速度是相當快的。

目前可能還會有個疑問,這個緩存文件在什麼時候刪除呢?在用戶索引條目變化的時候(也就是有新郵件,或是webmail/imap的刪除、移動時),這時爲了方便起見,直接採用暴力的方式 popcache.clean () 刪除掉緩存文件,用戶的再次進行POP3服務時會自動加載緩存了,同時也可以爲緩存文件建立一個 TIMEOUT 機制,在讀完緩存後檢查一個更新時間,超過 TIMEOUT 也可以直接刪除,這個就取決於用戶對 POP3 實時響應時間的要求了(也可以兩種方式結合),其中對於獨立的POP3服務器來說,驅動 popcache.clean() 的最好方式就是擴展一個POP3的 X-CLEAN 命令了,不過這個命令肯定要進行一個 allow ip的鑑權或是防火牆保護。

這個算是一個初步方案,其實就是提高在有新郵件到來前,用戶頻繁連接服務器CHECK狀態時的響應速度,並降低服務器的複雜和索引的頻繁查詢。畢竟普通用戶不會每分鐘都有新郵件,但是foxmail/outlook的定時、頻繁pull操作,服務器的開銷還是很大的。

嗯,差不多這樣就可以了,暢想一下,用Libevent內嵌一個Python解釋器實現一個POP3 Server會如何呢?權衡開發難度和服務器性能會不會好些呢?有機會就實現一個試試吧!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章