91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Nginx+Redis+Ehcache中大型高并發與高可用的三層緩存架構分析

發布時間:2021-12-13 09:54:56 來源:億速云 閱讀:113 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“Nginx+Redis+Ehcache中大型高并發與高可用的三層緩存架構分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Nginx+Redis+Ehcache中大型高并發與高可用的三層緩存架構分析”這篇文章吧。

Nginx

Nginx+Redis+Ehcache中大型高并發與高可用的三層緩存架構分析

對于中間件nginx常用來做流量的分發,同時nginx本身也有自己的緩存(容量有限),我們可以用來緩存熱點數據,讓用戶的請求直接走緩存并返回,減少流向服務器的流量

一、模板引擎

通常我們可以配合使用freemaker/velocity等模板引擎來抗住大量的請求

小型系統可能直接在服務器端渲染出所有的頁面并放入緩存,之后的相同頁面請求就可以直接返回,不用去查詢數據源或者做數據邏輯處理

對于頁面非常之多的系統,當模板有改變,上述方法就需要重新渲染所有的頁面模板,毫無疑問是不可取的。因此配合nginx+lua(OpenResty),將模板單獨保存在nginx緩存中,同時對于用來渲染的數據也存在nginx緩存中,但是需要設置一個緩存過期的時間,以盡可能保證模板的實時性

二、雙層nginx來提升緩存命中率

對于部署多個nginx而言,如果不加入一些數據的路由策略,那么可能導致每個nginx的緩存命中率很低。因此可以部署雙層nginx

分發層nginx負責流量分發的邏輯和策略,根據自己定義的一些規則,比如根據productId進行hash,然后對后端nginx數量取模將某一個商品的訪問請求固定路由到一個nginx后端服務器上去

后端nginx用來緩存一些熱點數據到自己的緩存區(分發層只能配置1個嗎)

Redis

Nginx+Redis+Ehcache中大型高并發與高可用的三層緩存架構分析

用戶的請求,在nginx沒有緩存相應的數據,那么會進入到redis緩存中,redis可以做到全量數據的緩存,通過水平擴展能夠提升并發、高可用的能力

一、持久化機制

持久化機制:將redis內存中的數據持久化到磁盤中,然后可以定期將磁盤文件上傳至S3(AWS)或者ODPS(阿里云)等一些云存儲服務上去。

如果同時使用RDB和AOF兩種持久化機制,那么在redis重啟的時候,會使用AOF來重新構建數據,因為AOF中的數據更加完整,建議將兩種持久化機制都開啟,用AO F來保證數據不丟失,作為數據恢復的第一選擇;用RDB來作不同程度的冷備,在AOF文件都丟失或損壞不可用的時候來快速進行數據的恢復。

實戰踩坑:對于想從RDB恢復數據,同時AOF開關也是打開的,一直無法正常恢復,因為每次都會優先從AOF獲取數據(如果臨時關閉AOF,就可以正常恢復)。此時首先停止redis,然后關閉AOF,拷貝RDB到相應目錄,啟動redis之后熱修改配置參數redis config set appendonly yes,此時會自動生成一個當前內存數據的AOF文件,然后再次停止redis,打開AOF配置,再次啟動數據就正常啟動

RDB

對redis中的數據執行周期性的持久化,每一刻持久化的都是全量數據的一個快照。對redis性能影響較小,基于RDB能夠快速異常恢復

AOF

以append-only的模式寫入一個日志文件中,在redis重啟的時候可以通過回放AOF日志中的寫入指令來重新構建整個數據集。(實際上每次寫的日志數據會先到linux os cache,然后redis每隔一秒調用操作系統fsync將os cache中的數據寫入磁盤)。對redis有一定的性能影響,能夠盡量保證數據的完整性。redis通過rewrite機制來保障AOF文件不會太龐大,基于當前內存數據并可以做適當的指令重構。

二、redis集群

replication

一主多從架構,主節點負責寫,并且將數據同步到其他salve節點(異步執行),從節點負責讀,主要就是用來做讀寫分離的橫向擴容架構。這種架構的master節點數據一定要做持久化,否則,當master宕機重啟之后內存數據清空,那么就會將空數據復制到slave,導致所有數據消失

