Ruby on Rails 網站大型化之靜態資源 CDN 架構


rails是個很成熟的網站開發架構,設計者也與時俱進把很多先進的技術與架構集成到rails中,造就了其他框架無法比擬的開發效率。網站發展到一定程度,網站流量越來越大就不能把靜態文件請求和動態網頁請求放到同一台服務器。因為靜態資源的流量會遠遠大於動態資源的請求,流量一大,靜態資源會占滿服務器帶寬,導致網站加載緩慢,所以cdn是必不可少的。

個人原創,版權所有,轉載請注明出處,並保留原文鏈接:

https://www.embbnux.com/2016/01/07/ruby_on_rails_assets_cdn/


rails的開發者考慮得很全,要實現網站的cdn化,只需要修改一個配置文件即可,不過為了不顯得我這篇博文太少了,我還是慢慢的講來。

一、講講原理之一個網頁的請求

一個網頁從在瀏覽器輸入網址,到展示在你面前,之間經歷了好多個請求,主要流程如下:

  • 發送請一個請求到所訪問地址,網站服務器返回一個html文本
  • 瀏覽器解析html文本,並加載里面引入的js、css以及圖片等文件, 這些叫做靜態資源,同樣瀏覽器還要往服務器發送這些靜態資源的請求
  • 等待外部靜態資源請求完成后,瀏覽器在進行css,js文件的解析執行,把圖片等填充到網頁上
  • 然后就是你所看到的一個網頁了,有顏色有圖片也有交互

二、rails的靜態資源

rails對於的靜態資源主要有兩種,一種是寫在代碼里的,比如網站的js、css以及圖標等文件,還有一種為用戶上傳的,比如用戶上傳的頭像圖片等。

對於靜態文件等rails引入了Asset Pipeline用來管理編譯靜態資源, 對於第一種寫在代碼里的靜態文件,在rails工程里面是存在app/assets文件夾下,分別有images和stylesheets以及javascripts等分類文件夾,js和css代碼放在這里可以用coffeescript以及sass等各種語言來寫,最終線上環境(生產環境)得對這些代碼進行編譯生成js以及css文件,這樣瀏覽器才會識別,編譯不僅進行格式的翻譯還會進行minify等,最終會在編譯文件后面加一段當前文件的hash,所以代碼變動,編譯出的文件就不一樣:

RAILS_ENV=production rake assets:precompile
#assets/javascripts/application.js => pubilic/application-3214abdc8899.js

由於編譯完的文件被加了一段hash所以不能直接在html里面用路徑訪問,所以得在view層渲染時得出文件路徑:

app/views/layout/application.html.erb:

<%= stylesheet_link_tag 'application' %>
<%= javascript_include_tag 'application' %>
<%= image_url 'favicon.png' %>

對應渲染出來的html是:

<link rel="stylesheet" media="screen" href="/assets/application-122fe15eeed76211bd37e2f1234454.css" />
<script src="/assets/application-583bffd2a21c2a6b8d1ab72bad4ba8af.js">
assets/favicon-1aa0e2adc41f64de39.png

加hash是為了在代碼得到更新后瀏覽器能夠及時更新使用新的靜態文件,早期的 rails版本使用的版本控制手段如下:

/stylesheets/application.css?1309495796

但是這種手段在cdn的使用場景上不能及時更新存在cdn上的文件,所以該用加了hash的文件名來做版本控制,保證cdn部署時代碼和靜態資源得到同時跟新,變成這樣

application-1309495796.css

第二種靜態資源是用戶上傳的,這些的不是放在代碼里的,在rails工程中這些靜態文件放在public文件夾下,因為web服務器的根目錄指向的就是public文件夾,其他文件夾瀏覽器沒有權限訪問得到, 之前的js和css也得被編譯完后放到public文件夾才可以訪問。這些靜態文件不會被編譯,所以文件名后面不會被加入hash, 但也可以用image_url ‘upload/avatar.png’來訪問,image_url會自動區分要不要加hash.

upload/avatar.png

三、開啟cdn

說了這么多,是時候開啟cdn了。如果一直是按rails規范來寫的話在這里開啟cdn配置,只需要在config/environments/production.rb加一句話:

config.action_controller.asset_host = 'static-cdn.embbnux.com'

這樣之前渲染出來的html就變成這樣:

<link rel="stylesheet" media="screen" href="http://static-cdn.embbnux.com/assets/application-122fe15eeed7688837e2f1234454.css" />
<script src="http://static-cdn.embbnux.com/assets/application-583bffd2a21c2a6b8d1a888ad4ba8af.js">
http://static-cdn.embbnux.comassets/favicon-1aa0e2adc41888de39.png
http:/
/static-cdn.embbnux.com/upload/avatar.png

出來的路徑就是指向cdn服務器上的靜態資源了,這樣一個網頁的訪問就只會有第一個html的請求發到我們服務器上,其他的靜態資源請求是發到cdn服務器上的,一個html文本一半也就幾k,大小很小的,加載時間也很快,不很會占用服務器帶寬。

有時候為了區分和管理第一種網站靜態資源和第二種用戶靜態資源可以配置分別指向兩個cdn域名,不同的域名用不同的cdn空間,可以這樣配置

config.action_controller.asset_host = Proc.new { |source|
if source =~ /assets/
'static-assets-cdn.embbnux.com'
else
'static-images-cdn.embbnux.com'
end
}

這樣渲染出來就變成這樣:

<link rel="stylesheet" media="screen" href="http://static-assets-cdn.embbnux.com/assets/application-122fe15eeed76211bd37e2f1234454.css" />
<script src="http://static-assets-cdn.embbnux.com/assets/application-583bffd2a21c2a6b8d1882bad488af.js">
http://static-assets-cdn.embbnux.comassets/favicon-1aa0e2adc8884de39.png
http:/
/static-images-cdn.embbnux.com/upload/avatar.png

為了保證assets文件及時更新到cdn存儲,可以寫個rake腳本利用cdn商提供的接口,在部署的時候及時上傳assets文件到cdn空間比如:

rake cdn:assets_upload

四、web服務器配置

為了保證cdn的文件能夠及時與我們自己服務器上靜態文件保持一致,需要開啟cdn的鏡像功能,但為了不使cdn緩存我們的動態html內容,造成鏡像網站而降低網站權重,需要配置一下nginx服務器

server {
server_name www.embbnux.com;
root /rails_app/public;
location / {
index index.html index.htm;
proxy_pass http://rails_app_upstream;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

server {
server_name static.embbnux.com;
root /rails_app/public;
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
location ~* ^/assets/ {
root /rails_app/public;
expires 1y;
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";
break;
}
}

這樣服務器上的靜態資源就可以通過static.embbnux.com訪問,動態資源只能通過www.embbnux.com訪問,cdn鏡像通過static域名,也就不用擔心會鏡像動態頁面

四、更進一步

開啟cdn后也就不用擔心靜態資源來占我們服務器的帶寬了,不過這也只是大型化網站的第一步,還可以進行很多優化,歡迎拍磚。流量在大一點,只接受動態資源請求的我們網站服務器也會承受不了的,這時候就是開啟負載均衡的時候了,可以一個nginx代理請求,然后中轉到幾台服務器上的rails_app_upstream,這都是后話了。

更多內容歡迎查看原文博客:
https://www.embbnux.com/2016/01/07/ruby_on_rails_assets_cdn/



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com