Nginx 切片模塊、斷點續傳

来源:http://www.cnblogs.com/chenpingzhao/archive/2016/08/24/5803772.html
-Advertisement-
Play Games

熟悉 CDN 行業主流技術的朋友應該都比較清楚,雖然 Nginx 近幾年發展的如日中天,但是基本上沒有直接使用它自帶的 proxy_cache 模塊來做緩存的,原因有很多,例如下麵幾個: 不支持多盤 不支持裸設備 大文件不會切片 大文件的 Range 請求表現不盡如人意 Nginx 自身不支持合併回 ...


熟悉 CDN 行業主流技術的朋友應該都比較清楚,雖然 Nginx 近幾年發展的如日中天,但是基本上沒有直接使用它自帶的 proxy_cache 模塊來做緩存的,原因有很多,例如下麵幾個:

  • 不支持多盤

  • 不支持裸設備

  • 大文件不會切片

  • 大文件的 Range 請求表現不盡如人意

  • Nginx 自身不支持合併回源

在現在主流的 CDN 技術棧裡面, Nginx 起到的多是一個粘合劑的作用,例如調度器、負載均衡器、業務邏輯(防盜鏈等),需要與 Squid、ATS 等主流 Cache Server 配合使用,

Nginx-1.9.8 中新增加的一個模塊ngx_http_slice_module解決了一部分問題。

首先,我們看看幾個不同版本的 Nginx 的 proxy_cache 對 Range 的處理情況。

Nginx-0.8.15

在 Nginx-0.8.15 中,使用如下配置文件做測試:

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    proxy_cache_path /tmp/nginx/cache levels=1:2 keys_zone=cache:100m;
    server {    
        listen       8087;
        server_name  localhost;
        location / {
            proxy_cache cache;
            proxy_cache_valid 200 206 1h;
           # proxy_set_header Range $http_range;
            proxy_pass http://127.0.0.1:8080;

        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }
}

重點說明以下兩種情況:

  • 第一次 Range 請求(沒有本地緩存),Nginx 會去後端將整個文件拉取下來(後端響應碼是200)後,並且返回給客戶端的是整個文件,響應狀態碼是200,而非206. 後續的 Range 請求則都用緩存下來的本地文件提供服務,且響應狀態碼都是對應的206了。

  • 如果在上面的配置文件中,加上 proxy_set_header Range $http_range;再進行測試(測試前先清空 Nginx 本地緩存)。則第一次 Range 請求(沒有本地緩存),Nginx 會去後端用 Range 請求文件,而不會把整個文件拉下來,響應給客戶端的也是206.但問題在於,由於沒有把 Range 請求加入到 cache key 中,會導致後續所有的請求,不管 Range 如何,只要 url 不變,都會直接用cache 的內容來返回給客戶端,這肯定是不符合要求的。

Nginx-1.9.7

在 Nginx-1.9.7 中,同樣進行上面兩種情況的測試,第二種情況的結果其實是沒多少意義,而且肯定也和 Nginx-0.8.15 一樣,所以這裡只關註第一種測試情況。

第一次 Range 請求(沒有本地緩存),Nginx 會去後端將整個文件拉取下來(後端響應碼是200),但返回給客戶端的是正確的 Range 響應,即206.後續的 Range 請求,則都用緩存下來的本地文件提供服務,且都是正常的206響應。

可見,與之前的版本相比,還是有改進的,但並沒有解決最實質的問題。

我們可以看看 Nginx 官方對於 Cache 在 Range 請求時行為的說明:

How Does NGINX Handle Byte Range Requests?

If the file is up-to-date in the cache, then NGINX honors a byte range request and serves only the specified bytes of the item to the client. If the file is not cached, or if it’s stale, NGINX downloads the entire file from the origin server. If the request is for a single byte range, NGINX sends that range to the client as soon as it is encountered in the download stream. If the request specifies multiple byte ranges within the same file, NGINX delivers the entire file to the client when the download completes.

Once the download completes, NGINX moves the entire resource into the cache so that all future byte-range requests, whether for a single range or multiple ranges, are satisfied immediately from the cache.

Nginx-1.9.8

我們繼續看看Nginx-1.9.8, 當然,在編譯時要加上參數--with-http_slice_module,並作類似下麵的配置:

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    proxy_cache_path /tmp/nginx/cache levels=1:2 keys_zone=cache:100m;
    server {
        listen       8087;
        server_name  localhost;
        location / {
            slice 1m;
            proxy_cache cache;
            proxy_cache_key $uri$is_args$args$slice_range;
            proxy_set_header Range $slice_range;
            proxy_cache_valid 200 206 1h;
            #proxy_set_header Range $http_range;
            proxy_pass http://127.0.0.1:8080;

        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }
}

不測不知道,一側嚇一跳,這儼然是一個殺手級的特性。

首先,如果不帶 Range 請求,後端大文件在本地 cache 時,會按照配置的 slice 大小進行切片存儲。

其次,如果帶 Range 請求,則 Nginx 會用合適的 Range 大小(以 slice 為邊界)去後端請求,這個大小跟客戶端請求的 Range 可能不一樣,並將以 slice 為大小的切片存儲到本地,並以正確的206響應客戶端。

