2025 年技术指引:让真实案例和经验为开发者开路 了解详情
写点什么

使用 ServiceComb Go-chassis 构建微服务

  • 2018-01-24
  • 本文字数:6650 字

    阅读完需:约 22 分钟

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

什么是 chassis?

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

Apache ServiceComb Go-chassis 简介

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

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

  • 服务发现(配合ServiceComb现有的ServiceCenter
  • 动态配置管理:
  • 负载均衡
  • 流量控制(服务端与客户端)
  • 熔断容错
  • 分布式追踪
  • Metrics
  • 日志
  • 路由策略

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

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

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

  • 体质指数计算器(calculator):负责处理运算事务。
  • 体质指数界面(web-app):提供用户界面及网关服务。

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

准备工作

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

  • 安装 git
  • 安装 Go 1.8+
  • 安装 docker
  • 下载 ServiceComb go-chassis

go get https://github.com/ServiceComb/go-chassis- 运行 Service Center

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

复制代码
docker pull servicecomb/service-center
docker run -d -p 30100:30100 servicecomb/service-center:latest

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

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

  • 具体业务逻辑

定义服务结构体

复制代码
type CalculateBmi struct {
}

编写计算体质指数(BMI)函数,该函数根据公式 \(BMI=\frac{weight}{height^2}\) 进行实现:

复制代码
func (c *CalculateBmi) BMIIndex(height, weight float64) (float64, error) {
if height <= 0 || weight <= 0 {
return 0, fmt.Errorf("Arugments must be above 0")
}
heightInMeter := height / 100
bmi := weight / (heightInMeter * heightInMeter)
return bmi, nil
}

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

复制代码
import (
rf "github.com/ServiceComb/go-chassis/server/restful"
)
……
func (c *CalculateBmi) Calculate(b *rf.Context) {
…… // 定义返回结构体,此处省略
heightStr := b.ReadQueryParameter("height")
weightStr := b.ReadQueryParameter("weight")
var height, weight, bmi float64
var err error
…… // 字符串与浮点数类型转换,此处省略
if bmi, err = c.BMIIndex(height, weight); err != nil {
errorResponse.Error = err.Error()
b.WriteHeaderAndJson(http.StatusBadRequest, errorResponse, "application/json")
return
}
result.Result = bmi
result.CallTime = time.Now().String()
b.WriteJson(result, "application/json")
}

指定对应的 URL 路由

复制代码
func (c *CalculateBmi) URLPatterns() []rf.Route {
return []rf.Route{
{http.MethodGet, "/calculator/bmi", "Calculate"},
}
}
  • 服务注册与配置

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

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

chassis.yaml

复制代码
APPLICATION_ID: bmi #应用 ID
cse:
service:
registry:
address: http://127.0.0.1:30100 #注册中心(ServiceCenter)的地址
protocols:
rest:
listenAddress: 0.0.0.0:8080 #微服务的监听地址

microservice.yaml

复制代码
service_description:
name: calculator #微服务名称
version: 0.0.1 #微服务版本号

启动框架和服务

复制代码
import (
"github.com/ServiceComb/go-chassis"
"github.com/ServiceComb/go-chassis/core/lager"
)
……
if err := chassis.Init(); err != nil { // 初始化框架
lager.Logger.Error("init failed", err)
return
}
chassis.Run() // 运行微服务

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

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

  • 前端静态界面

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

复制代码
func BmiPageHandler(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w,r,"external/index.html")
}

请求转发

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

复制代码
func BmiRequestHandler(w http.ResponseWriter, r *http.Request) {
queries := r.URL.Query()
heightStr := queries.Get("height")
weightStr := queries.Get("weight")
requestURI := fmt.Sprintf("cse://calculator/bmi?height=%s&weight=%s", heightStr, weightStr)
restInvoker := core.NewRestInvoker()
req, _ := rest.NewRequest("GET", requestURI)
resp, _ := restInvoker.ContextDo(context.TODO(), req)
w.Header().Set("content-type", "application/json")
w.WriteHeader(resp.GetStatusCode())
w.Write(resp.ReadBody())
}
  • 服务配置与启动

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

chassis.yaml

复制代码
APPLICATION_ID: bmi #应用 ID
cse:
service:
registry:
address: http://127.0.0.1:30100 #注册中心(ServiceCenter)的地址

microservice.yaml

复制代码
service_description:
name: web-app #微服务名称
version: 0.0.1 #微服务版本号

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

复制代码
func main() {
http.HandleFunc("/", BmiPageHandler)
http.HandleFunc("/calculator/bmi", BmiRequestHandler)
if err := chassis.Init(); err != nil {
lager.Logger.Error("Init fail", err)
return
}
port := flag.String("port", "8889", "Port web-app will listen")
address := flag.String("address", "0.0.0.0", "Address web-app will listen")
fullAddress := fmt.Sprintf("%s:%s", *address, *port)
http.ListenAndServe(fullAddress, nil)
}

界面效果

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

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

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

负载均衡

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

  • 开启

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

复制代码
cse:
loadbalance: # 全局负载均衡配置
strategy:
name: Random
microserviceA: # 微服务级别的负载均衡配置
strategy:
name: SessionStickiness

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

  • 微服务实例的本地缓存

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

复制代码
import (
"github.com/ServiceComb/go-chassis/core/registry"
)
……
items := registry.SelfInstancesCache.Items()
for microServiceID, _ := range items {
instanceID, exist := registry.SelfInstancesCache.Get(microServiceID)
if exist {
result.InstanceId = instanceID.([]string)[0]
}
}

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

  • 验证

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

