[关闭]
@pockry 2018-01-22T17:03:13.000000Z 字数 8793 阅读 2636

使用ServiceComb Go-chassis构建微服务

架构 微服务

作者:李波


近日,Apache基金会孵化项目ServiceComb开源了该项目旗下的Go语言微服务框架Apache ServiceComb Go-chassis(以下简称Go-chassis)。作为ServiceComb生态中的重要一环,Go-chassis将和已经开源的Apache ServiceComb Java-chassis一道,为用户带来良好的框架级多语言微服务编程体验。

什么是chassis?

Chassis,直译成中文是底盘的意思,它是一种微服务模式,由微服务大师Chris Richardson提出。在这种模式中,用户并不需要自己去处理构建微服务过程中外部配置、日志、健康检查、分布式追踪等那些横切关注点(crosscutting concern),而是将他们交给专门的框架来处理。用户可以更聚焦业务逻辑本身,简单、快速的开发微服务。

Apache ServiceComb Go-chassis简介

image

Go-chassis是一个用Go语言编写的微服务快速开发框架,采用插件化设计,将各种功能模块定义为接口,实现功能“可插拔”的同时也带来了非常好的扩展性;用户可以定制开发自己的通讯协议、处理链,对接自己的配置中心、服务发现中心等。Go-chassis的模块及工作流程如上图所示,不同协议请求进入到各协议Server,Server将具体的协议请求转换为Invocation统一抽象模型,并传入Handler chain( 框架内默认内置了大部分微服务治理所需的handler),最终再进入Transport handler,使用具体的协议客户端传输到目标。

目前,Go-chassis支持的特性包括但不限于:

在通讯协议方面,Go-chassis原生支持REST/Http 和 Highway协议,其中Highway是ServiceComb开发的、基于RPC的高性能通讯协议。

使用Go-chassis开发体质指数应用(BMI)

下面,我们将以简单的体质指数应用(BMI)为例,说明如何用Go-chassis快速开发微服务。BMI是国际上常用的衡量人体胖瘦程度的一个标准,我们开发的BMI应用主要包含两个微服务:

两个微服务之间的关系如下图所示,它们之间通过REST方式进行通信。

image

准备工作

在开始开发之前,请确保开发环境上已经完成以下配置

  1. go get https://github.com/ServiceComb/go-chassis

在 ServiceComb 微服务框架中,Service Center 提供服务注册及服务发现功能,可直接使用 docker 运行。

  1. docker pull servicecomb/service-center
  2. docker run -d -p 30100:30100 servicecomb/service-center:latest

体质指数计算器(calculator) 开发

体质指数计算器(calculator)提供运算服务,分为具体业务逻辑服务注册与配置启动框架三部分

定义服务结构体

  1. type CalculateBmi struct {
  2. }

编写计算体质指数(BMI)函数,该函数根据公式 进行实现:

  1. func (c *CalculateBmi) BMIIndex(height, weight float64) (float64, error) {
  2. if height <= 0 || weight <= 0 {
  3. return 0, fmt.Errorf("Arugments must be above 0")
  4. }
  5. heightInMeter := height / 100
  6. bmi := weight / (heightInMeter * heightInMeter)
  7. return bmi, nil
  8. }

​ 编写handler函数,其中restful.Context必须作为入参传入。restful.Context中包含了对http调用的RequestResponse的常用操作,Read开头的为对Request的读取,包括ReadEntityReadHeaderReadPathParameterReadBodyParameterReadRequest等;而Writer开头的为对Response的写入操作,包括WriteHeaderWriteJsonWriteError等。

  1. import (
  2. rf "github.com/ServiceComb/go-chassis/server/restful"
  3. )
  4. ……
  5. func (c *CalculateBmi) Calculate(b *rf.Context) {
  6. …… //定义返回结构体,此处省略
  7. heightStr := b.ReadQueryParameter("height")
  8. weightStr := b.ReadQueryParameter("weight")
  9. var height, weight, bmi float64
  10. var err error
  11. …… //字符串与浮点数类型转换,此处省略
  12. if bmi, err = c.BMIIndex(height, weight); err != nil {
  13. errorResponse.Error = err.Error()
  14. b.WriteHeaderAndJson(http.StatusBadRequest, errorResponse, "application/json")
  15. return
  16. }
  17. result.Result = bmi
  18. result.CallTime = time.Now().String()
  19. b.WriteJson(result, "application/json")
  20. }

