a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 編程 > Ruby > 正文

Ruby on Rails中緩存機(jī)制的深度解析

2020-02-24 15:40:34
字體:
供稿:網(wǎng)友

  今天小編給大家分享一篇Ruby on Rails中緩存機(jī)制的深度解析,感興趣的朋友跟小編一起來了解一下吧!

  幾個(gè)場景

  首先,讓我先來帶您瀏覽幾個(gè) ChangingThePresent.org 中的頁面吧。我將顯示站點(diǎn)中幾個(gè)需要緩存的地方。然后,再指出我們?yōu)槠渲忻總€(gè)地方所做出的選擇以及為實(shí)現(xiàn)這些頁面所使用的代碼或策略。尤其會重點(diǎn)討論如下內(nèi)容:

  全靜態(tài)頁面

  幾乎無變化的全動態(tài)的頁面

  動態(tài)頁面片段

  應(yīng)用程序數(shù)據(jù)

  先來看看靜態(tài)頁面。幾乎每個(gè)站點(diǎn)都會有靜態(tài)頁面,如圖 1 所示,其中還有我們的條款和條件。可以通過單擊 register 然后再選擇是否接受用戶協(xié)議來瀏覽相應(yīng)頁面。對于 ChangingThePresent 而言,我們從此頁中刪除了所有動態(tài)內(nèi)容以便 Apache 能夠?qū)λM(jìn)行緩存。按照我們 Apache 中配置的規(guī)則,這些內(nèi)容永遠(yuǎn)都不會由 Rails 服務(wù)器生成。因此,我根本無需對其考慮 Rails 緩存。

  圖 1. 用戶協(xié)議

2015422163759311.jpg (402×341)

  接下來,再來看看全動態(tài)頁面。理論上講,ChangingThePresent 可以有一些動態(tài)構(gòu)建的頁面,但是這些頁面一般很少變化。由于幾乎所有頁面都會顯示用戶是否登錄,因此我們并不怎么關(guān)注這種緩存。

  再下來,看看頁面分段緩存。圖 2 中所示的主頁原來是完全靜態(tài)的,現(xiàn)在,有一些元素變成了動態(tài)的。每天,頁面都會顯示一系列禮物,這些禮物有的是隨機(jī)選的,有的則由我們的管理員選定。請注意在標(biāo)題為 “A Few of our Special Gifts for Mother's Day” 節(jié)下的那些禮物,同時(shí)也請注意在最右邊顯示為 “l(fā)ogin.” 的那個(gè)鏈接。此鏈接取決于用戶是否登錄。我們不能緩存整個(gè)頁。頁面每天只能改變一次。

  圖 2. 主頁

