亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Ruby > 正文

深入理解Ruby on Rails中的緩存機制

2020-10-29 19:40:46
字體:
來源:轉載
供稿:網友

幾個場景

首先,讓我先來帶您瀏覽幾個 ChangingThePresent.org 中的頁面吧。我將顯示站點中幾個需要緩存的地方。然后,再指出我們為其中每個地方所做出的選擇以及為實現這些頁面所使用的代碼或策略。尤其會重點討論如下內容:

  •     全靜態頁面
  •     幾乎無變化的全動態的頁面
  •     動態頁面片段
  •     應用程序數據

先來看看靜態頁面。幾乎每個站點都會有靜態頁面,如圖 1 所示,其中還有我們的條款和條件。可以通過單擊 register 然后再選擇是否接受用戶協議來瀏覽相應頁面。對于 ChangingThePresent 而言,我們從此頁中刪除了所有動態內容以便 Apache 能夠對它進行緩存。按照我們 Apache 中配置的規則,這些內容永遠都不會由 Rails 服務器生成。因此,我根本無需對其考慮 Rails 緩存。
圖 1. 用戶協議

2015422163759311.jpg (402×341)

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

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

2015422163836768.jpg (572×433)

 最后再考慮應用程序。除非是在 15 年之前進行網絡沖浪,否則您現在遇到的有趣站點全部都是動態的。現代的應用程序大都分層,而且可以通過在層間添加緩存來使這些分層更加有效。ChangingThePresent 在數據庫層采用了一些緩存。接下來,我將深入討論不同類型的緩存,還會介紹我們為 ChangingThePresent 都采用了何種緩存。
緩存靜態內容

Mongrel 是一種 Web 服務器,由 Zed Shaw 利用 2500 行 Ruby 和 C 編寫而成。這個小型的服務器占用內存極少,非常適合 Ruby Web 應用程序,例如 Rails、Nitro、Iowa 等等。Mongrel 可運行于 UNIX? 和 Linux? 上,也可運行在 Win32 上。Mongrel 也經??梢宰鳛榇磉\行在另一個 Web 服務器(例如 Apache 或 Litespeed)的后端,但這不是必需的 ―― 因為 Mongrel 是一種 HTTP 服務器,可以與所有您偏好的 HTTP 工具結合使用。

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

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

HTTP/1.1 200 OKCache-Control: max-age=86400, must-revalidateExpires: Tues, 17 Apr 2007 11:43:51 GMTLast-Modified: Mon, 16 Apr 2007 11:43:51 GMT

注意這些不是 HTML 報頭。它們與 Web 頁面內容獨立構建。Web 服務器將負責構建這些 HTTP 報頭。像這樣一篇有關 Rails 的文章系列若詳細介紹 Web 服務器配置,未免有點偏題,所以我將直接切入可用 Rails 框架進行控制的緩存內容這一主題(有關 Web 服務器配置的更多內容,請參見 參考資料 中的相關鏈接)。
頁面緩存

如果動態頁面不經常更改,可以使用頁面級的緩存。比如,Blog 和公告牌使用的就是這種緩存。通過頁面緩存,Rails 就可以用來構建動態 HTML 頁,并將此頁存儲在公共目錄,這樣,應用程序服務器就可以像服務其他靜態頁面一樣來服務這個動態頁。

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

  •     想要緩存哪些頁面?
  •     當頁面內容更改時,您如何能在緩存中讓該頁面到期失效?

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

class AboutController < ApplicationController caches_page :privacy_policy, :user_agreement end

讓頁面到期失效則可以通過 expire_page 指令來實現。若要在 Rails 調用 new_pages 動作時使上述頁面到期失效,可以使用如下代碼:
清單 3. 使頁面失效

class AboutController < ApplicationController caches_page :privacy_policy, :user_agreement   def new_pages  expire_page :action => :privacy_policy  expire_page :action => :user_agreement end end

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

復制代碼 代碼如下:
map.connect 'member/:id/:tab', :controller => 'profiles', :action => 'show'

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

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

如果只是想緩存簡單的靜態頁面,那么了解上述內容就應該足夠了。只要內容簡單,實現起來就不難。

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

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

class CauseController < ApplicationController  cache_sweeper :cause_sweeper...class CauseSweeper < ActionController::Caching::Sweeper 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  endend

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

至此,您已經了解了頁面緩存的主要的優勢及主要的缺點:對于多數頁面檢索而言,根本無需考慮使用 Rails。頁面緩存的優勢是速度快。缺點是缺少靈活性。如果想要基于應用程序內的條件 ― 例如,身份認證 ― 來緩存整個頁面,那么可以使用動作緩存。

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

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

  class AboutController < ApplicationController   caches_action :secret_page, :secret_list   end

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

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