指定对应的URL路由

  1. func (c *CalculateBmi) URLPatterns() []rf.Route {
  2. return []rf.Route{
  3. {http.MethodGet, "/calculator/bmi", "Calculate"},
  4. }
  5. }

完成业务逻辑代码的编写之后,需要将业务逻辑注册到Go-chassis框架,注册时可以同时指定微服务的名称、ID等属性。

  1. chassis.RegisterSchema("rest",&CalculateBmi{})

除了在代码中指定的部分属性外,更多的属性是通过配置文件来进行配置。配置文件包括chassis.yamlmicroservice.yaml,放置于代码目录下的conf文件夹内。其中,chassis.yaml中配置的是微服务的公共属性,如公共的AppId信息,使用的注册中心类型信息、地址信息,服务的协议、监听地址、注册发现地址、传输协议信息等;microservice.yaml配置的是微服务的私有属性,包括服务名、版本等。

chassis.yaml

  1. APPLICATION_ID: bmi #应用ID
  2. cse:
  3. service:
  4. registry:
  5. address: http://127.0.0.1:30100 #注册中心(ServiceCenter)的地址
  6. protocols:
  7. rest:
  8. listenAddress: 0.0.0.0:8080 #微服务的监听地址

microservice.yaml

  1. service_description:
  2. name: calculator #微服务名称
  3. version: 0.0.1 #微服务版本号

启动框架和服务

  1. import (
  2. "github.com/ServiceComb/go-chassis"
  3. "github.com/ServiceComb/go-chassis/core/lager"
  4. )
  5. ……
  6. if err := chassis.Init(); err != nil { //初始化框架
  7. lager.Logger.Error("init failed", err)
  8. return
  9. }
  10. chassis.Run() //运行微服务

体质指数界面(web-app)开发

开发完后端的calculator服务之后,需要开发提供给用户的交互界面,主要分为前端静态界面、请求转发、服务启动入口三个部分。

前端静态界面使用了Bootstrap开发,并通过golang 官方库中http.ServeFile将前端静态页面展示出来。

  1. func BmiPageHandler(w http.ResponseWriter, r *http.Request) {
  2. http.ServeFile(w,r,"external/index.html")
  3. }

请求转发

体质指数界面(web-app)微服务收到前端界面发过来的请求时,通过core.NewRestInvoker()将请求转发到calculator服务。在转发调用的过程中,用户并不需要感知calculator服务具体的地址和端口,服务发现的过程由go-chassis框架自动完成。

  1. func BmiRequestHandler(w http.ResponseWriter, r *http.Request) {
  2. queries := r.URL.Query()
  3. heightStr := queries.Get("height")
  4. weightStr := queries.Get("weight")
  5. requestURI := fmt.Sprintf("cse://calculator/bmi?height=%s&weight=%s", heightStr, weightStr)
  6. restInvoker := core.NewRestInvoker()
  7. req, _ := rest.NewRequest("GET", requestURI)
  8. resp, _ := restInvoker.ContextDo(context.TODO(), req)
  9. w.Header().Set("content-type", "application/json")
  10. w.WriteHeader(resp.GetStatusCode())
  11. w.Write(resp.ReadBody())
  12. }

体质指数界面(web-app)服务的配置文件同样包括chassis.yamlmicroservice.yaml两个yaml文件,具体内容如下:

chassis.yaml

  1. APPLICATION_ID: bmi #应用ID
  2. cse:
  3. service:
  4. registry:
  5. address: http://127.0.0.1:30100 #注册中心(ServiceCenter)的地址

