服務端處理耗時請求(發郵件/壓縮圖片/抓取網頁)一般有幾種方法?
01-01
先說耗時的操作,一般有兩類:
- 計算密集型,比如壓縮圖片,壓縮視頻,計算一個龐大的函數表達式等等
- IO (Input/Output,輸入輸出)延時型,比如抓取網頁、發送郵件、下載文件等等
而前者的很多也可以歸類至 IO 中。
比如「壓縮圖片」的本質就是從一個輸入流讀取圖片信息,保存為自身語言支持的 Bitmap 數據結構,這個過程屬於 Input,然後在 Output 的過程中進行數據壓縮和編碼。那麼,IO 處理方法從大的分類來說,都可以分為 Blocked IO(阻塞型)和 Non-blocked IO(非阻塞型)。
還有一種類似的分類,叫同步 IO 和非同步 IO。關於兩者的對比以及各自的優缺點,給一個參考傳送:http://blog.csdn.net/jeanwaljean/article/details/5982292
那麼伺服器選擇何種作為處理,首先應取決於自身語言的特性。- 以 JavaScript 作為伺服器語言(沒錯,說的就是 NodeJS),一般是選擇非同步 IO,這是由 JavaScript 自身的函數式語言特性決定,函數作為對象,可以很方便地作為參數傳入用於操作完成時的 callback。NodeJS 甚至連資料庫的操作都是非同步的,這個在其他語言中並不常見。
- 以 Java 作為伺服器語言,如果選擇了默認的 IO 方式,那麼就是阻塞式的。直觀方便,IO 操作不結束,方法調用就不返回。同時,Java 還提供了第二種方式,就是非阻塞 IO,所使用到的類主要在 java.nio 包下。
第二,還取決於應用場景。
以「發送郵件」這種常見案例來說,要看你是希望營造一種什麼樣的用戶體驗。大部分伺服器的服務對象應該是為客戶瀏覽器。用戶在前端(瀏覽器)點擊發送郵件後,伺服器收到這個請求,怎麼做?有兩種方法:
- 直接返回「OK,我知道了,馬上幫你處理」的 response,同時後台再去做,返回要比執行實際操作更早
- 伺服器立馬去發郵件,整個請求(HTTP Request)還是處於處理中的狀態,直到郵件發送結束(SMTP 伺服器返回發送結果),才返回客戶端一個結果
這兩種操作都是可行的,前者的用戶體驗是快,後者的用戶體驗是更可靠。
因為一旦發送失敗了,後者的實現上,伺服器很簡單就可以把失敗信息返回。但是對於前者,瀏覽器與伺服器之間的 Connection 一般是斷掉的,那麼發送失敗了,伺服器不知道該向哪裡返回,可能只好自己默默寫入資料庫,只有用戶查詢了才知道,哦,原來上次沒發送成功啊。當然,技術是不斷發展的,對於情況 1 也是有辦法直接讓瀏覽器知道發送結果的,一般就是 Comet 技術,但是對於開發人員來說,2 更方便。---綜上,沒有最優,只有最合適。
趁下班的空兒和我這邊的架構師討論了一下:
從架構來說,所有的伺服器耗時操作都建議採用非同步方式來進行,這樣可以提高伺服器的響應能力,提升用戶體驗。- 發送郵件,目前基本上郵件伺服器都是採用隊列的方式進行處理,也就是說程序將郵件發送的請求提交給郵件伺服器即可認為郵件已發送,郵件伺服器來完成所有的發送操作。
- 對於壓縮圖片,這個需要根據單個圖片文件的大小以及圖片文件的數量來說的,如果數量巨大則需要通過集群進行處理。
- 抓取網頁涉及的方面比較多:
- 抓取深度和廣度的問題,需要處理重複抓取的問題,處理到幾級連接?
- 需要分段抓取,不同的伺服器抓取不同的網段,最後合併
- 針對不同的網段的地域及時差,可以分配不同的網段給同一台伺服器來進行抓取,避開網路高峰時段。
後台架構,對於耗時操作一般採用單獨的伺服器或者服務程序來完成,並通過消息匯流排對各個分系統進行通知,從而提高系統的響應速度。目前可以通過很多現有的架構模型來簡化非同步處理,比如通過ESB來完成各類消息的路由及發布,下圖就是Mule Esb的非同步處理方式。
郵件一般都是不告訴你的。你平常上Web郵箱發郵件,也不是點了發送之後就立刻都對方信箱的,而是上傳到伺服器上後就告訴你發送成功,然後後台慢慢發送,如果失敗給你一封退信。
其他的如果需要用戶知道的,都會有個狀態提示,比如優酷的視頻轉碼。看有多耗時了,非常耗時的話可以不同步返回,提交task到服務端,然後拿到一個唯一id,客戶端定期通過這個id來check完成進度
推薦閱讀:
※很多QQ,網易郵箱只在登陸時採用HTTPs,那麼進去後都HTTP這樣的網站安全嗎?
※HTTP/2 對現在的網頁訪問,有什麼大的優化呢?體現在什麼地方?
※既然說 HTTP 是明文傳輸,為什麼沒聽說哪個著名的網站因為採用 http 協議而暴露了用戶的密碼?
※用 http 數據加密和 https 有什麼區別?
※http協議請求響應頭中參數的疑問??