註意上面所說的,Nginx 到後端的 Range 並不一定等於客戶端請求的 Range,因為無論你請求的Range 如何,Nginx 到後端總是以 slice 大小為邊界,將客戶端請求分割成若幹個子請求到後端,假設配置的 slice 大小為1M,即1024位元組,那麼如果客戶端請求 Range 為0-1023範圍以內任何數字,均會落到第一個切片上,如果請求的 Range 橫跨了幾個 slice 大小,則nginx會向後端發起多個子請求,將這幾個 slice 緩存下來。而對客戶端,均以客戶端請求的 Range 為準。如果一個請求中,有一部分文件之前沒有緩存下來,則 Nginx 只會去向後端請求缺失的那些切片。

由於這個模塊是建立在子請求的基礎上,會有這麼一個潛在問題:當文件很大或者 slice 很小的時候,會按照 slice 大小分成很多個子請求,而這些個子請求並不會馬上釋放自己的資源,可能會導致文件描述符耗盡等情況。

小結

總結一下,需要註意的點:

  • 該模塊用在 proxy_cache 大文件的場景,將大文件切片緩存

  • 編譯時對 configure 加上 --with-http_slice_module 參數

  • $slice_range 一定要加到 proxy_cache_key 中,並使用 proxy_set_header 將其作為 Range 頭傳遞給後端

  • 要根據文件大小合理設置 slice 大小

具體特性的說明,可以參考 Roman Arutyunyan 提出這個 patch 時的郵件來往:
https://forum.nginx.org/read.php?29,261929,261929#msg-261929

順帶提一下,Roman Arutyunyan 也是個大牛,做流媒體領域的同學們肯定很多都聽說過:nginx-rtmp 模塊的作者。

參考資料

  • http://www.tianwaihome.com/2015/03/nginx-proxy-cache.html

  • Nginx 官方的 Cache 指南

       https://www.nginx.com/blog/nginx-caching-guide/

  • Nginx各版本changelog

       http://nginx.org/en/CHANGES

  • Nginx proxy 模塊 wiki

      http://nginx.org/en/docs/http/ngx_http_proxy_module.html

  • http_slice_module 的歷次提交記錄

      http://hg.nginx.org/nginx/rev/29f35e60840b

      http://hg.nginx.org/nginx/rev/bc9ea464e354

      http://hg.nginx.org/nginx/rev/4f0f4f02c98f

  • http_slice_module 提交前的郵件來往

      https://forum.nginx.org/read.php?29,261929

  • Nginx 之前版本關於 Range cache 的郵件來往

      https://forum.nginx.org/read.php?2,8958,8958

  • 切片模塊的 wiki

     http://nginx.org/en/docs/http/ngx_http_slice_module.html

 

本文來源於:http://www.pureage.info/2015/12/10/nginx-slice-module.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 複製和移動文件 cp:copy cp SRC DEST cp file1 file2 file3 //file1,file2為源文件,file3為目標 複製一個文件到一個文件 複製多個文件到一個目錄,目錄必須存在 cp /etc/passwd /tmp/ 複製到/tmp/下,文件名為passwd 若 ...
  • 在windows主機安裝centos虛擬機後,遇到虛擬機連接外網問題。 解決方案:http://blog.csdn.net/pang040328/article/details/12427359 經過如上操作,確認可以ping 8.8.8.8,表示虛擬機可以連接外網了。不過,ping www.bai ...
  • 首先根據書中講解的實例代碼(標準實例來源於UCOS ii經典教程 邵貝貝) 並且在另一個任務中進行消息發送,如下代碼 無論是斷點調試,還是從輸出的調試信息中都可以確定每次都有消息發送,但是在OSMboxPend中始終沒有接收到消息導致err一直等於OS_TIMEOUT而無法進行正確消息處理 但是只要 ...
  • 最近公司團隊的項目用到ESP8266,使用的是stm32c8t6晶元,軟體使用MDK,於是寫下調試過程中的一些註意點。具體代碼和涉及思路不能外泄,這裡只給出我們調試過程中的註意的方面。 關於ESP8266,我們首先做一些說明,這些都是我們團隊在調試過程中總結出來的,都是經過實際的測試,而不是談論或是 ...
  • 簡要複習一下ARM9中斷控制器的控制過程: 1.首先能識別觸發的中斷(對應中斷源必須打開,然後查詢當前中斷狀態寄存器),硬體會操控PC跳到中斷向量入口(IRQ_HANDLE,硬體控制的只要是IRQ中斷類型就會進入),在中斷跳轉函數裡面保存現場(保存R0等等工作寄存器)--跳到服務函數(裡面進行中斷源 ...
  • 文件描述符 可以理解為linux跟蹤打開文件,而分配的一個數字,這個數字有點類似c語言操作文件時候的句柄,通過句柄就可以實現文件的讀寫操作 用戶可以自定義文件描述符範圍是:3 num,這個最大數字,跟用戶的:ulimit –n 定義數字有關係,不能超過最大值 查看系統文件描述符最大值 linux系統 ...
  • Centos6.2代碼 CentOS 6.0沒有預設沒有裝語言支持(Language Support),因此很不方面。 終於發現了有效的方法: su root yum install "@Chinese Support" exit 最後一步:logout,註意是註銷,然後再次登錄此用戶。 當然這裡安... ...
  • 在ubuntu下網路管理器Network Manager莫名奇妙出現無法連接無線網的情況,於是昨天就開始著手解決這一問題: 一 :卸載 1.第一步卸載Network-Manager (具體字母的大小寫我沒註意,如果Network-Manager不能成功,那就換成network-manager試試,卸 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...