2015422163836768.jpg (572×433)

  最后再考慮應(yīng)用程序。除非是在 15 年之前進(jìn)行網(wǎng)絡(luò)沖浪,否則您現(xiàn)在遇到的有趣站點(diǎn)全部都是動態(tài)的。現(xiàn)代的應(yīng)用程序大都分層,而且可以通過在層間添加緩存來使這些分層更加有效。ChangingThePresent 在數(shù)據(jù)庫層采用了一些緩存。接下來,我將深入討論不同類型的緩存,還會介紹我們?yōu)?ChangingThePresent 都采用了何種緩存。

  緩存靜態(tài)內(nèi)容

  Mongrel 是一種 Web 服務(wù)器,由 Zed Shaw 利用 2500 行 Ruby 和 C 編寫而成。這個(gè)小型的服務(wù)器占用內(nèi)存極少,非常適合 Ruby Web 應(yīng)用程序,例如 Rails、Nitro、Iowa 等等。Mongrel 可運(yùn)行于 UNIX? 和 Linux? 上,也可運(yùn)行在 Win32 上。Mongrel 也經(jīng)常可以作為代理運(yùn)行在另一個(gè) Web 服務(wù)器(例如 Apache 或 Litespeed)的后端,但這不是必需的 —— 因?yàn)?Mongrel 是一種 HTTP 服務(wù)器,可以與所有您偏好的 HTTP 工具結(jié)合使用。

  除了圖像之外,有關(guān)緩存靜態(tài)數(shù)據(jù)的內(nèi)容,可講的內(nèi)容不多。由于我們的網(wǎng)站是一個(gè)慈善性質(zhì)的門戶網(wǎng)站,這意味著我們需要更多地關(guān)注用戶的感受,比如多加入一些圖像或視頻。但我們的 Web 服務(wù)器 Mongrel 并不能很好地服務(wù)靜態(tài)數(shù)據(jù),因此我們使用 Apache 來服務(wù)圖像內(nèi)容。

  我們現(xiàn)在正在著手轉(zhuǎn)向采用圖形加速器 Panther Express 來緩存最經(jīng)常被使用的圖像以使其能夠更快地被我們的客戶訪問到。要采取這種策略,我們將需要一個(gè)子域 images.changingThePresent.org。Panther Express 直接在圖像的本地緩存中提供圖像服務(wù),然后再向我們發(fā)送請求。由于 Panther 服務(wù)并不知道我們何時(shí)會更改圖像,所以我們使用 HTTP 報(bào)頭來使其到期失效,如下所示:

  HTTP 緩存失效報(bào)頭

  HTTP/1.1 200 OK

  Cache-Control: max-age=86400, must-revalidate

  Expires: Tues, 17 Apr 2007 11:43:51 GMT

  Last-Modified: Mon, 16 Apr 2007 11:43:51 GMT

  注意這些不是 HTML 報(bào)頭。它們與 Web 頁面內(nèi)容獨(dú)立構(gòu)建。Web 服務(wù)器將負(fù)責(zé)構(gòu)建這些 HTTP 報(bào)頭。像這樣一篇有關(guān) Rails 的文章系列若詳細(xì)介紹 Web 服務(wù)器配置,未免有點(diǎn)偏題,所以我將直接切入可用 Rails 框架進(jìn)行控制的緩存內(nèi)容這一主題(有關(guān) Web 服務(wù)器配置的更多內(nèi)容,請參見 參考資料 中的相關(guān)鏈接)。

  頁面緩存

  如果動態(tài)頁面不經(jīng)常更改,可以使用頁面級的緩存。比如,Blog 和公告牌使用的就是這種緩存。通過頁面緩存,Rails 就可以用來構(gòu)建動態(tài) HTML 頁,并將此頁存儲在公共目錄,這樣,應(yīng)用程序服務(wù)器就可以像服務(wù)其他靜態(tài)頁面一樣來服務(wù)這個(gè)動態(tài)頁。

  如果頁面已經(jīng)被緩存,那么就不需要引入 Rails,頁面緩存是 Rails 內(nèi)速度最快的一種緩存。在最底層,頁面緩存實(shí)際上在 Rails 中非常容易實(shí)現(xiàn)。頁面和分段緩存二者均在控制器級別發(fā)生。您需要告知 Rails 如下內(nèi)容:

  想要緩存哪些頁面?

  當(dāng)頁面內(nèi)容更改時(shí),您如何能在緩存中讓該頁面到期失效?

  可以通過在控制器類中使用 caches_page 指令來啟用頁面緩存。例如,若要在 about_us_controller 緩存 privacy_policy 和 user_agreement 頁面,可以輸入如下代碼:

  清單 2. 啟用頁面緩存

  class AboutController

  caches_page :privacy_policy, :user_agreement

  end

  讓頁面到期失效則可以通過 expire_page 指令來實(shí)現(xiàn)。若要在 Rails 調(diào)用 new_pages 動作時(shí)使上述頁面到期失效,可以使用如下代碼:

  清單 3. 使頁面失效

  class AboutController

  caches_page :privacy_policy, :user_agreement

  def new_pages

  expire_page :action => :privacy_policy

  expire_page :action => :user_agreement

  end

  end

  另外,有幾個(gè)小問題需要注意,比如 URL。URL 不能依賴于 URL 參數(shù)。例如,應(yīng)該使用 gifts/water/1 而非 gifts/water?page=1。在 routes.rb 中使用這類 URL 將非常容易。比如,我們的頁面中總是有一個(gè)選項(xiàng)卡參數(shù)用來顯示哪個(gè)選項(xiàng)卡被當(dāng)前選中。若要將此選項(xiàng)卡作為 URL 的一部分,我們會有如下的路由規(guī)則:

  清單 4. 選項(xiàng)卡的路由規(guī)則

  復(fù)制代碼 代碼如下:

  map.connect 'member/:id/:tab', :controller => 'profiles', :action => 'show'

  對于具有頁面參數(shù)的那些列表以及依賴于 URL 參數(shù)的其他頁面,也需要采用相同的做法。此外,還需要考慮安全性問題。

  如果頁面已經(jīng)在緩存內(nèi),那么就不會用到 Rails 框架,服務(wù)器并不能為您管理安全性。Web 服務(wù)器將更樂于在緩存內(nèi)呈現(xiàn)任何頁面,而不管用戶是否對其擁有查看的權(quán)限。所以,如果您很關(guān)心頁面可由誰查看,那么就不要使用頁面緩存。

  如果只是想緩存簡單的靜態(tài)頁面,那么了解上述內(nèi)容就應(yīng)該足夠了。只要內(nèi)容簡單,實(shí)現(xiàn)起來就不難。

  當(dāng)想要緩存更為復(fù)雜的內(nèi)容時(shí),就需要進(jìn)行一些權(quán)衡取舍了。由于想要緩存的頁面高度動態(tài),所以到期失效邏輯就會變得更加復(fù)雜。要處理復(fù)雜的到期失效邏輯,將需要編寫和配置定制清理器(sweeper)。在某些控制器擊發(fā)時(shí),這些類會從緩存內(nèi)刪除選定的元素。

  多數(shù)定制清理器都會觀察某些模型對象,并根據(jù)更改擊發(fā)邏輯來使一個(gè)或多個(gè)緩存頁面到期失效。清單 5 顯示了一種典型的緩存清理器。在此清理器中,開發(fā)人員可以定義一個(gè)活動記錄事件,比如 after_save。當(dāng)此事件擊發(fā)時(shí),清理器也會擊發(fā),并可讓緩存內(nèi)的特定頁面到期失效。這個(gè)事例所顯示的到期失效基于 expire_page 方法。而很多嚴(yán)格的應(yīng)用程序大都直接使用 Ruby 優(yōu)秀的文件系統(tǒng)實(shí)用工具來顯式地刪除所緩存的頁面。

  清單 5. 一個(gè)典型的觀察器

  class CauseController

  cache_sweeper :cause_sweeper

  ...

  class CauseSweeper

  observe Cause

  def after_save(record)

  expire_page(:controller => 'causes', :action => 'show',

  :id => record.id)

  cause.nonprofits.each do |nonprofit|

  expire_page(:controller => 'nonprofits', :action => 'show',

  :id => nonprofit.id)

  end

  end

  end

  現(xiàn)在,您可能會開始感覺到頁面緩存的些許缺點(diǎn)了:復(fù)雜性。您雖然可以很好地進(jìn)行頁面級的緩存,但固有的復(fù)雜性卻讓應(yīng)用程序很難測試,進(jìn)而會增加系統(tǒng)內(nèi)出現(xiàn) bug 的可能性。而且,如果頁面針對每個(gè)用戶都會有所不同,或者希望緩存進(jìn)行過身份驗(yàn)證的頁面,那么將需要使用頁面緩存之外的方式。對于 ChangingThePresent,我們必須處理兩種情況,原因是我們必須基于用戶是否登錄來更改基本布局上的鏈接。對于大多數(shù)頁面,我們甚至都不會考慮使用頁面級緩存。為了讓您能夠深入了解頁面級的緩存,在本文的 參考資料 部分,我特意給出了到一系列有關(guān)頁面級緩存的優(yōu)秀文章的鏈接。接下來,將來深入探究另一種形式的整頁緩存 —— 動作緩存。

  動作緩存

  至此,您已經(jīng)了解了頁面緩存的主要的優(yōu)勢及主要的缺點(diǎn):對于多數(shù)頁面檢索而言,根本無需考慮使用 Rails。頁面緩存的優(yōu)勢是速度快。缺點(diǎn)是缺少靈活性。如果想要基于應(yīng)用程序內(nèi)的條件 — 例如,身份認(rèn)證 — 來緩存整個(gè)頁面,那么可以使用動作緩存。

  動作緩存與頁面緩存的工作方式大體相同,但在流程上稍有差別。Rails 在呈現(xiàn)動作前會實(shí)際調(diào)用控制器。如果由該動作呈現(xiàn)的頁面已經(jīng)存在于緩存內(nèi),那么 Rails 就會在緩存內(nèi)呈現(xiàn)頁面而不是重新加以呈現(xiàn)。由于現(xiàn)在使用了 Rails,因此動作緩存的速度要比頁面緩存慢一些,但其優(yōu)點(diǎn)還是很明顯的。幾乎所有的 Rails 認(rèn)證模式都會在控制器上使用 before 過濾器。動作緩存讓您能夠利用認(rèn)證及控制器上的任何過濾器。

  從語句構(gòu)成的角度來看,動作緩存與頁面緩存也應(yīng)該十分類似,只有指令不太一樣。清單 6 顯示了如何使用 caches_action 指令。

  清單 6. 啟用動作緩存

  class AboutController

  caches_action :secret_page, :secret_list

  end

  緩存到期失效以及清理器的工作方式也應(yīng)該相同。我們不使用動作緩存的原因與我們不使用頁面緩存的原因是一樣的,但分段緩存對我們來說更重要一些。

  緩存頁面分段

  借助部分緩存,可以緩存頁面的一部分,所緩存的內(nèi)容很多時(shí)候都是布局之類的。要使用分段緩存,開發(fā)人員需要先確定分段,方法是通過在 Web 頁面上直接放上 rhtml 指令來包圍一塊內(nèi)容,如清單 7 所示。在 ChangingThePresent.org 上,我們使用分段緩存來緩存首頁和其他的幾頁。所有的這些頁均使用了數(shù)據(jù)庫密集訪問而且大都是我們最受歡迎的頁面。

  清單 7. 確定緩存分段

  

  

