Skip to content

加快 Amazon S3 上靜態網站的存取

Published: 9 分鐘

山姆鍋曾經提到,影化身網站是放置在 Amazon S3 上,也利用 CloudFront來減少存取的延遲。 但是,好還可以更好,山姆鍋在本文會分享如何減少 HTTP 要求數量,壓縮網頁內容來加快存取速度。

Amazon S3 雖然方便,但因為不是設計來支援動態內容,有幾個限制會影響到存取效率的最佳化(優化),像是不支援執行時期 GZip encoding。雖然不支援動態壓縮,但是我們可以預先把內容做 GZip 壓縮來達到同樣效果。底下將說明如何透過 s3cmd 這個工具來達到減少 HTTP 請求數量以及資料量的目的。對了!請注意山姆鍋用的工作環境是 Mac OS X。

準備工具 s3cmd

本文使用的 s3cmd 版本需要是 1.1 以上。

安裝 s3cmd

到官方網站下載s3cmd並解壓縮後,執行下列指令來安裝:

$ python setup.py install

設定 s3cmd

要讓 s3cmd 能夠正確連到 Amazon S3 服務,需要做些設定。在命令列執行下列指令並安照提示輸入您 S3 的認證資訊:

$ s3cmd --configure

驗證 s3cmd 安裝完成

執行下列指令,確定 s3cmd 已經可以正確連到 Amazon S3:

$ s3cmd ls
2013-05-22 10:24  s3://aaa.eavatar.com
2013-06-05 02:30  s3://blog.eavatar.com

如果有看到之前建好的 bucket 就表示安裝設定正常。

預先對 HTML, JS, 以及 CSS 檔案做 GZip 壓縮

之前提過 Amazon S3 不支援動態做檔案的 GZip 壓縮,但我們可以預先壓好檔案在上傳到 S3。除了預先壓縮外,還要告訴 S3,這些壓縮過的檔案該使用的 HTTP 標頭。

設定壓縮腳本

在 Rakefile 中,加入下列腳本:

desc "GZip HTML"
task :gzip_html do
  puts "## GZipping HTML"
  system 'find public/ -type f -name \*.html -exec gzip -9 {} \;'
  # Batch rename .html.gz to .html
  Dir['**/*.html.gz'].each do |f|
    test(?f, f) and File.rename(f, f.gsub(/\.html\.gz/, '.html'))
  end
end

desc "GZip CSS"
task :gzip_css do
  puts "## GZipping CSS"
  styles_dir = "#{public_dir}/assets"
  system 'find public/assets -maxdepth 1 -type f -name \*.css -exec gzip -9 {} \;'
  # Batch rename .css.gz to .css
  Dir['public/assets/*.css.gz'].each do |f|
    test(?f, f) and File.rename(f, f.gsub(/\.css\.gz/, '.css'))
  end
end

desc "GZip JS"
task :gzip_js do
  puts "## GZipping JS"
  styles_dir = "#{public_dir}/assets"
  system 'find public/assets -maxdepth 1 -type f -name \*.js -exec gzip -9 {} \;'
  # Batch rename .js.gz to .js
  Dir['public/assets/*.js.gz'].each do |f|
    test(?f, f) and File.rename(f, f.gsub(/\.js\.gz/, '.js'))
  end
end

desc "GZip All"
task :gzip => [:gzip_html, :gzip_css, :gzip_js] do
end

同樣是 Rakefile,修改 generate 任務確保每次產生檔案時同時作壓縮。修改後的 generate 任務看起來應該像:

desc "Generate jekyll site"
task :generate do
  raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
  puts "## Generating Site with Jekyll"
  system "compass compile --css-dir #{source_dir}/assets"
  system "jekyll"
  Rake::Task[:gzip_html].execute
  Rake::Task[:gzip_css].execute
  Rake::Task[:gzip_js].execute
end

注意,上述腳本山姆鍋只在 Mac OS X 上測試過,不過理論上,Linux 系統應該也可以執行。基本上,這個腳本會把 HTML, CSS 以及 JS 檔案使用 gzip 壓縮,並將’js’從檔名中移除。另外,您要根據您 JS/CSS 輸出的路徑,修改’public/assets’成實際放置 JS/CSS 的路徑。

修改部署腳本來設定適當 HTTP 標頭

修改 Rakefile 中,S3 的部署腳本,針對 HTML, JS 以及 CSS 檔案做不同的配置。

desc "Deploy staging website via s3cmd"
task :s3_dev do
  puts "## Deploying staging website via s3cmd"
  # sync gzipped html files
  # NOTE: Setting charset in header for faster browser rendering
  ok_failed system("s3cmd sync  --acl-public -P --reduced-redundancy public/* s3://#{s3_bucket_dev}/ --mime-type='text/html; charset=utf-8' --add-header 'Content-Encoding: gzip' --exclude '*.*' --include '*.html'")
  # sync non gzipped, non js/css/image files
  ok_failed system("s3cmd sync --guess-mime-type --acl-public -P --reduced-redundancy public/* s3://#{s3_bucket_dev}/ --exclude 'images/' --exclude '*.css' --exclude '*.js'  --exclude '*.html'")
  # sync gzipped css and js
  ok_failed system("s3cmd sync --guess-mime-type --acl-public -P --reduced-redundancy public/* s3://#{s3_bucket_dev}/ --add-header 'Content-Encoding: gzip' --add-header 'Cache-Control: public, max-age=31600000' --exclude '*.*' --include '*.js' --include '*.css'")
  # sync all images
  ok_failed system("s3cmd sync --guess-mime-type --acl-public -P --reduced-redundancy  --add-header 'Cache-Control: public, max-age=31600000' public/images/* s3://#{s3_bucket_dev}/images/")
end

其中,請把#{s3_bucket_dev}換成您使用的 S3 bucket 名稱。 底下是幾個重要的 s3cmd 參數說明:

  • —add-header 參數告訴 s3cmd,當那些檔案被下載時,要設定相對應的 HTTP 標題。
  • —mime-type 指定該檔案要回傳給瀏覽器的 Mime 型別。Amazon S3 對於 HTML 檔案預設並不會有 utf-8 這個編碼設定,但沒有這個設定,瀏覽器要等比較久的時間才能決定網頁內容的正確編碼,甚至使用了錯誤的編碼。

除了設定’Content-Encoding: gzip’這個標頭讓瀏覽器知道回傳的內容經過 gzip 壓縮外,同時也設定’Cache-Control’標頭來讓瀏覽器或者 CloudFront 知道這些內容該緩存的時間。針對 JS、圖檔、或者 CSS 這類靜態檔案,我們希望緩存的時間越長越好。但是 HTML 或者XML檔案,因為,會需要比較快更新,山姆鍋在這裡設為緩存 1 小時(),您可以根據需要自行調整。

小結

作為靜態網站服務器,Amazon S3 不支援動態 GZip,的確是不方便。不過它提供的額外特性以及跟 CloudFront 整合,讓它仍舊是相當好的選擇。

參考資料

郭信義 (Sam Kuo)

奔騰網路科技技術長,專長分散式系統、Web 應用與雲端服務架構、設計、開發、部署與維運。工作之餘,喜歡關注自由軟體的發展與應用,偶爾寫一下部落格文章。

你可能會有興趣的文章