<% cache 'gifts_index' do %>  <h3>   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.  </h3>  <h2 class="lightBlue"><%= @event_title %></h2>  <div id="homefeatureitems">    <% for gift in @event_gifts %>     <%= render :partial => 'gifts/listable', :locals => { :gift => gift } %>    <% end %>  </div>  ...<% end %>

在清單 7 中,cache 幫助程序標識所要緩存的分區。第一個參數是標識此緩存分區的惟一名稱。第二個參數包含代碼塊 ― 即第一個 do 和最后一個 end 之間的代碼 ― 此代碼塊準確地確定了要緩存的 RHTML 分區。

我們的網站只有一個主頁,所以命名這個頁面非常容易。在其他地方,我們使用一種特定的方法來決定此網頁的 URL 以便惟一標識緩存分段。例如,當我們為特定的內容(比如世界和平或減少貧困)而進行代碼緩存時,我們需要使用清單 8 中的代碼。代碼會為之尋找永久 url,也稱為 permalink。
清單 8. 通過 URL 標識緩存分段

<% cache @cause.permalink(params[:id]) do %>

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

def index when_fragment_expired 'causes_list', 15.minutes.from_now do   @causes = Cause.find_all_ordered endend

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

至此為止,我已經介紹了 Ruby on Rails 的頁面和分段緩存模型??催^了 API 之后,現在就可以定義緩存后的數據的去處了。默認地,Rails 將把緩存后的頁面放入文件系統。緩存后的頁面和動作都會進入公共目錄??梢耘渲镁彺婧蟮姆侄蔚拇鎯ξ恢?。為此,需要用到內存存儲、文件系統(在所定義的目錄)、數據庫或稱為 memcached 的服務。對于 ChangingThePresent.org,我們使用 memcached。

可以將 Memcached 想象為一個大型的 hash 圖,這個圖可通過網絡獲得?;趦却娴木彺嫠俣瓤欤诰W絡的緩存的可伸縮性比較好。有了插件支持,Rails 就可使用 memcached 來緩存分段和 ActiveRecord 模型。要使用它,需要安裝 memcached(更多信息,請參看 參考資料)并在 environment.rb(或其他的環境配置文件,比如 production.rb)對它進行配置。
清單 10. 配置緩存

config.action_controller.perform_caching = truememcache_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 將啟用緩存。接下來的一行將準備緩存選項。注意,這里的諸多選項是為了讓您可以獲得更多的調試數據、禁用緩存和定義該緩存的名稱空間。在 參考資料 部分給出的 memcached 站點可以找到有關配置選項的更多信息。
模型緩存

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

要想讓模型使用緩存解決方案,只需擴展 CachedModel 類,而非擴展 ActiveRecord,如清單 11 所示。 CachedModel 擴展 ActiveRecord::Base。ActiveRecord 并非全對象關系型映射層。此框架極大地依賴于 SQL 來執行復雜的特性,而且如果需要,用戶可以很容易降至 SQL。直接使用 SQL 會使緩存出問題,因為緩存層必須處理完整的結果集,而不是單獨一個數據庫行。處理完整的結果集常常會問題不斷,而且如果沒有支持應用程序的深層邏輯,這幾乎不太可能。正由于這個原因,CachedModel 的焦點才會放到緩存單個模型對象上,并只加速返回單行結果的查詢。
清單 11. 使用 CachedModel

