# 容錯
在分布式系統中,世界各地的故障一直在發生。Micro試圖用一些容錯的最佳實踐來解決這個問題。本文檔介紹了一些可以配置的方法。
## 心跳
心跳是服務發現中刷新注冊的機制。
### 基本原理
服務在啟動時注冊服務發現,并在關閉時取消注冊。有時這些服務可能會意外死亡,被強行殺死或面臨暫時的網絡問題。在這些情況下,遺留的節點將存在服務發現中。如果服務被自動刪除,這將是理想的。
### 解決辦法
由于這個確切原因,Micro支持注冊的TTL選項和間隔。TTL指定在發現之后注冊的信息存在多長時間,然后過期并被刪除。時間間隔是服務應該重新注冊的時間,以保留其在服務發現中的注冊信息。
這些選項可以用micro工具包中提供的標志。
### 用法
對于micro工具包,只需使用內置標志來設置ttl和間隔。
```
micro --register_ttl=30 --register_interval=15 api
```
以上這個例子,我們設置了一個30秒的ttl,重新注冊間隔為15秒。
對于go-micro,當聲明一個微服務時,你可以通過time.duration傳遞選項。
```
service := micro.NewService(
micro.Name("com.example.srv.foo"),
micro.RegisterTTL(time.Second*30),
micro.RegisterInterval(time.Second*15),
)
```
## 負載均衡
負載均衡是傳輸請求負載或維持高可用性的一種方式
### 基本原理
任何單個流程應用程序的可用性和擴展都存在限制。如果應用程序因任何原因死亡,您將無法再處理請求。如果有足夠的請求負載發送到應用程序,它可能會開始緩慢響應或根本不響應。通過發送請求至多個應用程序副本可以解決這些問題。
### 解決辦法
Micro通過[選擇器](https://godoc.org/github.com/micro/go-micro/selector#Selector)接口進行客戶端負載平衡,以在任意數量的服務節點上傳播請求。當服務啟動時,它將服務發現注冊為具有唯一地址和ID的服務節點。在發出請求時,Micro客戶端使用選擇器來決定向哪個節點發出請求。選擇器使用服務注冊表查找服務的節點,然后使用負載均衡策略(例如:隨機哈希或循環法)選擇要發送請求的節點。
### 用法
客戶端負載平衡內置于go-micro客戶端。這是自動完成的。
## 重試
重試是一種在不成功時重試請求的方法
### 基本原理
由于許多原因,請求可能會失敗; 網絡錯誤,請求加載,應用程序死亡。在這些情況下,如果我們可以針對不同的應用程序副本重試請求以獲得成功的響應,那將是理想的。
### 解決辦法
微客戶端包括一個重試請求的機制。選擇器(如上所述)返回一個Next函數,該函數在執行時使用負載平衡策略從列表中返回一個節點。Next函數可以執行多次,根據負載均衡策略返回一個新節點。如果設置了重試次數,如果請求失敗,則會執行Next函數,并且將針對新節點重試請求。
### 用法
重試可以設置為客戶端的標志或選項。它默認為1,意味著1次嘗試請求。
通過標志進行更改。
```
micro --client_retries=3
```
通過選項進行設置。
```
client.Init(
client.Retries(3),
)
```
## 緩存發現
發現緩存是服務發現信息的客戶端緩存
### 基本原理
服務發現是微服務的核心依賴,但如果架構不正確,也可能成為單點故障。每個發現系統都有自己的擴展性和高可用性。在事件發生下降的情況下,由于服務不知道如何解析名稱到地址,系統的其余部分將無法使用。如果為系統中的每個請求執行查找,發現也可能成為瓶頸。
### 解決辦法
客戶端緩存是一種消除服務發現瓶頸和單點故障的方法。Micro包含一個選擇器(客戶端負載平衡器),它在服務發現信息的內存緩存中維護與之相關的信息。如果發生緩存未命中,選擇器將使用服務注冊表進行查找并緩存數據。緩存也會周期性地被TTL掉,以確保陳舊的數據不會存在。
### 用法
高速緩存選擇器可以通過標志或在創建新服務時進行設置。
作為工具包的標志執行以下操作
```
micro --selector=cache api
```
如果調用Init方法,Go-micro服務也可以使用相同的標志。或者,選擇器可以用代碼設置。
```
import (
"github.com/micro/go-micro/client"
"github.com/micro/go-micro/selector/cache"
)
service := micro.NewService(
micro.Name("com.example.srv.foo"),
)
service.Client().Init(cache.NewSelector())
```