流量控制

  • 开启

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

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

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

复制代码
cse:
handler:
chain:
Consumer:
default: ratelimiter-consumer #添加消费者段流量控制的 handler
flowcontrol:
Consumer
qps:
enabled: true # 是否启用流量控制
limit:
calculator: 1 # key 为指定要限制的请求发往的微服务的名称;value 为每秒允许的请求数

验证

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

熔断与降级

  • 开启

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

复制代码
cse:
handler:
chain:
Provider:
default: bizkeeper-provider
circuitBreaker:
Provider:
calculator:
requestVolumeThreshold: 3 #10s 内发生错误的阈值,超出阈值触发熔断
fallback:
Provider:
enabled: true
fallbackpolicy:
Provider:
policy: returnnull #出错后的处理策略
  • 验证
  1. 使服务进入熔断状态。访问 http://localhost:8889 ,在身高或体重的输入框中输入一个负数,连续点击三次或以上 Submit 按钮,此时在网页下方能看到类似左图的界面。
  2. 验证服务处于熔断状态。在身高和体重的输入框中输入正数,再次点击 Submit 按钮,此时看到的界面依然是类似左图的界面。同时在 体质指数计算器 (calculator) 后台运行日志中也能看到 circuit open 的日志。
  3. 验证服务恢复正常。约 5 秒后 ,在身高和体重的输入框中输入正数,点击 Submit 按钮,此时界面显示正常。

分布式调用链追踪

开启

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

复制代码
cse:
handler:
chain:
Provider:
default: tracing-provider
tracing:
enabled: true
collectorType: zipkin
collectorTarget: http://localhost:9411/api/v1/spans

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

复制代码
cse:
handler:
chain:
Provider:
default: tracing-consumer
tracing:
enabled: true
collectorType: zipkin
collectorTarget: http://localhost:9411/api/v1/spans

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

复制代码
docker pull openzipkin/zipkin
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 文件中添加下列内容:

复制代码
cse:
metrics:
apiPath: /metrics
enable: true
enableGoRuntimeMetrics: true #是否开启 go runtime 检测
  • ​​​​验证

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

加入ServiceComb 社区

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

感谢徐川对本文的审校。

2018-01-24 17:1619499

评论

发布
暂无评论
发现更多内容

你以为自己Nginx掌握的很好?这份1330页Nginx笔记,颠覆你的认知!

Java 程序员 后端

电竞入亚,行业爆发,你的游戏是否还缺个「大招」?

融云 RongCloud

游戏 社交 泛娱乐

你能读懂微服务架构深度解析:架构设计背后的哲学吗?

Java 程序员 后端

使用Spring Cloud Config进行分布式配置:Vault 后端

Java 程序员 后端

你是否精通springcloud:使用SpringCloud进行同步通信?

Java 程序员 后端

你看得起劲的斗鱼直播,已经在 GitHub 开源了自家项目!

Java 程序员 后端

Redis 6.0 新特性篇:客户端缓存全面揭秘

码哥字节

redis 缓存 NoSQL 数据库 11月日更

你还搞不定生涩难懂的Spring-Aop?梳理完毕以后原来如此简单

Java 程序员 后端

区块链将会深度应用于乡村振兴

CECBC

嘉宾就位 | Unity、Beeto、荔枝、阿里云、StarMaker、LiveMe、积目…花城论剑

融云 RongCloud

通信云 社交 元宇宙 泛娱乐 出海

自定义View:如何实现一个双击放大缩小的图片控件

Changing Lin

11月日更

使用Redis和Java进行数据库缓存 - DZone数据库

Java 程序员 后端

作为Java面试官,我会问Java程序员一些什么问题?

Java 程序员 后端

毕业之后,开源给了我第一份工作

Zilliz

数据库 vim 开源 成长

作为一名程序员,你觉得最重要的能力是什么?

Java 程序员 后端

WICC · 广州 | 圆桌对话:社交泛娱乐 & 出海的机遇与挑战

融云 RongCloud

通信云 社交 泛娱乐 出海

使用Spring Data JPA的Specification构建数据库查询

Java 程序员 后端

传授一套月薪20k程序员的高薪秘籍

Java 程序员 后端

你是否已经精通了SpringBoot的执行器功能了呢?不精通就来学

Java 程序员 后端

你知道面试必问的AOP吗?通过Spring又如何实现呢?

Java 程序员 后端

难以置信!数字货币袭来!这类人都要富起来了 !

CECBC

Github霸榜月余~,原来是阿里大咖的千亿级并发系统设计手册上线了

Java 编程 程序员

融云与 HIFIVE 达成战略合作,共创「沉浸式」社交解决方案

融云 RongCloud

通信云 语聊房 语音社交

你必须了解的微服务架构设计的10个要点!

Java 程序员 后端

你懂的!EL表达式与JSTL标签库

Java 程序员 后端

认知未来货币需要新的思想资源

CECBC

你居然还去服务器上捞日志,搭个日志收集系统难道不香么!

Java 程序员 后端

外包学生管理系统 - 详细架构设计

奔奔

你有效地管理JVM的垃圾了吗?是时候把垃圾拿出来了!

Java 程序员 后端

你能读懂微服务架构深度解析:架构设计背后的哲学吗?(1)

Java 程序员 后端

你还在使用 try-catch-finally 关闭资源?

Java 程序员 后端

使用ServiceComb Go-chassis构建微服务_语言 & 开发_王齐林_InfoQ精选文章