?

?

  Here, you can make the world a better place with a single gift. Donation gifts

  are also a wonderful way to honor friends and family. Just imagine what we

  can achieve together.

  

?

  

?

?

  

?

  

   'gifts/listable', :locals => { :gift => gift } %>

  

  

?

  ...

  

  在清單 7 中,cache 幫助程序標(biāo)識所要緩存的分區(qū)。第一個(gè)參數(shù)是標(biāo)識此緩存分區(qū)的惟一名稱。第二個(gè)參數(shù)包含代碼塊 — 即第一個(gè) do 和最后一個(gè) end 之間的代碼 — 此代碼塊準(zhǔn)確地確定了要緩存的 RHTML 分區(qū)。

  我們的網(wǎng)站只有一個(gè)主頁,所以命名這個(gè)頁面非常容易。在其他地方,我們使用一種特定的方法來決定此網(wǎng)頁的 URL 以便惟一標(biāo)識緩存分段。例如,當(dāng)我們?yōu)樘囟ǖ膬?nèi)容(比如世界和平或減少貧困)而進(jìn)行代碼緩存時(shí),我們需要使用清單 8 中的代碼。代碼會為之尋找永久 url,也稱為 permalink。

  清單 8. 通過 URL 標(biāo)識緩存分段

  

  通常,當(dāng)緩存單獨(dú)頁面時(shí),需要用清理器使之過期失效。有時(shí),使用簡單的基于時(shí)間的對象過期更為容易和簡潔。默認(rèn)地,Rails 并不提供這類機(jī)制,但有一種插件名為 timed_fragment_cache 可以實(shí)現(xiàn)這一目的。借助這個(gè)插件,我可以指定超時(shí),可以在緩存了的內(nèi)容中指定,也可以在為此頁提供了動態(tài)數(shù)據(jù)的控制器代碼中指定。例如,清單 9 所示的代碼就可以為此頁面構(gòu)建動態(tài)數(shù)據(jù)。when_fragment_expired 方法只有在相關(guān)的緩存分段過期時(shí)才會執(zhí)行。此方法接受參數(shù),用來指定超時(shí)的時(shí)長,它還接受一個(gè)代碼塊,用來指定當(dāng)內(nèi)容過期時(shí)哪些內(nèi)容需要重建。我也可以選擇在 rhtml 頁面中指定超時(shí)和緩存方法,但我更愿意使用基于控制器的方法。

  清單 9. 基于時(shí)間的緩存到期

  def index

  when_fragment_expired 'causes_list', 15.minutes.from_now do

  @causes = Cause.find_all_ordered

  end

  end

  如果能夠容忍數(shù)據(jù)稍微有些陳舊,那么使用定時(shí)的到期機(jī)制將可以極大地簡化緩存策略。對于每個(gè)被緩存的元素,只需指定想要緩存的內(nèi)容、可生成動態(tài)內(nèi)容的任何控制器動作以及超時(shí)。與頁面緩存類似,如果需要,也可以使用 expire_fragment :controller => controller, :action => action, :id => id 方法顯式讓內(nèi)容到期。此方法的工作方式與緩存動作和緩存頁面的到期失效是一樣的。接下來,我將介紹如何配置此后端。

  Memcached

  至此為止,我已經(jīng)介紹了 Ruby on Rails 的頁面和分段緩存模型。看過了 API 之后,現(xiàn)在就可以定義緩存后的數(shù)據(jù)的去處了。默認(rèn)地,Rails 將把緩存后的頁面放入文件系統(tǒng)。緩存后的頁面和動作都會進(jìn)入公共目錄。可以配置緩存后的分段的存儲位置。為此,需要用到內(nèi)存存儲、文件系統(tǒng)(在所定義的目錄)、數(shù)據(jù)庫或稱為 memcached 的服務(wù)。對于 ChangingThePresent.org,我們使用 memcached。

  可以將 Memcached 想象為一個(gè)大型的 hash 圖,這個(gè)圖可通過網(wǎng)絡(luò)獲得。基于內(nèi)存的緩存速度快,而基于網(wǎng)絡(luò)的緩存的可伸縮性比較好。有了插件支持,Rails 就可使用 memcached 來緩存分段和 ActiveRecord 模型。要使用它,需要安裝 memcached(更多信息,請參看 參考資料)并在 environment.rb(或其他的環(huán)境配置文件,比如 production.rb)對它進(jìn)行配置。

  清單 10. 配置緩存

  config.action_controller.perform_caching = true

  memcache_options = {

  :c_threshold => 10_000,

  :compression => false,

  :debug => false,

  :readonly => false,

  :urlencode => false,

  :ttl => 300,

  :namespace => 'igprod',

  :disabled => false

  }

  CACHE = MemCache.new memcache_options

  清單 10 顯示了一種典型的配置,其中第一行 config.action_controller.perform_caching = true 將啟用緩存。接下來的一行將準(zhǔn)備緩存選項(xiàng)。注意,這里的諸多選項(xiàng)是為了讓您可以獲得更多的調(diào)試數(shù)據(jù)、禁用緩存和定義該緩存的名稱空間。在 參考資料 部分給出的 memcached 站點(diǎn)可以找到有關(guān)配置選項(xiàng)的更多信息。

  模型緩存

  我們使用的最后一種緩存是基于模型的緩存。我們使用的是稱為 CachedModel 的緩存插件的一種定制版本。模型緩存實(shí)際上是一種有限形式的數(shù)據(jù)庫緩存。緩存很容易按模型啟用。

  要想讓模型使用緩存解決方案,只需擴(kuò)展 CachedModel 類,而非擴(kuò)展 ActiveRecord,如清單 11 所示。 CachedModel 擴(kuò)展 ActiveRecord::Base。ActiveRecord 并非全對象關(guān)系型映射層。此框架極大地依賴于 SQL 來執(zhí)行復(fù)雜的特性,而且如果需要,用戶可以很容易降至 SQL。直接使用 SQL 會使緩存出問題,因?yàn)榫彺鎸颖仨毺幚硗暾慕Y(jié)果集,而不是單獨(dú)一個(gè)數(shù)據(jù)庫行。處理完整的結(jié)果集常常會問題不斷,而且如果沒有支持應(yīng)用程序的深層邏輯,這幾乎不太可能。正由于這個(gè)原因,CachedModel 的焦點(diǎn)才會放到緩存單個(gè)模型對象上,并只加速返回單行結(jié)果的查詢。

  清單 11. 使用 CachedModel

  Class Cause

  大多數(shù) Rails 應(yīng)用程序都會重復(fù)訪問多個(gè)條目,例如用戶對象。模型緩存在很多情況下都可以明顯地使速度加快。對于 ChangingThePresent,我們剛剛開始加速基于模型的緩存。

  結(jié)束語

  Ruby 雖然是一門生產(chǎn)率極高的語言,但若從性能角度考慮,該語言解釋性的特性讓它并不那么理想。大多數(shù)主要的 Rails 應(yīng)用程序都將會通過有效利用緩存來彌補(bǔ)某些不足。對于 ChangingThePresent.org,我們主要使用分段緩存,并通過控制器使用基于時(shí)間的方法來使緩存分段到期失效。這種方式很適合我們的網(wǎng)站,即使其中有一些頁面會基于登錄進(jìn)來的用戶有所變化。

  我們還研究了使用受 memcached 支撐的 CachedModel 類所能帶來的影響。雖然我們的研究還僅限于緩存對數(shù)據(jù)庫性能所造成的影響,但早期的結(jié)果還是很有希望的。在 下一篇 文章中,我將介紹一些實(shí)用技巧,您可以使用這些技巧來為另一個(gè)真實(shí)世界中的 Rails 示例進(jìn)行數(shù)據(jù)庫優(yōu)化。

  以上就是Ruby on Rails中緩存機(jī)制的深度解析了,想必都了解了吧,更多相關(guān)內(nèi)容請繼續(xù)關(guān)注武林技術(shù)頻道。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 蜜桃免费视频 | 欧美午夜理伦三级在线观看 | 国产综合亚洲精品一区二 | 欧美一区二区视频免费观看 | 欧美同性三人交 | 亚洲人成在线观看 | 嫩草影院懂你的 | 亚洲视频一区二区三区 | 性视频网站免费 | av在线免费观看一区二区 | 成年人在线观看 | 欧美久久久久久 | 五月激情综合 | 欧美日韩中文字幕 | 91高清免费看 | 午夜精品一区二区三区在线观看 | 97视频在线免费观看 | 超碰在线看 | 伊人网在线视频 | 亚洲精品久久久久avwww潮水 | 毛片a片 | 成人午夜精品一区二区三区 | 无码少妇一区二区三区 | 在线看欧美| 久久com| 亚洲精品中文字幕 | 国产性×xxx盗摄xxxx | www.伊人 | 成人av电影免费观看 | 一级免费视频 | aⅴ色国产 欧美 | 黄色电影在线免费看 | 久久久91精品国产一区二区三区 | 精品久久久免费视频 | 国产精品成人一区二区三区夜夜夜 | av香港经典三级级 在线 | 国产精品久久久999 日本在线免费观看 | 欧美精品区| 久久国产精品视频 | 九一免费国产 | 羞羞av在线|