sentinal哨兵

哨兵是redis集群架構中很重要的一個組件,負責監控redis master和slave進程是否正常工作,當某個redis實例故障時,能夠發送消息報警通知給管理員,當master node宕機能夠自動轉移到slave node上,如果故障轉移發生來,會通知client客戶端新的master地址。sentinal至少需要3個實例來保證自己的健壯性,并且能夠更好地進行quorum投票以達到majority來執行故障轉移。

前兩種架構方式最大的特點是,每個節點的數據是相同的,無法存取海量的數據。因此哨兵集群的方式使用與數據量不大的情況

redis cluster

redis cluster支撐多master node,每個master node可以掛載多個slave node,如果mastre掛掉會自動將對應的某個slave切換成master。需要注意的是redis cluster架構下slave節點主要是用來做高可用、故障主備切換的,如果一定需要slave能夠提供讀的能力,修改配置也可以實現(同時也需要修改jedis源碼來支持該情況下的讀寫分離操作)。redis cluster架構下,master就是可以任意擴展的,直接橫向擴展master即可提高讀寫吞吐量。slave節點能夠自動遷移(讓master節點盡量平均擁有slave節點),對整個架構過載冗余的slave就可以保障系統更高的可用性。

ehcache

Nginx+Redis+Ehcache中大型高并發與高可用的三層緩存架構分析

tomcat jvm堆內存緩存,主要是抗redis出現大規模災難。如果redis出現了大規模的宕機,導致nginx大量流量直接涌入數據生產服務,那么最后的tomcat堆內存緩存也可以處理部分請求,避免所有請求都直接流向DB

針對上面的技術我特意整理了一下,有很多技術不是靠幾句話能講清楚,所以干脆找朋友錄制了一些視頻,很多問題其實答案很簡單,但是背后的思考和邏輯不簡單,要做到知其然還要知其所以然。如果想學習Java工程化、高性能及分布式、深入淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友可以加我的Java進階群:694549689,群里有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給大家。

緩存數據更新策略

對時效性要求高的緩存數據,當發生變更的時候,直接采取數據庫和redis緩存雙寫的方案,讓緩存時效性最高。

對時效性不高的數據,當發生變更之后,采取MQ異步通知的方式,通過數據生產服務來監聽MQ消息,然后異步去拉取服務的數據更新tomcat jvm緩存和redis緩存,對于nginx本地緩存過期之后就可以從redis中拉取新的數據并更新到nginx本地。

經典的緩存+數據庫讀寫的模式,cache aside pattern

讀的時候,先讀緩存,緩存沒有的話,那么就讀數據庫,然后取出數據后放入緩存,同時返回響應

更新的時候,先刪除緩存,然后再更新數據庫

之所以更新的時候只是刪除緩存,因為對于一些復雜有邏輯的緩存數據,每次數據變更都更新一次緩存會造成額外的負擔,只是刪除緩存,讓該數據下一次被使用的時候再去執行讀的操作來重新緩存,這里采用的是懶加載的策略。舉個例子,一個緩存涉及的表的字段,在1分鐘內就修改了20次,或者是100次,那么緩存跟新20次,100次;但是這個緩存在1分鐘內就被讀取了1次,因此每次更新緩存就會有大量的冷數據,對于緩存符合28黃金法則,20%的數據,占用了80%的訪問量

數據庫和redis緩存雙寫不一致的問題

最初級的緩存不一致問題以及解決方案

問題:如果先修改數據庫再刪除緩存,那么當緩存刪除失敗來,那么會導致數據庫中是最新數據,緩存中依舊是舊數據,造成數據不一致。

解決方案:可以先刪除緩存,再修改數據庫,如果刪除緩存成功但是數據庫修改失敗,那么數據庫中是舊數據,緩存是空不會出現不一致

比較復雜的數據不一致問題分析