Class Cause < CachedModel

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

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

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91国产一区在线| 日本高清不卡在线| 97国产一区二区精品久久呦| 欧美性xxxx在线播放| 97国产成人精品视频| 26uuu亚洲伊人春色| 国产福利精品av综合导导航| 久久天天躁狠狠躁夜夜躁2014| 亚洲在线视频观看| 草民午夜欧美限制a级福利片| 日韩午夜在线视频| 国产精品偷伦免费视频观看的| 91tv亚洲精品香蕉国产一区7ujn| 国产精品自产拍在线观看中文| 国产精品嫩草视频| 亚洲伊人成综合成人网| 欧美成人激情视频| 日韩欧美高清在线视频| 欧美亚洲视频在线看网址| 日韩av免费观影| 久久这里只有精品视频首页| 亚洲永久在线观看| 麻豆乱码国产一区二区三区| 欧美日韩亚洲精品内裤| 中文字幕日韩有码| 欧美在线视频一区| 国产精品久久久久久久久免费| 欧美高清在线视频观看不卡| 欧美日韩xxx| 成人免费视频网| 俺去亚洲欧洲欧美日韩| 中文字幕日韩精品在线| 欧美日韩在线观看视频小说| www.亚洲成人| 国产婷婷成人久久av免费高清| 欧美黑人一级爽快片淫片高清| 亚洲欧美激情另类校园| 影音先锋日韩有码| 日韩精品视频观看| 久久色免费在线视频| 97在线看免费观看视频在线观看| 国产精品视频成人| 国产91在线高潮白浆在线观看| 性夜试看影院91社区| 亚洲一区二区三区四区视频| 国产精品久久久av久久久| 日本高清视频一区| 欧美亚洲伦理www| 久久精品国产96久久久香蕉| 亚洲人午夜精品免费| 91视频-88av| 日韩欧美国产黄色| 亚洲激情视频在线| 欧美老妇交乱视频| 91九色在线视频| 欧美电影院免费观看| 国内精品久久久| 午夜精品久久17c| 亚洲自拍偷拍网址| 中文字幕亚洲一区二区三区五十路| 欧美怡春院一区二区三区| 91产国在线观看动作片喷水| 国产精品爱久久久久久久| 日韩美女主播视频| 久久免费视频在线| 久久久999国产精品| 91成品人片a无限观看| 91久久久久久久一区二区| 欧美激情日韩图片| 精品亚洲一区二区三区在线播放| 亚洲欧洲美洲在线综合| 久久99青青精品免费观看| 久久精品国产久精国产一老狼| 成人免费视频在线观看超级碰| 亚洲人成毛片在线播放| 国产精品久久久久久av福利| 2019av中文字幕| 欧美成人免费一级人片100| 日韩av在线高清| 色婷婷久久一区二区| 国内精品中文字幕| 国产精品专区一| 久久久久久久久综合| 日韩av免费在线播放| 亚洲a在线播放| 亚洲精品福利视频| 中文字幕国内精品| 岛国av一区二区三区| 亚洲一区二区三区香蕉| 97涩涩爰在线观看亚洲| 成人精品视频在线| 色偷偷综合社区| 少妇av一区二区三区| 成人在线观看视频网站| 国产在线视频2019最新视频| 精品日韩美女的视频高清| 一区二区三区美女xx视频| 成人疯狂猛交xxx| 久久影院中文字幕| 欧美激情精品久久久久久蜜臀| 国内外成人免费激情在线视频| 欧美大人香蕉在线| 亚洲一区二区三区视频| 中文字幕亚洲欧美日韩在线不卡| 欧美激情性做爰免费视频| 国产精品视频永久免费播放| 91在线观看免费高清| 91九色在线视频| 亚洲黄色片网站| 久久精品一偷一偷国产| 不卡av电影在线观看| 欧美日本啪啪无遮挡网站| 日韩成人av网址| 久久国内精品一国内精品| 奇米4444一区二区三区| 成人免费在线网址| 国内伊人久久久久久网站视频| 欧美成人免费观看| 精品久久久久久久久久| 日韩av男人的天堂| 色无极亚洲影院| 欧美成人免费一级人片100| 欧美另类极品videosbest最新版本| 97**国产露脸精品国产| 亚洲一区二区三区久久| 欧美高清视频一区二区| 亚洲成人精品视频在线观看| 亚洲视频免费一区| 欧美一级淫片videoshd| 中文字幕久热精品视频在线| 2019中文字幕全在线观看| 色偷偷av一区二区三区乱| 亚洲午夜色婷婷在线| 69av在线视频| 日韩成人在线免费观看| 亚洲一区二区自拍| 国产视频观看一区| 高清欧美一区二区三区| 日av在线播放中文不卡| 午夜精品一区二区三区在线播放| 欧美小视频在线| 欧美孕妇孕交黑巨大网站| 91色中文字幕| 欧美视频不卡中文| 国产精品久久99久久| 日韩一区在线视频| 国产97在线|亚洲| 国产免费一区二区三区在线观看| 日韩综合视频在线观看| 久久成人av网站| 茄子视频成人在线| 欧美亚洲视频在线观看| 国产成人av网址| 亚洲欧美精品suv| 亚洲精品国精品久久99热| 国产精品福利片| 综合久久五月天| 91视频免费网站| 伊人伊成久久人综合网站| 欧美精品午夜视频| 国产精品国产三级国产专播精品人| 久久亚洲精品一区二区| 日韩av在线不卡| 久久av在线看|