QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

使用 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:1619526

评论

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

下一代人工智能:逻辑理解?物理理解?

安第斯智能云

人工智能

10分钟掌握Java性能分析诀窍

安第斯智能云

Java 后端

统一预估引擎的设计与实现

安第斯智能云

算法 后端

网络安全、Web安全、渗透测试之笔经面经总结

网络安全学海

面试 网络安全 信息安全 渗透测试 漏洞分析

模型端侧加速哪家强?一文揭秘百度EasyEdge平台技术内核

百度大脑

人工智能 深度学习 百度 飞桨

如何抓住用户体验的关键时刻?

石云升

用户体验 关键时刻 7月日更

供应链、产品溯源以及区块链所面临的巨大阻碍是什么?

CECBC

场景背后见真章:银行数字化转型持续深入

CECBC

产业区块链迎来新纪元,基础设施建设成核心命题

CECBC

拍乐云 X 青云科技,预见数字自由,相约 CIC 2021 云计算峰会

拍乐云Pano

网络攻防学习笔记 Day80

穿过生命散发芬芳

网络攻防 7月日更

为什么电脑自带的录屏功能不好用?

淋雨

视频剪辑 Camtasia 专业录屏

第七届军博会圆满闭幕,数军科技多项成果获关注

科技热闻

Realtime DB技术详解

安第斯智能云

数据

11道高频React面试题及详解,另附有React面试题集合

前端依依

面试 大前端 React

国内首家入驻统信系统的APaaS厂商

明道云

oCPX简介——广告界的“无人驾驶”技术

安第斯智能云

算法

获取微信小程序页面路径方法

一颗小树

小程序 微信开发者工具 页面路径 微信开发者

快手上线本地生活榜单:自媒体平台在逐步蚕食搜索引擎市场

石头IT视角

七种颜色的事件风暴法

escray

学习 极客时间 7月日更 如何落地业务建模

星环研发总监为你揭秘TDH8.0的前因后果 | TDH8.0 使用必读 3

星环科技

数据库 大数据 多模型数据

在外包做开发3年,为了进大厂,耗时半年,整合出25W字Java全栈面试题,这就是我的决心

Java架构师迁哥

图解 JavaScript 数组方法

devpoint

ES6 array 7月日更

技术实践 | 网易云信视频转码提速之分片转码

网易云信

Java到底是什么?

卢卡多多

Java 入门 7月日更 Java入门

【软件测试转型自动化测试001】Python环境搭建&语法规则

程序员阿沐

Python 软件测试 自动化测试 环境搭建 语法规则

用户管理系统 - 用户权限设计从入门到精通

蒋川

后台开发 权限系统 权限管理 权限架构 用户管理

char+char=number

喵叔

7月日更

解读新技术,解锁新玩法,HarmonyOS开发者日杭州站等你来参加

科技汇

百度智能云人脸离线识别SDK再升级,优化复杂光线识别效果,急速通行无惧暗光

百度大脑

人脸识别 百度智能云

云原生Web服务框架ESA Restlight

安第斯智能云

云原生

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