基於go的微服務搭建(六) - health check

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

第六節:health check
原文地址
轉載請註明原文及翻譯地址

當我們的微服務越來越複雜,讓docker swarm知道我們的服務運行良好與否很重要.下面我們來看一下如何查看服務健全狀態.
例如,我們的accountservice服務將沒用如果不能 服務http或者連結資料庫.
最好的辦法就是提供一個healthcheck存取點.我們基於http,所以映射到/health,如果運行良好,返回http 200同事一些解釋什麼是良好的資訊.如果有問題,非http 200返回,並解釋哪裡不好.有人認為都應該返回200,之後返回錯誤資訊.我同意,但是這個簡單例子中,我會用非200返回.

代碼

一樣,你可以直接branch到這部分

git checkout P6

加入BoltDB的檢查

我們的服務如果不能串連database將沒有用,因此我們加入函數 Check()

type IBoltClient interface {b    OpenBoltDb()    QueryAccount(accountId string) (model.Account, error)    Seed()    Check() bool //new}

這個函數可能很簡單,但是足夠了,他將根據BoltDb能否串連而返回true/false.

func (bc *BoltClient) Check() bool {    return bc.boltDB != nil}

mocked代碼在mackclient.go遵從stretchr/testify的形式

func (m *MockBoltClient) Check() bool {    args := m.Mock.Called()    return args.Get(0).(bool)

加入/health路徑

很直接,我們在routes.go中加入

Route{    "HealthCheck",    "GET",    "/health",    HealthCheck},

我們用函數HealthCheck來處理請求,我們把這個函數加到handler.go中:

func HealthCheck(w http.ResponseWriter, r *http.Request) {        // Since we're here, we already know that HTTP service is up. Let's just check the state of the boltdb connection        dbUp := DBClient.Check()        if dbUp {                data, _ := json.Marshal(healthCheckResponse{Status: "UP"})                writeJsonResponse(w, http.StatusOK, data)        } else {                data, _ := json.Marshal(healthCheckResponse{Status: "Database unaccessible"})                writeJsonResponse(w, http.StatusServiceUnavailable, data)        }}func writeJsonResponse(w http.ResponseWriter, status int, data []byte) {        w.Header().Set("Content-Type", "application/json")        w.Header().Set("Content-Length", strconv.Itoa(len(data)))        w.WriteHeader(status)        w.Write(data)}type healthCheckResponse struct {        Status string `json:"status"`}

HealthCheck函數用Check()函數來檢查資料庫情況.如果正常,我們返回healthCheckResponse結構的執行個體.注意這個小寫首字母,這樣只有在這個package中才能用這個結構.我們也提取出返回結果的代碼進一個函數來讓我們不重複代碼.

運行

在blog/accountservice檔案夾中,運行:

> go run *.goStarting accountserviceSeeded 100 fake accounts...2017/03/03 21:00:31 Starting HTTP service at 6767

curl這個/health路徑

> curl localhost:6767/health{"status":"UP"}

docker healthcheck

接下來,我們用docker的健全狀態檢查機制來檢查我們的服務.加入下面命令在Dockerfile:

HEALTHCHECK --interval=5s --timeout=5s CMD["./healthchecker-linux-amd64", "-port=6767"] || exit 1

healthchecker-linux-amd64是什麼?docker自己不知道怎樣做這個健全狀態檢查,我們需要幫一下,我們在CMD命令輸入來指引到/health路徑.根據exit code,docker會判斷服務良好與否.如果太多的檢查失敗,swarm會關掉容器並開啟新的執行個體
最常見的健全狀態檢查使用curl,然而這要求我們的docker鏡像安裝curl.這裡我們會用go來執行這個小程式.

建立helathchecker程式

在goblog下增加檔案夾

mkdir healthchecker

加入main.go

package mainimport (    "flag"    "net/http"    "os")func main() {    port := flag.String("port", "80", "port on localhost to check")     flag.Parse()    resp, err := http.Get("http://127.0.0.1:" + *port + "/health")    // Note pointer dereference using *        // If there is an error or non-200 status, exit with 1 signaling unsuccessful check.    if err != nil || resp.StatusCode != 200 {        os.Exit(1)    }    os.Exit(0)}

代碼不多,主要做:

  • 用內建flags讀取-port=NNNN命令參數,如果沒有,用預設連接埠80
  • 開始http get請求127.0.0.1:[port]/health
  • 如果有錯誤或者返回狀態非200,退出同一個非0值,0==成功,>0==失敗

試一下,如果你停止了accountservice,用go run *.go啟動,或者編譯它go build ./accountservice
之後回到後台運行healthchecker

> cd $GOPATH/src/github.com/callistaenterprise/goblog/healthchecker> go run *.goexit status 1

哎呀!我們忘記給連接埠號碼了.再試一次

> go run *.go -port=6767>

沒有輸出表示我們成功了.好,讓我們編譯一個linux/amd64二進位並加入到accountservice中,通過加入healthchecker在dockerfile中. 我們用copyall.sh指令碼來做:

#!/bin/bashexport GOOS=linuxexport CGO_ENABLED=0cd accountservice;go get;go build -o accountservice-linux-amd64;echo built `pwd`;cd ..// NEW, builds the healthchecker binarycd healthchecker;go get;go build -o healthchecker-linux-amd64;echo built `pwd`;cd ..export GOOS=darwin   // NEW, copies the healthchecker binary into the accountservice/ foldercp healthchecker/healthchecker-linux-amd64 accountservice/docker build -t someprefix/accountservice accountservice/

同時,我們更新accountservice的dockerfile:

FROM iron/baseEXPOSE 6767ADD accountservice-linux-amd64 /# NEW!! ADD healthchecker-linux-amd64 /HEALTHCHECK --interval=3s --timeout=3s CMD ["./healthchecker-linux-amd64", "-port=6767"] || exit 1ENTRYPOINT ["./accountservice-linux-amd64"]

加入的部分

  • 加入一個ADD語句來確定healthchecker加入到鏡像中.
  • HEALTHCHECK語句告訴docker每3s執行一次,逾時為3s

部署healthcheck

現在我們能部署帶有healthchecking的accountservice了.自動化來做這些事,加入兩行到copyall.sh中:

docker service rm accountservicedocker service create --name=accountservice --replica=1 --network=my_network -p=6767:6767someprefix/accountservice

運行./copyall.sh等幾秒,之後檢查容器狀態,docker ps:

> docker psCONTAINER ID        IMAGE                             COMMAND                 CREATED        STATUS                1d9ec8122961        someprefix/accountservice:latest  "./accountservice-lin"  8 seconds ago  Up 6 seconds (healthy)107dc2f5e3fc        manomarks/visualizer              "npm start"             7 days ago     Up 7 days

我們看到(healthy)欄位在status欄,沒有健全狀態檢查的服務不會有這個提示.

看一下失敗的情形

讓我們加入可以測試的api來讓路徑表現的不健康.在routes.go中,加入新路徑:

Route{        "Testability",        "GET",        "/testability/healthy/{state}",        SetHealthyState,},    

這個路徑(你不應該包括他在生產環境)提供我們一個讓健全狀態檢查失敗的方法.SetHealthyState函數在handlers.go中:

var isHealthy = true // NEWfunc SetHealthyState(w http.ResponseWriter, r *http.Request) {        // Read the 'state' path parameter from the mux map and convert to a bool        var state, err = strconv.ParseBool(mux.Vars(r)["state"])                // If we couldn't parse the state param, return a HTTP 400        if err != nil {                fmt.Println("Invalid request to SetHealthyState, allowed values are true or false")                w.WriteHeader(http.StatusBadRequest)                return        }                // Otherwise, mutate the package scoped "isHealthy" variable.        isHealthy = state        w.WriteHeader(http.StatusOK)}

重啟accountservice

func HealthCheck(w http.ResponseWriter, r *http.Request) {        // Since we're here, we already know that HTTP service is up. Let's just check the state of the boltdb connection        dbUp := DBClient.Check()                if dbUp && isHealthy {              // NEW condition here!                data, _ := json.Marshal(                ...        ...        }

重新請求healthcheck

> cd $GOPATH/src/github.com/callistaenterprise/goblog/accountservice> go run *.goStarting accountserviceSeeded 100 fake accounts...2017/03/03 21:19:24 Starting HTTP service at 6767

第一次嘗試成功,現在改變accountservice用curl請求到測試路徑

> curl localhost:6767/testability/healthy/false> go run *.go -port=6767exit status 1

工作正常,讓我們在docker swarm中運行,用copyall.sh重新編譯和部署

> cd $GOPATH/src/github.com/callistaenterprise/goblog> ./copyall.sh

等一會,之後運行docker ps來看我們的健康服務

> docker psCONTAINER ID    IMAGE                            COMMAND                CREATED         STATUS 8640f41f9939    someprefix/accountservice:latest "./accountservice-lin" 19 seconds ago  Up 18 seconds (healthy)

注意CONTAINER ID和CREATED.請求測試api,我的是192.168.99.100

> curl $ManagerIP:6767/testability/healthy/false>

現在,運行docker ps

> docker psCONTAINER ID        IMAGE                            COMMAND                CREATED         STATUS                                                             NAMES0a6dc695fc2d        someprefix/accountservice:latest "./accountservice-lin" 3 seconds ago  Up 2 seconds (healthy)

看,一個新的CONTAINER ID和新的CREATED和STATUS時間戳記.因為swarm每三秒會檢查一次,之後探索服務不健康,所以用一個新的服務替換掉,並且不需要管理員的插手

總結

我們加入一個簡單的/health路徑和一些docker的健全狀態檢查機制.展示swarm是如何控制非健康服務的.
下一節,我們會深入swarm,我們會關注微服務兩個架構:服務發現和負載平衡.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.