使用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(中篇)

相关文章
相关标签/搜索