問題:對于數據發生來變更,先刪除緩存,然后去修改數據庫,此時數據庫中的數據還沒有修改成功,并發的讀請求到來去讀緩存發現是空,進而去數據庫查詢到此時的舊數據放到緩存中,然后之前對數據庫數據的修改成功來,就會造成數據不一致

解決方案:將數據庫與緩存更新與讀取操作進行異步串行化。當更新數據的時候,根據數據的唯一標識,將更新數據操作路由到一個jvm內部的隊列中,一個隊列對應一個工作線程,線程串行拿到隊列中的操作一條一條地執行。當執行隊列中的更新數據操作,刪除緩存,然后去更新數據庫,此時還沒有完成更新的時候過來一個讀請求,讀到了空的緩存那么可以先將緩存更新的請求發送至路由之后的隊列中,此時會在隊列積壓,然后同步等待緩存更新完成,一個隊列中多個相同數據緩存更新請求串在一起是沒有意義的,因此可以做過濾處理。等待前面的更新數據操作完成數據庫操作之后,才會去執行下一個緩存更新的操作,此時會從數據庫中讀取最新的數據,然后寫入緩存中,如果請求還在等待時間范圍內,不斷輪詢發現可以取到緩存中值就可以直接返回(此時可能會有對這個緩存數據的多個請求正在這樣處理);如果請求等待事件超過一定時長,那么這一次的請求直接讀取數據庫中的舊值

對于這種處理方式需要注意一些問題:

讀請求長時阻塞:由于讀請求進行來非常輕度的異步化,所以對超時的問題需要格外注意,超過超時時間會直接查詢DB,處理不好會對DB造成壓力,因此需要測試系統高峰期QPS來調整機器數以及對應機器上的隊列數最終決定合理的請求等待超時時間

多實例部署的請求路由:可能這個服務會部署多個實例,那么必須保證對應的請求都通過nginx服務器路由到相同的服務實例上

熱點數據的路由導師請求的傾斜:因為只有在商品數據更新的時候才會清空緩存,然后才會導致讀寫并發,所以更新頻率不是太高的話,這個問題的影響并不是特別大,但是的確可能某些機器的負載會高一些

分布式緩存重建并發沖突解決方案

對于緩存生產服務,可能部署在多臺機器,當redis和ehcache對應的緩存數據都過期不存在時,此時可能nginx過來的請求和kafka監聽的請求同時到達,導致兩者最終都去拉取數據并且存入redis中,因此可能產生并發沖突的問題,可以采用redis或者zookeeper類似的分布式鎖來解決,讓請求的被動緩存重建與監聽主動的緩存重建操作避免并發的沖突,當存入緩存的時候通過對比時間字段廢棄掉舊的數據,保存最新的數據到緩存

緩存冷啟動以及緩存預熱解決方案

當系統第一次啟動,大量請求涌入,此時的緩存為空,可能會導致DB崩潰,進而讓系統不可用,同樣當redis所有緩存數據異常丟失,也會導致該問題。因此,可以提前放入數據到redis避免上述冷啟動的問題,當然也不可能是全量數據,可以根據類似于當天的具體訪問情況,實時統計出訪問頻率較高的熱數據,這里熱數據也比較多,需要多個服務并行的分布式去讀寫到redis中(所以要基于zk分布式鎖)

通過nginx+lua將訪問流量上報至kafka中,storm從kafka中消費數據,實時統計處每個商品的訪問次數,訪問次數基于LRU(apache commons collections LRUMap)內存數據結構的存儲方案,使用LRUMap去存放是因為內存中的性能高,沒有外部依賴,每個storm task啟動的時候基于zk分布式鎖將自己的id寫入zk同一個節點中,每個storm task負責完成自己這里的熱數據的統計,每隔一段時間就遍歷一下這個map,然后維護一個前1000的數據list,然后去更新這個list,最后開啟一個后臺線程,每隔一段時間比如一分鐘都將排名的前1000的熱數據list同步到zk中去,存儲到這個storm task對應的一個znode中去