microservice.yaml

  1. service_description:
  2. name: web-app #微服务名称
  3. version: 0.0.1 #微服务版本号

calculator服务不同,体质指数界面(web-app)在Go-chassis框架内是一个消费者类型的服务,故只需调用chassis.Init()Go-chassis框架进行初始化。

  1. func main() {
  2. http.HandleFunc("/", BmiPageHandler)
  3. http.HandleFunc("/calculator/bmi", BmiRequestHandler)
  4. if err := chassis.Init(); err != nil {
  5. lager.Logger.Error("Init fail", err)
  6. return
  7. }
  8. port := flag.String("port", "8889", "Port web-app will listen")
  9. address := flag.String("address", "0.0.0.0", "Address web-app will listen")
  10. fullAddress := fmt.Sprintf("%s:%s", *address, *port)
  11. http.ListenAndServe(fullAddress, nil)
  12. }

界面效果

通过上述步骤,体质指数(BMI)应用已经开发完毕,可以通过http://localhost:8889访问该应用,届时将能看到如下界面,并可输入身高和体重信息验证服务是否正常运行。

image

使用Go-chassis进行微服务治理

除了基础的业务逻辑开发外,Go-chassis提供了丰富的微服务治理功能。下面将在刚刚开发的体质指数应用(BMI)基础上,介绍如何使用Go-chassis进行微服务治理。

负载均衡

当对体质指数计算器(calculator)进行水平扩展时,需要将请求均衡地分发到多个体质指数计算器(calculator)上。Go-chassis的负载均衡功能包括负载均衡策略和负载均衡过滤器两种方式。微服务实例在经过过滤器中制定的规则初筛之后,根据策略算法选出一个合适的实例进行下一步处理。Go-chassis内置了RoundRobinRandomSessionStickinessWeightedResponse四种策略,其中默认使用的策略为RoundRobin。此外,无论是负载均衡策略还是负载均衡过滤器,开发者都可以根据自己的需求进行定制。

负载均衡功能默认开启,不需要另外配置。若用户希望使用RoundRobin之外的策略,可以在配置文件chassis.yaml中进行指定。

  1. cse:
  2. loadbalance: # 全局负载均衡配置
  3. strategy:
  4. name: Random
  5. microserviceA: # 微服务级别的负载均衡配置
  6. strategy:
  7. name: SessionStickiness

对体质指数计算器(calculator)进行水平拓展时,用户只需复制原有代码,并在配置文件中修改监听端口,使得新的实例在另一个端口运行即可。

为了便于区分不同的运行实例,在体质指数计算器(calculator)的实现中新增了返回实例ID的代码。

  1. import (
  2. "github.com/ServiceComb/go-chassis/core/registry"
  3. )
  4. ……
  5. items := registry.SelfInstancesCache.Items()
  6. for microServiceID, _ := range items {
  7. instanceID, exist := registry.SelfInstancesCache.Get(microServiceID)
  8. if exist {
  9. result.InstanceId = instanceID.([]string)[0]
  10. }
  11. }

Go-chassis框架初始化时,会将注册中心中的实例缓存到本地,并每30秒同步一次注册中心和本地缓存的数据(可配置)。代码中使用了本地缓存的数据来获取实例ID。

上述操作完成后,在界面上点击Submit 按钮,可以发现实例ID交替变换。

流量控制

流量控制机制通过控制数据传输速率来避免微服务过载运行。用户可以进行服务端流量控制,限制接收处理请求的频率,在体质指数计算器(calulator)的chassis.yaml中可进行服务端流量控制的配置:

  1. cse:
  2. handler:
  3. chain:
  4. Provider:
  5. default: ratelimiter-provider #添加服务段流量控制的handler
  6. flowcontrol:
  7. Provider:
  8. qps:
  9. enabled: true # 是否启用流量控制
  10. limit:
  11. web-app: 1 # key为指定要限制的微服务调用者名称,此处web-app为调用calculator的微服务的名称;value为每秒允许的请求数。

