使用go chassis進行微服務路由管理

引言

隨着微服務的快速發展,愈來愈多的公司選擇使用「金絲雀發佈」的模式進行軟件的發佈。在本文中我將經過華爲的開源微服務框架:go-chassis,向各位介紹如何經過對router的管理從而達到金絲雀發佈的目的。git

               

                                                            圖一
github

Go-chassis實現金絲雀發佈

金絲雀發佈:又叫灰度發佈,使程序能夠在黑白之間進行新老版本平滑過分地發佈,使應用能夠更加平穩地升級。 如圖一所示,須要將原100%訪問 version 1.0的流量一半分流至新的版本version 2.0,此時咱們經過如下簡單的配置,咱們就能夠實現圖一所示的效果。apache

routeRule:

 RESTServer: 

 - precedence: 1 # 優先級,數字越大優先級越高

 route: #路由規則列表

 - tags:

 version: 1.0 #對接service center的話,若是不填就自動爲0.1

 weight: 50 #全重 50%到這裏

 - tags:

 version: 2.0 

 weight: 50 #全重 50%到這裏複製代碼

經過流量的分流,在老版本依舊正常服務的狀況下,經過引流部分流量訪問新的版本,進行新版本的發佈。若是新版本一切正常,以及用戶對新功能也滿意,咱們就能夠逐步將本來分流至version 1.0的流量所有分流至version 2.0。等所有請求version 2.0後,咱們就能夠將version 1.0 服務逐步下線。可是若是version 2.0在運行過程當中出現嚴重的問題,也能夠迅速將請求所有訪問version 1.0,而後將新本版所有下線。json

此時也許會有人問,咱們不單單是爲了將全部的請求進行分流,咱們僅僅須要某些功能進行分流,如圖二bash


                                                              圖二restful

圖二中,咱們只是須要將header含有chassis:v2進行分流,將80%的請求訪問新斑斑,其他的請求將繼續訪問老版本。此時咱們可使用以下配置已達到圖二中特定的效果app

routeRule:

 RESTServer: #這裏就是請求裏的host,也是sc裏的service name

 - precedence: 1 # 優先級,數字越大優先級越高

 route: #路由規則列表

 - tags:

 version: 1.0 #對接service center的話,若是不填就自動爲0.1

 weight: 100 #全重 100%到這裏

 - precedence: 2

 match:

 headers:

 Chassis: # 請求header中有V2

 regex: V2

 route: #路由規則列表

 - tags:

 version: 2.0

 weight: 80 #權重80%到這裏

 - tags:

 version: 1.0

 weight: 20 #權重100%到這裏複製代碼

1 Go-chassis介紹

源碼倉庫 : go-chassis框架

go-chassis文檔less

go-chassis 是華爲的一個開源微服務框架,該框架集成了許多功能,爲求爲廣大使用者這提供一站式的服務。curl

2 Go-chassis的路由管理介紹

go-chassis的路由管理可根據版本設置流量權重,header匹配,模板匹配等規則進行設置,讓你輕鬆經過路由管理實現金絲雀發佈。

2.1 路由管理配置說明

配置項

說明

precedence

優先級配置,數字越大則優先級越高

match

匹配特定請求,未定義則匹配任何請求

headers

header規則設置,支持正則, 等於, 小於, 大, 於不等於等匹配方式

router

配置路由規則列表

tags

tags屬性的配置,用於路由分發規則的version和appID

weight

router下的tag規則設置,設置請求權重,值爲0-100之間

version

router下的tag規則設置,設置請求的version,與weight搭配使用

refer

指定須要引用的模板,使用定義的模板名稱

sourceTemplate

定義請求模板

  • header說明

若是headers下同時配置多個匹配條件,則須要同時知足全部配置條件,纔會執行該header下的router規則

exact : 精確匹配, 必須等於該配置值

regex:按正則匹配header內容

noEqu:不等於。Header不等於配置值

noLess:大於等於。header不小於配置值

noGreater:小於等於。header不大於配置值

greater:大於。header大於配置值

less:小於。header小於配置值

在文中,將會經過展現demo使用的router配置進行詳細的介紹,以及實現的功能進行說明

