在前端開發中,性能一直都是被大家所重視的一點,然而判斷一個網站的性能最直觀的就是看網頁打開的速度。 其中提高網頁反應速度的一個方式就是使用緩存 。緩存技術一直一來在WEB技術體系中扮演非常重要角色,是快速且有效地提升性能的手段。
一個優秀的緩存策略可以縮短網頁請求資源的距離,減少延遲,並且由於緩存文件可以重復利用,還可以減少帶寬,降低網路負荷。
所以,緩存技術是無數WEB開發從業人員在工作過程中不可避免的一大問題。 在產品開發的時候我們總是想辦法避免緩存產生,而在產品發布之時又在想策略管理緩存提升網頁的訪問速度 。了解瀏覽器的緩存命中原理,是開發WEB應用的基礎,本文著眼於此,學習瀏覽器緩存的相關知識,總結緩存避免和緩存管理的方法,結合具體的場景說明緩存的相關問題。希望能對有需要的人有所幫助。
在實際WEB開發過程中,緩存技術會涉及到不同層、不同端,比如:用戶層、系統層、代理層、前端、後端、服務端等, 每一層的緩存目標都是一致的,就是盡快返回請求數據、減少延遲 ,但每層使用的技術實現是各有不同,面對不同層、不同端的優劣,選用不同的技術來提升系統響應效率。所以,我們首先看下各層的緩存都有哪些技術,都緩存哪些數據,從整體上,對WEB的緩存技術進行了解,如下圖所示:
本篇文章重點講的就是上面紅色框部分緩存內容。
當瀏覽器請求一個網站的時候,會載入各種各樣的資源,比如:HTML文檔、圖片、CSS和JS等文件。對於一些不經常變的內容,瀏覽器會將他們保存在本地的文件中,下次訪問相同網站的時候,直接載入這些資源,加速訪問。
那麼如何知曉瀏覽器是讀取了緩存還是直接請求伺服器?如下圖網站來做個示例:
第一次打開該網站後,如果再次刷新頁面。會發現瀏覽器載入的眾多資源中,有一部分size有具體數值,然而還有一部分請求,比如圖片、css和js等文件並沒有顯示文件大小,而是顯示了 from dis cache 或者 from memory cache 字樣。這就說明了,該資源直接從本地硬碟或者瀏覽器內存讀取,而並沒有請求伺服器。
瀏覽器啟用緩存至少有兩點顯而易見的好處: (1)減少頁面載入時間;(2)減少伺服器負載;
瀏覽器是否使用緩存、緩存多久,是由伺服器控制的 。准確來說,當瀏覽器請求一個網頁(或者其他資源)時, 伺服器發回的響應的「響應頭」部分的某些欄位指明了有關緩存的關鍵信息 。下面看下,HTTP報文中與緩存相關的首部欄位:
根據上面四種類型的首部欄位不同使用策略, 瀏覽器中緩存可分為強緩存和協商緩存 :
當瀏覽器對某個資源的請求命中了強緩存時, 返回的HTTP狀態為200 ,在chrome的開發者工具的network裡面 size會顯示為from cache ,比如:京東的首頁里就有很多靜態資源配置了強緩存,用chrome打開幾次,再用f12查看network,可以看到有不少請求就是從緩存中載入的:
Expires是HTTP 1.0提出的一個表示資源過期時間的header,它描述的是一個絕對時間,由伺服器返回,用GMT格式的字元串表示 ,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT,包含了Expires頭標簽的文件,就說明瀏覽器對於該文件緩存具有非常大的控制權。
例如,一個文件的Expires值是2020年的1月1日,那麼就代表,在2020年1月1日之前,瀏覽器都可以直接使用該文件的本地緩存文件,而不必去伺服器再次請求該文件,哪怕伺服器文件發生了變化。
所以, Expires是優化中最理想的情況,因為它根本不會產生請求 ,所以後端也就無需考慮查詢快慢。它的緩存原理,如下:
Expires是較老的強緩存管理header, 由於它是伺服器返回的一個絕對時間 ,在伺服器時間與客戶端時間相差較大時,緩存管理容易出現問題, 比如:隨意修改下客戶端時間,就能影響緩存命中的結果 。所以在HTTP 1.1的時候,提出了一個新的header, 就是Cache-Control,這是一個相對時間,在配置緩存的時候,以秒為單位,用數值表示 ,如:Cache-Control:max-age=315360000,它的緩存原理是:
Cache-Control描述的是一個相對時間 ,在進行緩存命中的時候, 都是利用客戶端時間進行判斷 ,所以相比較Expires,Cache-Control的緩存管理更有效,安全一些。
這兩個header可以只啟用一個,也可以同時啟用, 當response header中,Expires和Cache-Control同時存在時,Cache-Control優先順序高於Expires :
此外,還可以為 Cache-Control 指定 public 或 private 標記。 如果使用 private,則表示該資源僅僅屬於發出請求的最終用戶,這將禁止中間伺服器(如代理伺服器)緩存此類資源 。對於包含用戶個人信息的文件(如一個包含用戶名的 HTML 文檔),可以設置 private,一方面由於這些緩存對其他用戶來說沒有任何意義,另一方面用戶可能不希望相關文件儲存在不受信任的伺服器上。需要指出的是,private 並不會使得緩存更加安全,它同樣會傳給中間伺服器(如果網站對於傳輸的安全性要求很高,應該使用傳輸層安全措施)。 對於 public,則允許所有伺服器緩存該資源 。通常情況下,對於所有人都可以訪問的資源(例如網站的 logo、圖片、腳本等), Cache-Control 默認設為 public 是合理的 。
當瀏覽器對某個資源的請求沒有命中強緩存, 就會發一個請求到伺服器,驗證協商緩存是否命中,如果協商緩存命中,請求響應返回的http狀態為304並且會顯示一個Not Modified的字元串 ,比如你打開京東的首頁,按f12打開開發者工具,再按f5刷新頁面,查看network,可以看到有不少請求就是命中了協商緩存的:
查看單個請求的Response Header, 也能看到304的狀態碼和Not Modified的字元串,只要看到這個就可說明這個資源是命中了協商緩存,然後從客戶端緩存中載入的 ,而不是伺服器最新的資源:
【Last-Modified,If-Modified-Since】的控制緩存的原理,如下 :
【Last-Modified,If-Modified-Since】都是根據伺服器時間返回的header,一般來說, 在沒有調整伺服器時間和篡改客戶端緩存的情況下,這兩個header配合起來管理協商緩存是非常可靠的,但是有時候也會伺服器上資源其實有變化,但是最後修改時間卻沒有變化的情況 ,而這種問題又很不容易被定位出來,而當這種情況出現的時候,就會影響協商緩存的可靠性。 所以就有了另外一對header來管理協商緩存,這對header就是【ETag、If-None-Match】 。它們的緩存管理的方式是:
Etag和Last-Modified非常相似,都是用來判斷一個參數,從而決定是否啟用緩存。 但是ETag相對於Last-Modified也有其優勢,可以更加准確的判斷文件內容是否被修改 ,從而在實際操作中實用程度也更高。
協商緩存跟強緩存不一樣,強緩存不發請求到伺服器, 所以有時候資源更新了瀏覽器還不知道,但是協商緩存會發請求到伺服器 ,所以資源是否更新,伺服器肯定知道。大部分web伺服器都默認開啟協商緩存,而且是同時啟用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】,比如apache:
如果沒有協商緩存,每個到伺服器的請求,就都得返回資源內容,這樣伺服器的性能會極差。
【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】一般都是同時啟用,這是為了處理Last-Modified不可靠的情況。有一種場景需要注意:
比如,京東頁面的資源請求,返回的repsonse header就只有Last-Modified,沒有ETag:
協商緩存需要配合強緩存使用,上面這個截圖中,除了Last-Modified這個header,還有強緩存的相關header, 因為如果不啟用強緩存的話,協商緩存根本沒有意義 。
如果資源已經被瀏覽器緩存下來,在緩存失效之前,再次請求時,默認會先檢查是否命中強緩存,如果強緩存命中則直接讀取緩存,如果強緩存沒有命中則發請求到伺服器檢查是否命中協商緩存,如果協商緩存命中,則告訴瀏覽器還是可以從緩存讀取,否則才從伺服器返回最新的資源。其瀏覽器判斷緩存的詳細流程圖,如下:
『貳』 JAVA目前比較常用的緩存有哪些 集中式緩存與分布式緩存有何區別 它們應用場景是
java目前常用的緩存:
Generic
JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, etc)
EhCache 2.x
Hazelcast
Infinispan
Couchbase
Redis
Caffeine
Guava (deprecated)
Simple
建議使用spring boot集成方式,可插拔,簡單。
集中式緩存適用場景:
1、伺服器集群部署。
2、數據高一致性(任何數據變化都能及時的被查詢到)
分布式緩存適用場景:
系統需要緩存的數據量大
對數據的可用性較高的情況
需要橫向擴展,從而達到緩存的容量無限的要求
『叄』 緩存系統中的主要使用的數據結構是什麼
緩存系統中的主要使用的數據結構是memcached。
memcached是一套分布式的高速緩存系統,由LiveJournal的Brad Fitzpatrick開發,但被許多網站使用。這是一套開放源代碼軟體,以BSD license授權發布。
memcached的API使用三十二比特的循環冗餘校驗(CRC-32)計算鍵值後,將數據分散在不同的機器上。當表格滿了以後,接下來新增的數據會以LRU機制替換掉。
由於memcached通常只是當作緩存系統使用,所以使用memcached的應用程序在寫回較慢的系統時(像是後端的資料庫)需要額外的代碼更新memcached內的數據。
(3)分布式場景協商緩存使用擴展閱讀:
一、存儲方式
為了提高性能,memcached中保存的數據都存儲在memcached內置的內存存儲空間中。由於數據僅存在於內存中,因此重啟memcached、重啟操作系統會導致全部數據消失。
另外,內容容量達到指定值之後,就基於LRU(Least Recently Used)演算法自動刪除不使用的緩存。memcached本身是為緩存而設計的伺服器,因此並沒有過多考慮數據的永久性問題。
二、通信分布式
memcached盡管是「分布式」緩存伺服器,但伺服器端並沒有分布式功能。各個memcached不會互相通信以共享信息。那麼,怎樣進行分布式呢?這完全取決於客戶端的實現。本文也將介紹memcached的分布式。
『肆』 EhCache 分布式緩存/緩存集群
一 緩存系統簡介 EhCache 是一個純 Java 的進程內緩存框架 具有快速 精乾等特點 是 Hibernate 中默認的 CacheProvider EhCache 應用架構圖 下圖是 EhCache 在應用程序中的位置
EhCache 的主要特性有 快速 精幹 簡單 多種緩存策略 緩存數據有兩級 內存和磁碟 因此無需擔心容量問題 緩存數據會在虛擬機重啟的過程中寫入磁碟 可以通過 RMI 可插入 API 等方式進行分布式緩存 具有緩存和緩存管理器的偵聽介面 支持多緩存管理器實例 以及一個實例的多個緩存區域 提供 Hibernate 的緩存實現 由於 EhCache 是進程中的緩存系統 一旦將應用部署在集群環境中 每一個節點維護各自的緩存數據 當某個節點對緩存數據進行更新 這些更新的數據無法在其它節點 *** 享 這不僅會降低節點運行的效率 而且會導致數據不同步的情況發生 例如某個網站採用 A B 兩個節點作為集群部署 當 A 節點的緩存更新後 而 B 節點緩存尚未更新就可能出現用戶在瀏覽頁面的時候 一會是更新後的數據 一會是尚未更新的數據 盡管我們也可以通過 Session Sticky 技術來將用戶鎖定在某個節點上 但對於一些交互性比較強或者是非 Web 方式的系統來說 Session Sticky 顯然不太適合 所以就需要用到 EhCache 的集群解決方案 從 版本開始 Ehcache可以使用分布式的緩存了 EhCache 從 版本開始 支持五種集群方案 分別是 ? Terracotta ? RMI ? JMS ? JGroups ? EhCache Server 其中的三種最為常用集群方式 分別是 RMI JGroups 以及 EhCache Server 本文主要介紹RMI的方式 分布式這個特性是以plugin的方式實現的 Ehcache自帶了一些默認的分布式緩存插件實現 這些插件可以滿足大部分應用的需要 如果需要使用其他的插件那就需要自己開發了 開發者可以通過查看distribution包里的源代碼及JavaDoc來實現它 盡管不是必須的 在使用分布式緩存時理解一些ehcahce的設計思想也是有幫助的 這可以參看分布式緩存設計的頁面 以下的部分將展示如何讓分布式插件同ehcache一起工作 下面列出的是一些分布式緩存中比較重要的方面 ? 你如何知道集群環境中的其他緩存? ? 分布式傳送的消息是什麼形式? ? 什麼情況需要進行復制?增加(Puts) 更新(Updates)或是失效(Expiries)? ? 採用什麼方式進行復制?同步還是非同步方式? 為了安裝分布式緩存 你需要配置一個PeerProvider 一個CacheManagerPeerListener 它們對於一個CacheManager來說是全局的 每個進行分布式操作的cache都要添加一個cacheEventListener來傳送消息
二 集群緩存概念及其配置 正確的元素類型 只有可序列化的元素可以進行復制 一些操作 比如移除 只需要元素的鍵值而不用整個元素 在這樣的操作中即使元素不是可序列化的但鍵值是可序列化的也可以被復制 成員發現(Peer Discovery) Ehcache進行集群的時候有一個cache組的概念 每個cache都是其他cache的一個peer 沒有主cache的存在 剛才我們問了一個問題 你如何知道集群環境中的其他緩存?這個問題可以命名為成員發現(Peer Discovery) Ehcache提供了兩種機制用來進行成員發現 就像一輛汽車 手動檔和自動檔 要使用一個內置的成員發現機制要在ehcache的配置文件中指定元素的class屬性為 net sf ehcache distribution 自動的成員發現 自動的發現方式用TCP廣播機制來確定和維持一個廣播組 它只需要一個簡單的配置可以自動的在組中添加和移除成員 在集群中也不需要什麼優化伺服器的知識 這是默認推薦的 成員每秒向群組發送一個 心跳 如果一個成員 秒種都沒有發出信號它將被群組移除 如果一個新的成員發送了一個 心跳 它將被添加進群組 任何一個用這個配置安裝了復制功能的cache都將被其他的成員發現並標識為可用狀態 要設置自動的成員發現 需要指定ehcache配置文件中元素的properties屬性 就像下面這樣 peerDiscovery=automatic multicastGroupAddress=multicast address | multicast host name multicastGroupPort=port timeToLive= (timeToLive屬性詳見常見問題部分的描述) 示例 假設你在集群中有兩台伺服器 你希望同步sampleCache 和sampleCache 每台獨立的伺服器都要有這樣的配置 配置server 和server <class= net sf ehcache distribution properties= peerDiscovery=automatic multicastGroupAddress= />multicastGroupPort= timeToLive= 手動進行成員發現 進行手動成員配置要知道每個監聽器的IP地址和埠 成員不能在運行時動態地添加和移除 在技術上很難使用廣播的情況下就可以手動成員發現 例如在集群的伺服器之間有一個不能傳送廣播報文的路由器 你也可以用手動成員發現進行單向的數據復制 只讓server 知道server 而server 不知道server 配置手動成員發現 需要指定ehcache配置文件中的properties屬性 像下面這樣 peerDiscovery=manual rmiUrls=//server:port/cacheName //server:port/cacheName … rmiUrls配置的是伺服器cache peers的列表 注意不要重復配置 示例 假設你在集群中有兩台伺服器 你要同步sampleCache 和sampleCache 下面是每個伺服器需要的配置 配置server <class= net sf ehcache distribution properties= peerDiscovery=manual />rmiUrls=//server : /sampleCache |//server : /sampleCache 配置server <class= net sf ehcache distribution properties= peerDiscovery=manual />rmiUrls=//server : /sampleCache |//server : /sampleCache 配置CacheManagerPeerListener 每個CacheManagerPeerListener監聽從成員們發向當前CacheManager的消息 配置CacheManagerPeerListener需要指定一個 它以插件的機制實現 用來創建CacheManagerPeerListener 的屬性有 class – 一個完整的工廠類名 properties – 只對這個工廠有意義的屬性 使用逗號分隔 Ehcache有一個內置的基於RMI的分布系統 它的監聽器是RMICacheManagerPeerListener 這個監聽器可以用 RMI來配置 <class= net sf ehcache distribution RMI properties= hostName=localhost port= />socketTimeoutMillis= 有效的屬性是 hostname (可選) – 運行監聽器的伺服器名稱 標明了做為集群群組的成員的地址 同時也是你想要控制的從集群中接收消息的介面在CacheManager初始化的時候會檢查hostname是否可用 如果hostName不可用 CacheManager將拒絕啟動並拋出一個連接被拒絕的異常 如果指定 hostname將使用InetAddress getLocalHost() getHostAddress()來得到 警告 不要將localhost配置為本地地址 因為它在網路中不可見將會導致不能從遠程伺服器接收信息從而不能復制 在同一台機器上有多個CacheManager的時候 你應該只用localhost來配置 port – 監聽器監聽的埠 socketTimeoutMillis (可選) – Socket超時的時間 默認是 ms 當你socket同步緩存請求地址比較遠 不是本地區域網 你可能需要把這個時間配置大些 不然很可能延時導致同步緩存失敗 配置CacheReplicators 每個要進行同步的cache都需要設置一個用來向CacheManagerr的成員復制消息的緩存事件監聽器 這個工作要通過為每個cache的配置增加一個cacheEventListenerFactory元素來完成 <! Sample cache named sampleCache ><cache name= sampleCache maxElementsInMemory= eternal= false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk= false ><cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory properties= replicateAsynchronously=true replicatePuts=true replicateUpdates=true replicateUpdatesViaCopy=false replicateRemovals=true /></cache>class – 使用net sf ehcache distribution RMICacheReplicatorFactory 這個工廠支持以下屬性 replicatePuts=true | false – 當一個新元素增加到緩存中的時候是否要復制到其他的peers 默認是true replicateUpdates=true | false – 當一個已經在緩存中存在的元素被覆蓋時是否要進行復制 默認是true replicateRemovals= true | false – 當元素移除的時候是否進行復制 默認是true replicateAsynchronously=true | false – 復制方式是非同步的(指定為true時)還是同步的(指定為false時) 默認是true replicatePutsViaCopy=true | false – 當一個新增元素被拷貝到其他的cache中時是否進行復制指定為true時為復制 默認是true replicateUpdatesViaCopy=true | false – 當一個元素被拷貝到其他的cache中時是否進行復制(指定為true時為復制) 默認是true 你可以使用ehcache的默認行為從而減少配置的工作量 默認的行為是以非同步的方式復制每件事 你可以像下面的例子一樣減少RMICacheReplicatorFactory的屬性配置 <! Sample cache named sampleCache All missing RMICacheReplicatorFactory properties default to true ><cache name= sampleCache maxElementsInMemory= eternal= true overflowToDisk= false memoryStoreEvictionPolicy= LFU ><cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory /></cache> 常見的問題 Windows上的Tomcat 有一個Tomcat或者是JDK的bug 在tomcat啟動時如果tomcat的安裝路徑中有空格的話 在啟動時RMI監聽器會失敗 參見 bin/wa?A =ind &L=rmi users&P= 和 doc/faq howto bugs/l 由於在Windows上安裝Tomcat默認是裝在 Program Files 文件夾里的 所以這個問題經常發生 廣播阻斷 自動的peer discovery與廣播息息相關 廣播可能被路由阻攔 像Xen和VMWare這種虛擬化的技術也可以阻攔廣播 如果這些都打開了 你可能還在要將你的網卡的相關配置打開 一個簡單的辦法可以告訴廣播是否有效 那就是使用ehcache remote debugger來看 心跳 是否可用 廣播傳播的不夠遠或是傳得太遠 你可以通過設置badly misnamed time to live來控制廣播傳播的距離 用廣播IP協議時 timeToLive的值指的是數據包可以傳遞的域或是范圍 約定如下 是限制在同一個伺服器 是限制在同一個子網 是限制在同一個網站 是限制在同一個region 是限制在同一個大洲 是不限制 譯者按 上面這些資料翻譯的不夠准確 請讀者自行尋找原文理解吧 在Java實現中默認值是 也就是在同一個子網中傳播 改變timeToLive屬性可以限制或是擴展傳播的范圍
三 RMI方式緩存集群/配置分布式緩存 RMI 是 Java 的一種遠程方法調用技術 是一種點對點的基於 Java 對象的通訊方式 EhCache 從 版本開始就支持 RMI 方式的緩存集群 在集群環境中 EhCache 所有緩存對象的鍵和值都必須是可序列化的 也就是必須實現 java io Serializable 介面 這點在其它集群方式下也是需要遵守的 下圖是 RMI 集群模式的結構圖
採用 RMI 集群模式時 集群中的每個節點都是對等關系 並不存在主節點或者從節點的概念 因此節點間必須有一個機制能夠互相認識對方 必須知道其它節點的信息 包括主機地址 埠號等 EhCache 提供兩種節點的發現方式 手工配置和自動發現 手工配置方式要求在每個節點中配置其它所有節點的連接信息 一旦集群中的節點發生變化時 需要對緩存進行重新配置 由於 RMI 是 Java 中內置支持的技術 因此使用 RMI 集群模式時 無需引入其它的 Jar 包 EhCache 本身就帶有支持 RMI 集群的功能 使用 RMI 集群模式需要在 ehcache xml 配置文件中定義 節點 分布式同步緩存要讓這邊的cache知道對方的cache 叫做Peer Discovery(成員發現) EHCache實現成員發現的方式有兩種 手動查找 A 在ehcache xml中配置PeerDiscovery成員發現對象 Server 配置 配置本地hostName port是 分別監聽 : 的mobileCache和 : 的mobileCache 注意這里的mobileCache是緩存的名稱 分別對應著server server 的cache的配置 <?xml version= encoding= gbk ?><ehcache xmlns:xsi= instance xsi:noNamespaceSchemaLocation= ehcache xsd > <diskStore path= java io tmpdir /> <! 集群多台伺服器中的緩存 這里是要同步一些伺服器的緩存 server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache 注意 每台要同步緩存的伺服器的RMI通信socket埠都不一樣 在配置的時候注意設置 > <! server 的配置 > < class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache /></ehcache>以上注意元素出現的位置在diskStore下
同樣在你的另外 台伺服器上增加配置 Server 配置本地host port為 分別同步 : 的mobileCache和 : 的mobileCache <! server 的配置 >< class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache />Server 配置本地host port為 分別同步 : 的mobileCache緩存和 : 的mobileCache緩存 <! server 的配置 >< class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache />這樣就在三台不同的伺服器上配置了手動查找cache的PeerProvider成員發現的配置了 值得注意的是你在配置rmiUrls的時候要特別注意url不能重復出現 並且埠 地址都是對的 如果指定 hostname將使用InetAddress getLocalHost() getHostAddress()來得到 警告 不要將localhost配置為本地地址 因為它在網路中不可見將會導致不能從遠程伺服器接收信息從而不能復制 在同一台機器上有多個CacheManager的時候 你應該只用localhost來配置 B 下面配置緩存和緩存同步監聽 需要在每台伺服器中的ehcache xml文件中增加cache配置和cacheEventListenerFactory cacheLoaderFactory的配置 <defaultCache maxElementsInMemory= eternal= false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk= false /><! 配置自定義緩存 maxElementsInMemory:緩存中允許創建的最大對象數 eternal:緩存中對象是否為永久的 如果是 超時設置將被忽略 對象從不過期 timeToIdleSeconds:緩存數據空閑的最大時間 也就是說如果有一個緩存有多久沒有被訪問就會被銷毀 如果該值是 就意味著元素可以停頓無窮長的時間 timeToLiveSeconds:緩存數據存活的時間 緩存對象最大的的存活時間 超過這個時間就會被銷毀 這只能在元素不是永久駐留時有效 如果該值是 就意味著元素可以停頓無窮長的時間 overflowToDisk:內存不足時 是否啟用磁碟緩存 memoryStoreEvictionPolicy:緩存滿了之後的淘汰演算法 每一個小時更新一次緩存( 小時過期) ><cache name= mobileCache maxElementsInMemory= eternal= false overflowToDisk= true timeToIdleSeconds= timeToLiveSeconds= memoryStoreEvictionPolicy= LFU > <! RMI緩存分布同步查找 class使用net sf ehcache distribution RMICacheReplicatorFactory 這個工廠支持以下屬性 replicatePuts=true | false – 當一個新元素增加到緩存中的時候是否要復制到其他的peers 默認是true replicateUpdates=true | false – 當一個已經在緩存中存在的元素被覆蓋時是否要進行復制 默認是true replicateRemovals= true | false – 當元素移除的時候是否進行復制 默認是true replicateAsynchronously=true | false – 復制方式是非同步的 指定為true時 還是同步的 指定為false時 默認是true replicatePutsViaCopy=true | false – 當一個新增元素被拷貝到其他的cache中時是否進行復制 指定為true時為復制 默認是true replicateUpdatesViaCopy=true | false – 當一個元素被拷貝到其他的cache中時是否進行復制 指定為true時為復制 默認是true = > <! 監聽RMI同步緩存對象配置 注冊相應的的緩存監聽類 用於處理緩存事件 如put remove update 和expire > <cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory properties= replicateAsynchronously=true /> replicatePuts=true replicateUpdates=true replicateUpdatesViaCopy=false replicateRemovals=true <! 用於在初始化緩存 以及自動設置 > <bootstrapCacheLoaderFactory class= net sf ehcache bootstrap BootstrapCacheLoaderFactory /></cache> C 這樣就完成了 台伺服器的配置 下面給出server 的完整的ehcache xml的配置 <?xml version= encoding= gbk ?><ehcache xmlns:xsi= instance xsi:noNamespaceSchemaLocation= ehcache xsd > <diskStore path= java io tmpdir /> <!集群多台伺服器中的緩存 這里是要同步一些伺服器的緩存 server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache 注意每台要同步緩存的伺服器的RMI通信socket埠都不一樣 在配置的時候注意設置 > <! server 的配置 > < class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache /> <defaultCache maxElementsInMemory= eternal= false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk= false /> <! 配置自定義緩存 maxElementsInMemory:緩存中允許創建的最大對象數 eternal:緩存中對象是否為永久的 如果是 超時設置將被忽略 對象從不過期 timeToIdleSeconds:緩存數據空閑的最大時間 也就是說如果有一個緩存有多久沒有被訪問就會被銷毀 如果該值是 就意味著元素可以停頓無窮長的時間 timeToLiveSeconds:緩存數據存活的時間 緩存對象最大的的存活時間 超過這個時間就會被銷毀 這只能在元素不是永久駐留時有效 如果該值是 就意味著元素可以停頓無窮長的時間 overflowToDisk:內存不足時 是否啟用磁碟緩存 memoryStoreEvictionPolicy:緩存滿了之後的淘汰演算法 每一個小時更新一次緩存( 小時過期) > <cache name= mobileCache maxElementsInMemory= eternal= false overflowToDisk= true timeToIdleSeconds= timeToLiveSeconds= memoryStoreEvictionPolicy= LFU > <! RMI緩存分布同步查找 class使用net sf ehcache distribution RMICacheReplicatorFactory 這個工廠支持以下屬性 replicatePuts=true | false – 當一個新元素增加到緩存中的時候是否要復制到其他的peers 默認是true replicateUpdates=true | false – 當一個已經在緩存中存在的元素被覆蓋時是否要進行復制 默認是true replicateRemovals= true | false – 當元素移除的時候是否進行復制 默認是true replicateAsynchronously=true | false – 復制方式是非同步的 指定為true時 還是同步的 指定為false時 默認是true replicatePutsViaCopy=true | false – 當一個新增元素被拷貝到其他的cache中時是否進行復制 指定為true時為復制 默認是true replicateUpdatesViaCopy=true | false – 當一個元素被拷貝到其他的cache中時是否進行復制 指定為true時為復制 默認是true = > <! 監聽RMI同步緩存對象配置 注冊相應的的緩存監聽類 用於處理緩存事件 如put remove update 和expire > <cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory properties= replicateAsynchronously=true /> replicatePuts=true replicateUpdates=true replicateUpdatesViaCopy=false replicateRemovals=true <! 用於在初始化緩存 以及自動設置 > <bootstrapCacheLoaderFactory class= net sf ehcache bootstrap BootstrapCacheLoaderFactory /> </cache></ehcache> 自動發現 自動發現配置和手動查找的方式有一點不同 其他的地方都基本是一樣的 同樣在ehcache xml中增加配置 配置如下 <! 搜索某個網段上的緩存timeToLive 是限制在同一個伺服器 是限制在同一個子網 是限制在同一個網站 是限制在同一個region 是限制在同一個大洲 是不限制 >< class= net sf ehcache distribution properties= peerDiscovery=automatic multicastGroupAddress= multicastGroupPort= timeToLive= /> lishixin/Article/program/Java/hx/201311/25706
『伍』 描述一下hadoop中,有那些地方使用了緩存機制,分別有什麼作用
描述一下
hadoop
中,有哪些地方使用到了緩存機制,作用分別是什麼?
答:
緩存機制就是
DistributedCash
,
就是在
job
任務執行前,將需要的文件拷貝到
Task
機器
上進行緩存,提高
maprece
的執行效率。
『陸』 分布式存儲最佳緩存比
作者:深入細節的 SmartX 一線技術團隊
近日,VMware 發布了 vSAN 8,對存儲架構進行了重大更新。其中最主要的變化,即引入了新的 Express Storage Architecture(ESA)架構:用「存儲池」替代了原存儲架構(OSA)中的「磁碟組」,並不再需要專用 SSD 承擔緩存加速功能,一定程度上避免了 8.0 之前版本中的專用緩存檔利用率低、易發生緩存擊穿等問題。
而值得一提的是,在 vSAN 大版本更新之前,SmartX 即通過統一緩存空間和智能冷熱數據管理優化了分布式存儲緩存機制,有效規避了上述問題。本文將通過重點解讀 vSAN(以 vSAN 7 為例)和 SmartX 分布式塊存儲組件 ZBS* 緩存機制的原理,並測試對比兩種緩存機制下虛擬機性能表現,讓讀者更好地了解兩種技術實現機制的區別對業務可能帶來的實際影響。
* ZBS 內置於 SmartX 超融合軟體 SMTX OS,可與 SmartX 原生虛擬化 ELF 搭配提供服務。
本文重點
vSAN 7 採用劃分讀寫緩存空間的機制,將緩存磁碟按照容量佔比劃分為寫緩沖區(30%)和讀緩存區(70%)。這種方式可能出現緩存利用率低、在訪問數據量過大時導致緩存擊穿,進而引起性能下降等問題。
ZBS 採用統一緩存空間的機制,並通過 2 級 LRU 演算法對冷熱數據進行管理,在充分利用緩存容量的同時避免了因訪問量激增導致虛擬機性能下降的情況。
本文基於相同的硬體配置和 I/O 讀寫場景,分別測試 VMware 超融合(vSphere 虛擬化 + vSAN 分布式存儲)寫入 300 GB 數據、SMTX OS(ELF + ZBS)寫入 500 GB 數據時虛擬機的性能表現。結果顯示,vSAN 7 難以充分利用緩存介質,發生緩存擊穿,導致存儲性能下降;而 SMTX OS 即便在寫入更多數據的情況下也未發生緩存擊穿,虛擬機性能保持穩定。
場景問題
混閃配置是超融合或分布式存儲現階段的主流落地模式。混閃配置是指機器中的磁碟使用 SSD + HDD 混合組成,其中 SSD 磁碟作為數據緩存層,而 HDD 磁碟作為數據容量層。以該模式構建的分布式存儲池通過軟體演算法進行冷熱數據自動判斷,在提供高性能的同時,還可獲得較大的存儲容量,進而提升資源利用率,獲得相對全快閃記憶體儲更高的性價比。
在將 SSD 磁碟用作數據緩存層時,部分超融合產品會將緩存容量(Cache)劃分為讀和寫各自獨立的兩部分。例如,vSAN 7 及更早版本會將每個磁碟組(Disk Group)中的緩存磁碟,按照容量佔比劃分為寫緩沖區(30%)和讀緩存區(70%),當讀取數據未命中緩存或者寫緩存已滿,將會直接從容量層進行讀寫。
『柒』 華為技術架構師分享:高並發場景下緩存處理的一些思路
在實際的開發當中,我們經常需要進行磁碟數據的讀取和搜索,因此經常會有出現從資料庫讀取數據的場景出現。但是當數據訪問量次數增大的時候,過多的磁碟讀取可能會最終成為整個系統的性能瓶頸,甚至是壓垮整個資料庫,導致系統卡死等嚴重問題。
常規的應用系統中,我們通常會在需要的時候對資料庫進行查找,因此系統的大致結構如下所示:
1.緩存和資料庫之間數據一致性問題
常用於緩存處理的機制我總結為了以下幾種:
首先來簡單說說Cache aside的這種方式:
Cache Aside模式
這種模式處理緩存通常都是先從資料庫緩存查詢,如果緩存沒有命中則從資料庫中進行查找。
這裡面會發生的三種情況如下:
緩存命中:
當查詢的時候發現緩存存在,那麼直接從緩存中提取。
緩存失效:
當緩存沒有數據的時候,則從database裡面讀取源數據,再加入到cache裡面去。
緩存更新:
當有新的寫操作去修改database裡面的數據時,需要在寫操作完成之後,讓cache裡面對應的數據失效。
關於這種模式下依然會存在缺陷。比如,一個是讀操作,但是沒有命中緩存,然後就到資料庫中取數據,此時來了一個寫操作,寫完資料庫後,讓緩存失效,然後,之前的那個讀操作再把老的數據放進去,所以,會造成臟數據。
Facebook的大牛們也曾經就緩存處理這個問題發表過相關的論文,鏈接如下:
分布式環境中要想完全的保證數據一致性是一件極為困難的事情,我們只能夠盡可能的減低這種數據不一致性問題產生的情況。
Read Through模式
Read Through模式是指應用程序始終從緩存中請求數據。 如果緩存沒有數據,則它負責使用底層提供程序插件從資料庫中檢索數據。 檢索數據後,緩存會自行更新並將數據返回給調用應用程序。使用Read Through 有一個好處。
我們總是使用key從緩存中檢索數據, 調用的應用程序不知道資料庫, 由存儲方來負責自己的緩存處理,這使代碼更具可讀性, 代碼更清晰。但是這也有相應的缺陷,開發人員需要給編寫相關的程序插件,增加了開發的難度性。
Write Through模式
Write Through模式和Read Through模式類似,當數據發生更新的時候,先去Cache裡面進行更新,如果命中了,則先更新緩存再由Cache方來更新database。如果沒有命中的話,就直接更新Cache裡面的數據。
2.緩存穿透問題
在高並發的場景中,緩存穿透是一個經常都會遇到的問題。
什麼是緩存穿透?
大量的請求在緩存中沒有查詢到指定的數據,因此需要從資料庫中進行查詢,造成緩存穿透。
會造成什麼後果?
大量的請求短時間內湧入到database中進行查詢會增加database的壓力,最終導致database無法承載客戶單請求的壓力,出現宕機卡死等現象。
常用的解決方案通常有以下幾類:
1.空值緩存
在某些特定的業務場景中,對於數據的查詢可能會是空的,沒有實際的存在,並且這類數據信息在短時間進行多次的反復查詢也不會有變化,那麼整個過程中,多次的請求資料庫操作會顯得有些多餘。
不妨可以將這些空值(沒有查詢結果的數據)對應的key存儲在緩存中,那麼第二次查找的時候就不需要再次請求到database那麼麻煩,只需要通過內存查詢即可。這樣的做法能夠大大減少對於database的訪問壓力。
2.布隆過濾器
通常對於database裡面的數據的key值可以預先存儲在布隆過濾器裡面去,然後先在布隆過濾器裡面進行過濾,如果發現布隆過濾器中沒有的話,就再去redis裡面進行查詢,如果redis中也沒有數據的話,再去database查詢。這樣可以避免不存在的數據信息也去往存儲庫中進行查詢情況。
什麼是緩存雪崩?
當緩存伺服器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,也會給後端系統(比如DB)帶來很大壓力。
如何避免緩存雪崩問題?
1.使用加鎖隊列來應付這種問題。當有多個請求湧入的時候,當緩存失效的時候加入一把分布式鎖,只允許搶鎖成功的請求去庫裡面讀取數據然後將其存入緩存中,再釋放鎖,讓後續的讀請求從緩存中取數據。但是這種做法有一定的弊端,過多的讀請求線程堵塞,將機器內存占滿,依然沒有能夠從根本上解決問題。
2.在並發場景發生前,先手動觸發請求,將緩存都存儲起來,以減少後期請求對database的第一次查詢的壓力。數據過期時間設置盡量分散開來,不要讓數據出現同一時間段出現緩存過期的情況。
3.從緩存可用性的角度來思考,避免緩存出現單點故障的問題,可以結合使用 主從+哨兵的模式來搭建緩存架構,但是這種模式搭建的緩存架構有個弊端,就是無法進行緩存分片,存儲緩存的數據量有限制,因此可以升級為Redis Cluster架構來進行優化處理。(需要結合企業實際的經濟實力,畢竟Redis Cluster的搭建需要更多的機器)
4.Ehcache本地緩存 + Hystrix限流&降級,避免MySQL被打死。
使用 Ehcache本地緩存的目的也是考慮在 Redis Cluster 完全不可用的時候,Ehcache本地緩存還能夠支撐一陣。
使用 Hystrix進行限流 & 降級 ,比如一秒來了5000個請求,我們可以設置假設只能有一秒 2000個請求能通過這個組件,那麼其他剩餘的 3000 請求就會走限流邏輯。
然後去調用我們自己開發的降級組件(降級),比如設置的一些默認值呀之類的。以此來保護最後的 MySQL 不會被大量的請求給打死。
『捌』 「分布式緩存」 是什麼概念,怎麼理解
我的理解,分布式緩存系統是為了解決資料庫伺服器和web伺服器之間的瓶頸。
如果一個網站的流量很大,這個瓶頸將會非常明顯,每次資料庫查詢耗費的時間將會非常可觀。
對於更新速度不是很快的網站,我們可以用靜態化來避免過多的資料庫查詢。
對於更新速度以秒計的網站,靜態化也不會太理想,可以用緩存系統來構建。
如果只是單台伺服器用作緩存,問題不會太復雜,如果有多台伺服器用作緩存,就要考慮緩存伺服器的負載均衡。