本文將介紹整年4個9(99.99%)的系統可用性方案nginx
在系統的高可靠性裏有個衡量其可靠性的標準——X個9,這個X是表明數字3~5。X個9表示在系統1年時間的使用過程當中,系統能夠正常使用時間與總時間(1年)之比git
系統可用性的計算公式:A=MTBF/(MTBF+MTTR)github
拿365天(1年)作計算吧,看看幾個9要停機多久時間作能才能達到!web
1年 = 365天 = 8760小時
99.9 = 8760 * 0.1% = 8760 * 0.001 = 8.76小時
99.99 = 8760 * 0.0001 = 0.876小時 = 0.876 * 60 = 52.6分鐘
99.999 = 8760 * 0.00001 = 0.0876小時 = 0.0876 * 60 = 5.26分鐘算法
本文設計技術點:spring
LVS 是 Linux Virtual Server
(Linux 虛擬服務器) 的簡稱,目前 LVS 已是 Linux 內核標準的一部分,LVS 工做在網絡 4 層之上僅做分發之用,因此抗負載能力比較強。LVS 有完整的雙機熱備方案,幾乎支持對全部應用作負載均衡。LVS 在互聯網應用中的位置是在 Nginx 之上後端
LVS 自己只是一個叫 IP_VS
的內核模塊,這個模塊能夠作負載均衡,可是隻用這個模塊來作應用負載是遠遠不夠的,好比 LVS 自己宕機後如何處理?實際生產環境中,通常配合 Keepalived
來使用 LVS,keepalived
支持 VRRP
心跳協議,能夠實現 LVS 主備冗餘,以解決 LVS 自己單點故障。另外,Keepalived 支持健康檢測,網絡 4 層和 7 層健康檢測,防止服務器宕機。 瀏覽器
Keepalived做爲一個高性能集羣軟件,它還能實現對集羣中服務器運行狀態的監控以及故障隔離,下面咱們介紹一下Keepalived對服務器運行狀態和故障隔離的工做原理。tomcat
Keepalived工做在TCP/IP 模型的 三層(網絡層)、四層(傳輸層)、七層(應用層),根據TCP、IP 模型各層所能實現的功能,Keepalived運行機制以下:服務器
在網絡層(3):咱們知道運行中有4個重要的協議。互聯網絡IP協議、互聯網絡可控制報文協議ICMP、地址轉換協議ARP、反向地址轉換協議RARP,Keepalived在網絡層採用最多見的工做方式是經過ICMP協議向服務器集羣中的每個節點發送一個ICMP數據包(有點相似與Ping的功能),若是某個節點沒有返回響應數據包,那麼認爲該節點發生了故障,Keepalived將報告這個節點失效,並從服務器集羣中剔除故障節點。
在傳輸層(4):提供了兩個主要的協議:傳輸控制協議TCP和用戶數據協議UDP,傳輸控制協議TCP能夠提供可靠的數據輸出服務、IP地址和端口,表明TCP的一個鏈接端,要得到TCP服務,須要在發送機的一個端口和接收機的一個端口上創建鏈接,而Keepalived在傳輸層裏利用了TCP協議的端口鏈接和掃描技術來判斷集羣節點的端口是否正常,好比對於常見的WEB服務器80端口。或者SSH服務22端口,Keepalived一旦在傳輸層探測到這些端口號沒有數據響應和數據返回,就認爲這些端口發生異常,而後強制將這些端口所對應的節點從服務器集羣中剔除掉。
在應用層(7):能夠運行FTP,TELNET,SMTP,DNS等各類不一樣類型的高層協議,Keepalived的運行方式也更加全面化和複雜化,用戶能夠經過自定義Keepalived工做方式,例如:能夠經過編寫程序或者腳原本運行Keepalived,而Keepalived將根據用戶的設定參數檢測各類程序或者服務是否容許正常,若是Keepalived的檢測結果和用戶設定的不一致時,Keepalived將把對應的服務器從服務器集羣中剔除
VRRP
能夠將兩臺或者多臺物理路由器設備虛擬成一個虛擬路由
,這個虛擬路由器經過虛擬IP(一個或者多個)對外提供服務,而在虛擬路由器內部十多個物理路由器協同工做,同一時間只有一臺物理路由器對外提供服務,這臺物理路由設備被成爲:主路由器(Master角色),通常狀況下Master是由選舉算法產生,它擁有對外服務的虛擬IP,提供各類網絡功能,如:ARP請求,ICMP 數據轉發等,並且其它的物理路由器不擁有對外的虛擬IP,也不提供對外網絡功能,僅僅接收MASTER的VRRP狀態心跳信息,這些路由器被統稱爲BACKUP
的角色」,當主路由器失敗時,處於BACKUP
角色的備份路由器將從新進行選舉,產生一個新的主路由器進入MASTER
角色,繼續提供對外服務,整個切換對用戶來講是徹底透明的。
缺點:
- 非高可用,web-server掛了整個系統就掛了
- 擴展性差,當吞吐量達到web-server上限時,沒法擴容
注:單機不涉及負載均衡的問題
假設tomcat的吞吐量是1w次每秒,當系統總吞吐量達到3w時,如何擴容是首先要解決的問題,DNS輪詢是一個很容易想到的方案:
優勢:
- 零成本:在DNS-server上多配幾個ip便可,功能也不收費
- 部署簡單:多部署幾個web-server便可,原系統架構不須要作任何改造
- 負載均衡:變成了多機,但負載基本是均衡的
缺點:
- 非高可用:DNS-server只負責域名解析ip,這個ip對應的服務是否可用,DNS-server是不保證的,假設有一個web-server掛了,部分服務會受到影響
- 擴容非實時:DNS解析有一個生效週期
- 暴露了太多的外網ip
tomcat的性能較差,但nginx做爲反向代理的性能就強多了,假設線上跑到1w,就比tomcat高了10倍,能夠利用這個特性來作擴容:
優勢:
- DNS-server不須要動
- 負載均衡:經過nginx來保證
- 只暴露一個外網ip,nginx->tomcat之間使用內網訪問
- 擴容實時:nginx內部可控,隨時增長web-server隨時實時擴容
- 可以保證站點層的可用性:任何一臺tomcat掛了,nginx能夠將流量遷移到其餘tomcat
缺點:
- 時延增長+架構更復雜了:中間多加了一個反向代理層
- 反向代理層成了單點,非高可用:tomcat掛了不影響服務,nginx掛了怎麼辦?
爲了解決高可用的問題,keepalived出場了
優勢:
- 解決了高可用的問題
缺點:
- 資源利用率只有50%
- nginx仍然是接入單點,若是接入吞吐量超過的nginx的性能上限怎麼辦,例如qps達到了50000咧?
nginx畢竟是軟件,性能比tomcat好,但總有個上限,超出了上限,仍是扛不住。lvs就不同了,它實施在操做系統層面, 性能比nginx好不少,例如每秒能夠抗10w,這樣能夠利用他們來擴容,常見的架構圖以下:
缺點 不論是使用lvs仍是f5,這些都是scale up的方案,根本上,lvs/f5仍是會有性能上限,假設每秒能處理10w的請求,一天也只能處理80億的請求(10w秒吞吐量*8w秒),那萬一系統的日PV超過80億怎麼辦呢?(好吧,沒幾個公司要考慮這個問題)
水平擴展,是解決性能問題的根本方案,經過加機器擴充性能的方案才具有最好的擴展性。 facebook,google,baidu的PV是否是超過80億呢,它們的域名只對應一個ip麼,終點又是起點,仍是得經過DNS輪詢來進行擴容: 此時:
這一部分跳過了,微服務集羣化部署的相關的文章不少,本文篇幅有限,想了解的朋友請自行查找閱讀。
微服務架構中的應用優雅停機主要是指應用實例有計劃而平滑(即不產生須要處理的事故)的退出。應用服務器的停機主要分爲兩類:主動停機和被動停機,而其中主動停機和大部分的被動停機都是能夠實現優雅停機。若是應用不作優雅停機,則會帶來如下狀況:
微服務的優雅升級的目標就是避免以上幾種狀況,從而避免人工干預的工做量和提高微服務架構的服務高可靠。
優雅停機能夠解決如下場景:
優雅停機解決不了如下場景:
Java的優雅停機一般經過註冊JDK的ShutdownHook(鉤子)來實現,當系統接收到退出指令後,首先標記系統處於退出狀態,再也不接收新的消息,而後將積壓的消息處理完,最後調用資源回收接口將資源銷燬,最後各線程退出執行。簡單的使用demo案例以下(簡單版):
/**
* 優雅停機處理方式
*
* @author lry
**/
public class Main{
/**
* 啓動應用
**/
public void start(){
// 第一步:啓動應用服務……
// 第二步:註冊JDK鉤子
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The hook running...");
//第三步:調用停機處理
stop();
}
}));
}
/**
* 中止應用
**/
public void stop(){
// 中止應用前停機處理(如:註銷服務、標記不接受請求等)
}
}
複製代碼
注:一般優雅退出須要有超時控制機制,若是到達超時時間仍然沒有完成退出前的資源回收等操做,則由停機腳本直接調用KILL -9 PID的方式進行強制退出,否則可能會等待很長時間。
能夠遵照如下建議規則來設計微服務的優雅停機機制
微服務應用的優雅停機根據其使用者角色的不一樣,而主要分爲兩種類型
上圖1-6步操做在大多數微服務框架中都已經集成了,無需開發人員自主開發,若是某些採用自研微服務框架的公司沒有這方面功能,開發人員能夠先行在本身負責的業務系統中編寫ShutdownHook來完成相同操做。
若是不支持Nginx動態發現網關,則停機升級切換的過程須要人工接入,稍微費力點,但一樣對用用戶來講是沒法感知到的。
結合接入層的負載均衡高可用與微服務架構的高可用涉及,能夠作到任意時間升級而不影響用戶體驗,不形成生產事故。但仍是沒實現全自動的流程,由於Nginx不支持動態發現網關並修改配置生效。
社區經常使用的 upstream 動態更新方案有 4 個
這些插件有一個共同點,那就是在不須要重啓nginx的基礎上, 動態修改nginx的配置。
基於以上插件呢,能夠略作修改,使其支持nacos/zookeeper/consol/erueka等註冊中心的服務發現,定製須要的nginx reload upstream 動態更新模塊便可。