3快速入門---router 

例子中使用的go-chassis的rest協議

運行前,請前往一下地址下載 server center,並啓動server center
  •  安裝

go get -u github.com/go-chassis/go-chassis複製代碼

server-v1

在conf文件下新增或修改你的配置文件

配置microservice.yaml

---

#Private property of microservices

service_description:

  name: RESTServer

  version: 1.0複製代碼

name:配置你的服務名

version:配置服務版本號

配置chassis.yaml

---

cse:

 service:

 registry:

 address: http://127.0.0.1:30100 # 

 scope: full #set full to be able to discover other app's service

 protocols:

 rest:

 listenAddress: 127.0.0.1:9091複製代碼

  • address:爲註冊服務中心的地址,下載後爲進行任何修改,默認爲127.0.0.1:30100,如你已經進行修改,請使用本身修改後的值
  • rest: 所選用的通信協議,如爲grpc,則填寫grpc
  • listenAddress:爲服務監聽的IP和端口

代碼演示

在這裏使用的rest協議,須要聲明所須要的struct,以及實現URLPatterns,該方法主要用於路由的設置。

HelloServer

// HelloServer

type HelloServer struct {

}複製代碼

URLPatterns

// URLPatterns

func (*HelloServer) URLPatterns() []restful.Route {

   return []restful.Route{
      {Method: http.MethodGet, Path: "/hello/{name}", ResourceFuncName: "Hello"},

   }
}複製代碼

完整代碼以下


package main



import (

   "net/http"


   "github.com/go-chassis/go-chassis"

   "github.com/go-chassis/go-chassis/core/lager"

   "github.com/go-chassis/go-chassis/core/server"

   "github.com/go-chassis/go-chassis/server/restful"

)


func main() {

   chassis.RegisterSchema("rest", &ServerStruct{}, server.WithSchemaID("Hello"))

   if err := chassis.Init(); err != nil {

      lager.Logger.Error("Init failed." + err.Error())

      return

   }

   chassis.Run()

}



// HelloServer

type HelloServer struct {

}



// Hello

func (*HelloServer) Hello(ctx *restful.Context) {

   name := ctx.ReadPathParameter("name")

   ctx.Write([]byte("Chassis V1.0 hello : " + name))

}



// URLPatterns

func (*ServerStruct) URLPatterns() []restful.Route {

   return []restful.Route{

      {Method: http.MethodGet, Path: "/hello/{name}", ResourceFuncName:"Hello"},

   }

}複製代碼

啓動server V1

go build main.go

./main複製代碼

若是你直接啓動,須要設置環境變量:CHASSIS_HOME,若是未設置該環境變量,啓動時將找不到你的配置文件

CHASSIS_HOME=/{path}/{to}/serverV1/複製代碼

也就是你的conf所在的目錄

 server-v2

與server-v1相似,只要修改一下幾個地方便可

在 microservice.yaml 中將version修改成2.0,此處沒強制性要求,只要修改和不一致便可。修改Hello 方法,爲了方便區分服務之間的不一樣

// Hello

func (*HelloServer) Hello(ctx *restful.Context) {

   name := ctx.ReadPathParameter("name")

   ctx.Write([]byte("Chassis V2.0 hello : " + name))

}複製代碼

修改chassis.yaml中的監聽端口

完成以上修改了,就能夠啓動server-v2了

Client

前面介紹到的路由管理,也是在client端進行配置,下面展現在例子中使用到router.yaml配置

routeRule:

  RESTServer: # server設置的name,也是sc裏的service name

    - precedence: 1 # 優先級,數字越大優先級越高

      route: #路由規則列表

      - tags:

          version: 1.0 #對接service center的話,若是不填就自動爲0.1

        weight: 50 #全重 50%到這裏

      - tags:

          version: 2.0 #對接service center的話,若是不填就自動爲0.1

        weight: 50 #全重 50%到這裏

    - precedence: 2

      match:

        headers:

          Chassis: # 請求header中有v1 

            regex: v1

      route: #路由規則列表

      - tags:

          version: 1.0

        weight: 80 #權重 80%到這裏

      - tags:

          version: 2.0

        weight: 20 #權重 20%到這裏

    - precedence: 2

      match:

        headers:

          Chassis: # 請求header中有v2 

            regex: v2

      route: #路由規則列表

      - tags:

          version: 2.0

        weight: 80#權重 80%到這裏

      - tags:

          version: 1.0

        weight: 20 #權重 20%到這裏複製代碼

