服務器緩存系統

WEB系統中各參與者都可以進行緩存。數據庫緩存,應用服務器緩存,Web服務器緩存,客戶端瀏覽器緩存。

 

java緩存級別:

堆緩存

堆外緩存

磁盤緩存

分佈式緩存

 

典型java服務器端緩存系統:

1、接入nginx負載均衡到應用nginx。

2、應用nginx讀取本地緩存(Nginx Proxy Cache或者Local Redis緩存)。如果命中,則直接返回。後續步驟中也是類似不再贅述。

3、讀取從redis服務器緩存。OpenResty的lua-resty-redis模塊可以使Nginx具有了直接讀取redis緩存的能力,不佔用tomcat的線程。

3、回源到Tomcat集羣。

4、Tomcat應用中,讀取本地緩存。

6、回源到數據庫集羣。

7、將數據庫返回的數據以異步方式寫到主redis服務器。

 

有緩存時的查詢流程:

應用服務器查詢緩存。如果查到緩存服務器,則使用。如果沒有查到緩存,則查詢數據庫。數據庫返回結果後,應用服務器寫緩存服務器,內容爲key-value對。

 

緩存使用模式:

Cache-Aside:查不到緩存時,由業務代碼回源SoR(source of record)

Cache-As-SoR:所有操作都是對cache進行,Cache進行SoR回源。

 

緩存淘汰or更新

淘汰緩存只是增加了一次cache miss。更新緩存雖然避免了cache miss,但是成本更高。所以通常淘汰緩存而不是更新。

 

數據庫和緩存的一致性:

方式1:先更新數據庫,然後同步淘汰緩存。優點:數據不一致性時間短。缺點:請求處理時間長。例如:使用mysql memcached UDF(用戶自定義函數)和mysql觸發器在更新mysql數據庫的時候,觸發淘汰cache。這樣可以減少應用程序的邏輯。也可以保證事務的完整性。

方式2:先更新數據庫,然後異步淘汰緩存。優點:請求處理時間短。缺點:數據不一致時間長。例如:可以使用canal,模擬mysql slave和master的同步機制,監控mysql binlog來觸發redis緩存的淘汰。

 

清除緩存

基於時間清除緩存:TTL和TTI(Time to Idle)

緩存滿的含義:緩存超過設置的存儲空間或者超過設置的條目數。

緩存滿了,使用LRU機制驅逐老的緩存。熱點緩存,要多存儲幾份,也可以在應用系統中進行幾秒鐘的本地緩存,從而降低遠程緩存系統的壓力。

除了LRU還有FIFO和LFU(Least Frequently used)

 

緩存相關問題:

緩存穿透:查詢不存在的id,每次都會訪問DB。如果id不存在,則內容設置爲null,並且設置緩存的失效時間。

緩存雪崩:緩存集中過期失效(比如雙11活動在0點開始,1點緩存集中失效)。緩存失效時間加一個隨機因子,防止同時失效。可以在緩存失效前,主動通知後臺線程更新緩存。

緩存擊穿:一個key非常熱點(爆款產品),這個key失效瞬間,導致大量數據庫請求。對一個key只允許一個線程查詢數據庫和寫緩存,其他線程等待。

緩存預熱:緩存預熱就是系統上線後,提前將相關的熱點數據加載到緩存系統。避免在用戶請求的時候,再查詢數據庫。

 

Redis:

redis是數據結構服務器,所以重點就是它支持的數據結構。使用命令來操作數據結構。最常用的命令是set()和get()。

Redis是一個開源(BSD許可),內存存儲的數據結構服務器,可用作數據庫、高速緩存和消息隊列。Key-Value中值(value)可以是字符串、列表、集合、有序集合、哈希、位圖、hyperloglog(用於快速計算基數(一個數據集中不同元素的數目))、流等數據類型。內置Lua腳本、LRU機制、事務以及不同級別磁盤持久化功能。Redis支持master-slave模式的數據備份。可以通過Redis Sentinel(哨兵)提供高可用功能,發現主服務器崩潰後,自動選舉新的主服務器,並且通知應用服務器。也可以通過Redis Cluster提供集羣功能。