也可以进行消费端流量控制,限制发往指定微服务的请求的频率。在体质指数界面(web-app)中的chassis.yaml中配置:

  1. cse:
  2. handler:
  3. chain:
  4. Consumer:
  5. default: ratelimiter-consumer #添加消费者段流量控制的handler
  6. flowcontrol:
  7. Consumer
  8. qps:
  9. enabled: true # 是否启用流量控制
  10. limit:
  11. calculator: 1 # key为指定要限制的请求发往的微服务的名称;value为每秒允许的请求数

验证

访问 http://localhost:8889,在身高和体重的输入框中输入正数,尝试在1秒内多次点击 Submit 按钮。此时,能看到所有的请求将被后台延迟处理,处理的频率为1次/秒。

熔断与降级

熔断与降级主要用于解决或缓解服务雪崩的情况,即个别微服务表现异常时,系统能对其进行处理,从而避免资源的耗尽。用户可以在服务端体质指数计算器(calculator)的chassis.yaml 文件中指明使用服务治理的处理链及指定熔断和容错策略:

  1. cse:
  2. handler:
  3. chain:
  4. Provider:
  5. default: bizkeeper-provider
  6. circuitBreaker:
  7. Provider:
  8. calculator:
  9. requestVolumeThreshold: 3 #10s内发生错误的阈值,超出阈值触发熔断
  10. fallback:
  11. Provider:
  12. enabled: true
  13. fallbackpolicy:
  14. Provider:
  15. policy: returnnull #出错后的处理策略

image

分布式调用链追踪

开启

分布式调用链追踪用于有效地监控微服务的网络延时并可视化微服务中的数据流转。启用分布式调用链追踪,需要在体质指数计算器(calculator) 的 chassis.yaml 文件中添加如下配置,指定追踪数据上报的开关以及上报地址、上报类型等。

  1. cse:
  2. handler:
  3. chain:
  4. Provider:
  5. default: tracing-provider
  6. tracing:
  7. enabled: true
  8. collectorType: zipkin
  9. collectorTarget: http://localhost:9411/api/v1/spans

同样的,在体质指数界面(web-app)中的chassis.yaml中进行如下配置:

  1. cse:
  2. handler:
  3. chain:
  4. Provider:
  5. default: tracing-consumer
  6. tracing:
  7. enabled: true
  8. collectorType: zipkin
  9. collectorTarget: http://localhost:9411/api/v1/spans

此外,还需要运行Zipkin 分布式追踪服务,可以采取Docker方式:

  1. docker pull openzipkin/zipkin
  2. docker run -d -p 9411:9411 openzipkin/zipkin

验证

首先访问 http://localhost:8889 ,在身高和体重栏处输入正数,并点击 Submit 按钮。然后访问 http://localhost:9411 ,进入Zipkin查看分布式调用追踪情况,可得下方界面。

Metrics

监控数据能直观的显示微服务应用的性能数据,帮助更好的进行微服务治理、制定弹性伸缩策略等。Go-chassis支持输出Prometheus格式的监控数据,提供的数据包括Golang运行时的数据、微服务进程的内存占用、CPU占用情况等。要使用监控功能,需要在体质指数计算器(calculator) 的chassis.yaml 文件中添加下列内容:

  1. cse:
  2. metrics:
  3. apiPath: /metrics
  4. enable: true
  5. enableGoRuntimeMetrics: true #是否开启go runtime检测

首先访问 http://localhost:8889 ,在身高和体重栏处输入正数,并点击 Submit 按钮。然后访问 http://localhost:8080/metrics(其中8080为体质指数计算器(calculator)服务端监听的端口),可以得到下图所示的监控数据:

image

加入ServiceComb社区

​ 本文介绍了ServiceComb Go-chassis的基本特性以及如何使用ServiceComb Go-chassis开发体质指数应用(BMI)以及进行微服务治理。整个示例的源代码可以从Github上获取。同时,作为一个新开源的项目,ServiceComb Go-chassis诚挚的欢迎大家一起参与社区讨论,贡献代码,共同努力打造“最好用的Go语言微服务框架”。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注