部署多個實例的服務,每次啟動的時候就會去拿到上述維護的storm task id列表的節點數據,然后根據taskid,一個一個去嘗試獲取taskid對應的znode的zk分布式鎖,如果能夠獲取到分布式鎖,再去獲取taskid status的鎖進而查詢預熱狀態,如果沒有被預熱過,那么就將這個taskid對應的熱數據list取出來,從而從DB中查詢出來寫入緩存中,如果taskid分布式鎖獲取失敗,快速拋錯進行下一次循環獲取下一個taskid的分布式鎖即可,此時就是多個服務實例基于zk分布式鎖做協調并行的進行緩存的預熱

緩存熱點導致系統不可用解決方案

對于瞬間大量的相同數據的請求涌入,可能導致該數據經過hash策略之后對應的應用層nginx被壓垮,如果請求繼續就會影響至其他的nginx,最終導致所有nginx出現異常整個系統變得不可用。

基于nginx+lua+storm的熱點緩存的流量分發策略自動降級來解決上述問題的出現,可以設定訪問次數大于后95%平均值n倍的數據為熱點,在storm中直接發送http請求到流量分發的nginx上去,使其存入本地緩存,然后storm還會將熱點對應的完整緩存數據沒發送到所有的應用nginx服務器上去,并直接存放到本地緩存。

對于流量分發nginx,訪問對應的數據,如果發現是熱點標識就立即做流量分發策略的降級,對同一個數據的訪問從hash到一臺應用層nginx降級成為分發至所有的應用層nginx。storm需要保存上一次識別出來的熱點List,并同當前計算出來的熱點list做對比,如果已經不是熱點數據,則發送對應的http請求至流量分發nginx中來取消對應數據的熱點標識

緩存雪崩解決方案

redis集群徹底崩潰,緩存服務大量對redis的請求等待,占用資源,隨后緩存服務大量的請求進入源頭服務去查詢DB,使DB壓力過大崩潰,此時對源頭服務的請求也大量等待占用資源,緩存服務大量的資源全部耗費在訪問redis和源服務無果,最后使自身無法提供服務,最終會導致整個網站崩潰。

事前的解決方案,搭建一套高可用架構的redis cluster集群,主從架構、一主多從,一旦主節點宕機,從節點自動跟上,并且最好使用雙機房部署集群。

事中的解決方案,部署一層ehcache緩存,在redis全部實現情況下能夠抗住部分壓力;對redis cluster的訪問做資源隔離,避免所有資源都等待,對redis cluster的訪問失敗時的情況去部署對應的熔斷策略,部署redis cluster的降級策略;對源服務訪問的限流以及資源隔離

事后的解決方案:redis數據做了備份可以直接恢復,重啟redis即可;redis數據徹底失敗來或者數據過舊,可以快速緩存預熱,然后讓redis重新啟動。然后由于資源隔離的half-open策略發現redis已經能夠正常訪問,那么所有的請求將自動恢復

緩存穿透解決方案

對于在多級緩存中都沒有對應的數據,并且DB也沒有查詢到數據,此時大量的請求都會直接到達DB,導致DB承載高并發的問題。解決緩存穿透的問題可以對DB也沒有的數據返回一個空標識的數據,進而保存到各級緩存中,因為有對數據修改的異步監聽,所以當數據有更新,新的數據會被更新到緩存匯中。

Nginx緩存失效導致redis壓力倍增

可以在nginx本地,設置緩存數據的時候隨機緩存的有效期,避免同一時刻緩存都失效而大量請求直接進入redis


以上是“Nginx+Redis+Ehcache中大型高并發與高可用的三層緩存架構分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

庄河市| 博湖县| 茶陵县| 金乡县| 潞城市| 武强县| 乐都县| 望谟县| 宁化县| 黎城县| 布拖县| 长治县| 义马市| 沙田区| 抚远县| 革吉县| 静乐县| 建德市| 都江堰市| 汽车| 建昌县| 长泰县| 平顶山市| 加查县| 阿克苏市| 临猗县| 镇宁| 田东县| 来凤县| 宜黄县| 滦南县| 遵化市| 桂平市| 淄博市| 固原市| 蒙山县| 石城县| 格尔木市| 孟州市| 高清| 邵武市|