Redis使用ANSI C語言編寫,提供多種語言的API,包括:c、C++、C#、php、java、python、go等語言。

Redis的所有操作都是原子性的,同時Redis還支持對幾個操作合併後的原子性執行。

Redis支持 publish/subscribe模式,所以可以用作消息隊列。

Redis 支持管道技術。允許服務端未響應時,客戶端繼續向服務端發送其它請求,並最終一次性讀取所有服務端的響應。這提高了性能。

 

Twemproxy可以作爲redis的代理。這樣可以減少和後臺緩存服務器的連接數。也可以用於實現redis集羣。Twemproxy支持多種hash算法。支持失敗節點自動刪除。後端sharding(分片)邏輯對業務透明。

Redis集羣也可以不使用Twemproxy,直接使用redis-cluster特性。Redis-Cluster採用無中心結構。健壯性更高。

數據按照hash slot存儲分佈在多個節點。

每個節點保存整個集羣狀態,每個節點(包括slave節點)都和其他所有節點連接。

每個主節點有若干個slave節點。實現故障自動failover,節點之間通過gossip協議交換狀態信息,用投票機制完成Slave到Master的角色提升。這類似於簡化版的OSPF DR選舉。但是又不同,從節點發現主節點down了,從節點會廣播request消息,要求成爲主節點,其它從節點會如果同意則返回ack,如果選票過半,則當選。gossip協議用於P2P網絡中,傳播消息的方式類似於OSPF的flood機制。

可擴展性,可線性擴展到 1000 個節點,節點可動態添加或刪除。

高可用性,部分節點不可用時,集羣仍可用。

應用服務器可以訪問任何一個主節點,如果數據不在這個主節點上,它會返回一個moved重定向消息,告訴應用服務器應該訪問哪個主節點。可以使用JedisPool,它將cluster slots的結果保存在本地,分配請求。

 

主從同步:

Redis全量複製通常發生在slave初始化階段。之後就是增量賦值。

全量複製時,主服務器收到從服務器的SYNC命令後會生成RDB(Redis DataBase)快照文件。同時在緩衝區中記錄此後執行的命令。將RDB文件發送給slave之後,還要將緩衝區中的命令發送給slave。之後主服務器執行寫命令時就會向從服務器發送相同的寫命令。

這和ospf很類似。但是ospf顯然更先進,它會比較雙方的LSDB,只請求缺失的部分。

主從同步還可以使用AOF的方式,它的基本原理是從服務器回放主服務器執行過的命令。

 

redis cluster集羣中通過消息來進行通信。消息共有以下5種。

meet消息:加入到集羣中。

ping消息:檢測目標節點是否處於在線狀態。

pong消息:收到到meet消息或者ping消息後,會回覆pong消息。另外,pong消息也可以用於主動更新,例如故障轉移後,新的主節點會向集羣中發送pong消息,用於告知它已經升級爲主節點。

fail消息:fail消息用於通知某個節點掉線了。例如節點A認爲節點B已下線(B一段時間內都沒有回覆pong消息),節點A會向集羣中發送一條fail消息,接收到這條消息的節點會將節點B標記爲疑似下線。當大於等於半數的節點認爲B下線了,這個節點就被標記爲下線。

 

Redis vs Memcache

有持久化需求、對數據結構要求高、對處理有高級要求的應用,選擇redis。簡單的key/value存儲,選擇memcache。Redis只支持linux。Memcache支持windows、linux。

Redis支持簡單的事務,只是一次性按順序執行多條命令。但是不支持回滾,即有命令出錯,也會繼續執行。Memcache不支持事務。

Redis是單線程的。Memcache是多線程的。

Redis沒有自己的內存管理模塊。Memcache有自己的內存管理模塊,內存分配效率更高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章