隨着人們的生活水平的不斷提升,人們對身體健康愈來愈重視,不少人都作過體檢,通常公司都會有一年一度的體檢福利,健康體檢是家喻戶曉了。java
隨着互聯網的快速發展,同類同質產品之間的競爭愈來愈大,產品之間一個重要的差別就是用戶體驗。影響用戶體驗的,除了產品設計因素外,技術層面也是一個重要的影響因素,主要體如今服務的可用性和響應速度。提高服務可用性和響應速度如此重要,爲了實現這樣的目標,必需要有相應的手段,其中健康檢查就是保障服務可用性和快速響應一個很是重要的前提。nginx
健康檢查有哪些項目、指標和方法呢?此文帶你一一揭曉。web
健康體檢是指經過醫學手段和方法對受檢者進行身體檢查,瞭解受檢者健康情況、早期發現疾病線索和健康隱患的診療行爲。而系統的健康檢查是利用技術手段檢測網絡、主機、應用、服務等一系列對象是否健康或可用的過程。算法
互聯網產品對用戶體驗提出了很高的要求,但經常因爲技術側緣由,發生服務響應慢或者服務不可用等一系列影響用戶體驗的問題,致使業務中斷,影響收入,公司品牌和口碑也會受到巨大的負面影響。數據庫
影響服務不可用和響應慢的因素不少,多是服務硬件損壞、光纖被挖斷,多是請求量過大致使數據庫CPU負載、磁盤IO太高,又多是某同窗埋了雷,新上線的功能第一次運行就發生了OOM……後端
要保證系統高可用,咱們應該怎麼作呢?有人說,系統節點冗餘消除單節點故障不就好了嗎。說的沒錯,消除單節點是系統高可用的經常使用手段。消除單節點有一個很重要的前提是發現問題節點,把問題節點踢除或者把流量切換到其餘正常節點。服務器
如何「發現問題節點」,就是系統健康檢查須要作的事情。網絡
談論如何作健康檢查前,首先要弄明白的是要檢查的對象到底是誰。對象能夠網絡鏈接,能夠是一個小小的功能組件,能夠是一個進程,能夠是服務集羣,也能夠是機房單元。因此,要作到「高可用」,首先要弄清楚要作哪層面的高可用,哪些對象可能存在單點問題,要把「對象」搞清楚。負載均衡
那麼,健康檢查如何作呢?一般有兩種方式:主動和被動。tcp
由檢查方做爲主動方,定時主動發起健康檢查請求,請求的報文內容或者格式一般是獨立設計的,被健康的對象做簡單自檢後返回響應。舉個例子:
check interval=3000 rise=2 fall=5 timeout=1000 type=http; check_http_send "HEAD /check.do HTTP/1.0\r\n\r\n"; check_http_expect_alive http_2xx http_3xx;
配置間隔2000豪秒定時向後臺web服務器http://(ip:port)/check.do接口...
被動健康檢查不設計獨立的健康檢查請求,而是以正常鏈接狀況或者業務請求的響應做爲指標來衡量檢查對象的健康狀態。例如nginx官方開源版本的被動健康檢查配置:
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
Nginx是基於鏈接探測,若是在30s內嘗試鏈接3次失敗,則認爲後端web服務不可用。
上面談到,要實現高可用就要消除單點故障,最簡單直接的方案加備服務節點,經過定時心跳健康檢查發現主服務節點宕機後,備服務節點把主的工做接管過來,客戶端把請求流量切換到備服務節點。
主服務節點與備服務節點之間經過專用的心跳線進行健康檢查,因爲網絡分區等緣由它們可能沒法收到對方心跳,這時備節點會認爲主節點已宕機,主節點也認爲備節點已宕機,但其實主從兩節點狀態都是正常的,客戶端能正常訪問到主從兩節點,出現「雙寫」,這種現象在業界稱爲「腦裂(split-brain)」。
出現腦裂會致使數據混亂的災難事件發生,影響業務的正確性,這時引入第三方機構進行仲裁能夠有效避免腦裂的發生。出現腦裂會致使數據混亂的災難事件發生,影響業務的正確性,這時引入第三方機構進行仲裁能夠有效避免腦裂的發生。
既然主從雙方沒法確認對方的存活,出現爭議時能夠由第三方仲裁節點作出決定,到底誰是主由它說了算,第三方仲裁節點通常是由Zookeeper這種高可用方案來實現。
Keepalived是一款保證集羣高可用的服務軟件,其功能相似於heartbeat,用於防止單點故障。可是它通常不會單獨出現,而是與其它負載均衡技術(如LVS、HAProxy、Nginx)一塊兒工做來達到集羣的高可用。
它的健康檢查也包含兩個方面,一個是Keepalived組件之間的健康檢查(經過VRRP心跳報文),以下圖所示
另外一個是Keepalived組件與本地負載均衡組件的健康檢查,配置以下:
vrrp_script check_nginx_running { script "/usr/local/bin/check_running"(定義腳本) interval 10(腳本執行的間隔) weight -10(腳本執行的優先級) }
其中,應用的健康檢查方式經過自定義腳本實現。
Keepalived組件之間經過VRRP協議進行健康檢查,若是主服務器宕機,備服務器經過VRRP協議選舉成爲新的主服務器,把虛擬IP從舊的主服務器上爭搶過來,實現高可用。
VRRP報文是封裝在IP報文上的,支持各類上層協議,網絡設備一般也是使用VRRP協議實現主備高可用切換,如交換機、路由器、防火牆等。
當網絡設備發生故障時,VRRP機制可以選舉出新的網絡設備承擔數據流量,從而保障網絡的可靠通訊。
移動設備鏈接互聯網經過NAT方式,移動App的PUSH推送須要與服務器保持長鏈接,但大部分移動網絡運營商都在鏈接一段時間沒有數據交互時,會淘汰 NAT列表中的對應鏈接,形成鏈接中斷。爲了保持網絡鏈接的「健康」可用,咱們能夠在鏈接創建後,App與服務器互相按期發送Ping Pong心跳信息來保持鏈接的持續有效。
以上是應用層的鏈接健康檢查方案,操做系統也支持底層網絡的鏈接健康檢查即Keepalive。TCP Keepalive能夠在鏈接無活動一段時間後,發送一個空的探測報文,使TCP鏈接不會被客戶端或者防火牆等中間網絡設備關閉。Linux能夠經過如下三個參數對Keepalive的間隔、頻率和閾值和進行配置:
net.ipv4.tcp_keepalive_time = 7200 net.ipv4.tcp_keepalive_intvl = 75 net.ipv4.tcp_keepalive_probes = 9
主機之間的可達性能夠經過Ping命令進行識別,Ping命令使用的是ICMP協議,它能識別從客戶端到目標主機整個路徑的網絡連通性。Ping一般用於手工測試某臺主機是否啓動和網絡是否聯通。
ICMP是網絡層協議,與具體進程是不要緊的,沒法經過Ping識別進程是否存在。但進程有端口,有進程信息,能夠經過telnet端口或ps命令檢測進程是否存在。進程可能會因爲內存不足被kill或者其餘緣由異常關閉,能夠經過cron定時腳本檢測識別後自動拉起,這種方案對老破舊項目中只能單實例部署的應用的可用性提高很是有效。
NameServer是RocketMQ的路由中心,NameServer中維護着Producer集羣、Broker集羣、 Consumer集羣的服務狀態和路由信息。當有新的Consumer加入集羣時,除了上報自身信息外,還獲取各個Broker的地址、Topic、隊列等信息,這樣就能知道它消費的Topic消息存儲到哪一個Broker和隊列上。
NameServer能夠部署多個,NameServer之間相互獨立不互通。Producer、Broker、Consumer服務啓動時須要指定多個NameServer,服務的信息會同時註冊到多個指定的 NameServer上,達到高可用。
每一個Broker節點與全部NameServer會保持TCP長鏈接,每隔30s給NameServer發送心跳報文,告訴NameServer本身還活着。而每一個NameServer每隔10s檢查一下各個Broker的最近一次心跳時間,若是發現某個Broker超過120s都沒發送心跳報文,就認爲這個Broker已經宕機了,會關閉對應的網絡鏈接channel,並將其從路由信息裏移除。
一個服務實例或者進程會經過按期的心跳包向其餘服務來報告它的存活,但有這個心跳包仍是不夠的,不足以反映它的健康情況。好比磁盤空間不足了,服務已經沒法再寫數據了,但它還能響應心跳包;服務依賴Redis,但Redis服務出了問題鏈接不上,但它還能響應心跳包;服務的某些功能依賴分佈式存儲服務,但分佈式存儲服務不可用了,但它依然能響應心跳包。咱們能夠看到,要肯定一個服務實例是否存活而且「健康」,仍是有不少方面須要考慮的。Spring Boot Actuator能比較好的解決這個問題,它能反映整個服務的健康情況,包括它所依賴的子系統的健康情況。
Spring Boot Actuator是Spring Boot的一個子項目,Actuator提供Endpoint(端點)給外部應用程序進行訪問和交互。Actuator包括許多功能,好比健康檢查、審計、指標收集等等,可幫助咱們監控和管理Spring Boot應用程序。Health就是其中一個Endpoint,它提供了關於Spring Boot應用的基本健康狀況信息,容許其餘雲服務或者k8s等定時檢測到應用的健康情況,對異常狀況及時做出響應。
假如某微服務應用使用到了MySQL、Amazon S三、Elastic Search、DynamocDB這些資源系統,它的健康檢查結果就應該包含全部這些子系統的健康情況:
Actuator的健康檢查由HealthIndicator接口實現,HealthIndicator接口只有一個health()方法,返回值是Health健康對象。
@FuncationalInterface public class HealthIndicator { /** * Return an indication of health. * @result the health for */ public Health health(); }
Health對象有狀態status和details兩個字段,status默認有UNKNOWN、UP、DOWN和OUT\_OF\_SERVICE四個值,用戶能夠自定義和擴展,details是一個KV結構,用戶能夠隨意自定義要返回的數據值。
@JsonInclude(Include.NON_EMPTY) public final class Health extends HealthComponent { private final Status status; private final Map<String, Object> details; ... }
Actuator內置了不少經常使用的HealthIndicator:
用戶能夠根據實際狀況自定義,好比:
@Override public Health health() { int errorCode = check(); // perform some specific health check if (errorCode != 0) { return Health.down().withDetail("Error Code", errorCode).build(); } return Health.up().build(); }
默認狀況下health的狀態是啓用且對外開放的,經過http://locahost:8080/actuator... 「UP」},這是一個彙總的狀態,詳細的健康信息能夠經過配置項management.endpoint.health.show-details=always打開,一個完整的包含details的健康檢查信息以下:
彙總的健康狀態由 HealthAggregator 彙總而成的,彙總的算法是:全部子系統的健康狀態按DOWN、OUT\_OF\_SERVICE、UP、UNKNOWN這個順序進行排序取最前面一個狀態值。
好比ehCache是UP,MySQL是UNKNOWN,diskSpace是OUT\_OF\_SERVICE;那麼排序下來就是:OUT\_OF\_SERVICE、UP、UNKNOWN,取第一個就是OUT\_OF\_SERVICE,即服務不可用。
高可用是一個很複雜的工程問題,它是由一系列的子問題構成,健康檢查和健康度量只是其中一個。業務要保持連續不中斷,系統要保證持續運行,就要保證全鏈路全部參與的節點都是高可用的,避免出現單點故障。
如何及時發現不健康或故障的節點並告警,如何在節點出現不健康或故障時及時failfast/failover避免發生雪崩效應,健康檢查在其中扮演着很是重要的做用。
做者:vivo 互聯網服務器團隊-Chen Jianbo