1. 程式人生 > >Nginx+Redis+Ehcache大型高並發高可用三層架構總結

Nginx+Redis+Ehcache大型高並發高可用三層架構總結

緩存機制 redis集群架構 salve bsp 機房 模板 不可 周期 jvm

在生產環境中,對於高並發架構,我們知道緩存 是最重要的環節,對於大量的高並發。可以采用三層緩存架構來實現,也就是Nginx+Redis+Ehcache

技術分享圖片

對於中間件Nginx常來做流量分發,同事nginx本身也有自己的緩存機制,但是呢,容量也是有限,我們可以用來緩存熱點數據,讓用戶的請求直接走緩存並返回,從而減少流向服務器的流量

一:模板引擎

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

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

二:雙層nginx來提升換成你命中率

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

分發層nginx負責流量 分發的邏輯和策略,根據自己定義的一些規則,比如根據productld(產品表示)進行hash,然後對後端nginx數據訪問 固定路由到一個nginx後端服務器上去,後端nginx用來緩存一些熱點數據到自己的緩存區;

技術分享圖片

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

一:持久化機制

所謂持久化 機制就是講redis內存中的數據持久化到磁盤中,然後可以定期講磁盤文件上傳到S3或 這雲存儲 服務上去

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

Ps:又一個坑需要踩,對於想從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有一定的影響,能夠盡量保證數據的完整性,redis通過rewrite機制來保障AOF文件不會太大,基於內存數據並做到適當的指令重建

二:redis集群

replication

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

sentinal哨兵

哨兵是redis集群架構中很重要的一個組件,負責監控redis master和slave進程是夠正常工作,當某個redis實例出現故障時,能夠發送告警通知到管理員,當master node宕機能夠自動轉移到slave node上

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

redis cluster

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

技術分享圖片

Tomcat jvm堆內存緩存,主要是抗redis出現大規模災難,如果redis出現了大規模的宕機,導致nginx大量流量直接永祥數據生產服務器,那麽最後tomcat堆內存緩存也可以處理部分請求,避免所有請求都直接流向數據庫;

【緩存數據更新策略】

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

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

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

將數據庫與緩存更新的讀寫操作進行異步串行化,當跟新數據的時候,根據數據的唯一標識,將更新數據操作路由到一個jvm內部隊列中,一個隊列對應一個工作線程,線程串行隨後在隊列裏一條一條的執行,當執行隊列中的更新數據操作,刪除緩存,然後去更新數據庫,此時還沒有完成更新的時候過來一個讀請求,讀到了空緩存,那麽可以先將緩存更新之後的請求發送到路由之後的隊列中,此時會在隊列積壓,然後同步等待緩存更新完成,

【緩存雪崩解決方案】

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

事前解決方案:搭建一套高可用架構redis cluster集群,主從架構,一主多從,並且最好使用雙機房部署集群

事中解決方案:部署一層ehcache緩存,在整個redis集群中能夠扛得住部分壓力,對redis cluster的訪問做資源隔離,避免所有資源都請求等待,對redis cluster的訪問失敗這種情況應該實施熔斷策略,對源服務訪問進行限流以及資源隔離

事後解決方案:redis數據做了備份可以直接恢復,重啟redis即可,redis數據徹底丟失或者數據過舊,可以快速緩存預熱,然後讓redis重新啟動,最後由於資源隔離的half-open策略發現redis恢復正常,那麽所有的請求將自動恢復

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

這個時候我們可以在nginx本地設置緩存數據的時候設置緩存有效期,避免同一時間緩存都失效導致大量的請求直接進入redis

Nginx+Redis+Ehcache大型高並發高可用三層架構總結