說明:

以上配置中當沒有在請求的header中設置任何值的狀況下,全部的請求將平均分配到兩個sever,可是當在header中設置 v1,此時請求將有80%分流到版本爲1.0的服務中,20%分流到版本爲2.0的服務中,而若是在header中設置了v2,則和設置v1時恰好相反。在配置文件中使用到的RESTServer爲你開發的服務名稱,若是你服務名爲 RESTxxx,則此處的RESTServer就改成RESTxxx便可。同時在設置header匹配條件是的chassis:v1也是任意的鍵值對,只要在請求時的header設置與配置一致事,router策略的配置便可生效。

client修改microservice.yaml和chassis.yaml文件,與服務端相似,name咱們修改成:RESTClient,監聽地址配置爲:8080

client代碼演示

package main

import (
   "context"
   "fmt"
   "net/http"
   "strconv"

   "github.com/go-chassis/go-chassis/core"
   "github.com/go-chassis/go-chassis"
   "github.com/go-chassis/go-chassis/client/rest"
   "github.com/go-chassis/go-chassis/core/lager"
   "github.com/go-chassis/go-chassis/core/server"
   "github.com/go-chassis/go-chassis/server/restful"    "github.com/go-chassis/go-chassis/pkg/util/httputil"

)


func main() {

   chassis.RegisterSchema("rest", &ClientStruct{}, server.WithSchemaID("Hello"))

   if err := chassis.Init(); err != nil {

      lager.Logger.Error("Init failed." + err.Error())

      return

   }

   chassis.Run()

}

type ClientStruct struct {

}type result struct {

   Reply string

   Error string

}

func (*ClientStruct) Hello(ctx *restful.Context) {

   url := ctx.ReadRequest().URL

   times := ctx.ReadQueryParameter("times")

   sefverName := ctx.ReadQueryParameter("server")

   timeNum, _ := strconv.Atoi(times)

   results := []result{}

   for i := 0; i < timeNum; i++ {

      result := invoker(url.Path, sefverName)

      results = append(results, result)

   }

   ctx.WriteJSON(results, "application/json")

}

func invoker(url, serverName string) result {
   callUrl := fmt.Sprintf("cse://%s/%s", serverName, url)

   req, err := rest.NewRequest(http.MethodGet, callUrl,nil)

   if err != nil {

      return result{Error: err.Error()}

   }

    // req.Header.Set("Chassis", "v1") resp, err :=core.NewRestInvoker().ContextDo(context.TODO(), req)

   if err != nil {

      return result{Error: err.Error()}

   }

   if resp.StatusCode >= 200 || resp.StatusCode <=304 {

      return result{Reply: string(httputil.ReadBody(resp))}
   }

   return result{Reply: string(httputil.ReadBody(resp))}

}

// URLPatterns

func (*ClientStruct) URLPatterns() []restful.Route
{
   return []restful.Route{
      {Method: http.MethodGet, Path: "/hello/{name}", ResourceFuncName: "Hello"},
   }
}複製代碼

演示代碼中使用到的times主要爲了實現一次請求,咱們能夠屢次向sever發起請求,簡化測試。爲了簡化,在client所提供的route和server是一致的,直接將請求在拼接「cse://」後就能夠轉發至server,查詢參數中server獲取值爲啓動的服務名稱,通常client和server對外提供通常是不一致的,這裏只是爲了demo演示方便。

client代碼編寫完而且啓動後,使用以下命令進行訪問

curl  http://127.0.0.1:8080/hello/chassis?times=10&server=RESTServer複製代碼

最後推薦關於go-chassis的文章,如下的文章可讓你更加深刻的對go-chassis的進行了解

Go語言微服務開發框架實踐-go chassis(上篇)

Go語言微服務開發框架實踐-go chassis(中篇)

相關文章
相關標籤/搜索