Go语言微服务开发框架实践(上篇)
Posted 华为云产品与解决方案
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言微服务开发框架实践(上篇)相关的知识,希望对你有一定的参考价值。
Go chassis是华为开源的一个go语言微服务开发框架。通过这篇文章中,我将从设计思路到源码剖析来深度分析Go Chassis。并且介绍自己在实践过程中的go语言性能调优和最佳实践,最后将使用go chassis编写一个http服务,此为上篇,将主要介绍go chassis的运行机制。
为什么我们要用go语言来开发微服务?
go依然是一门新兴的语言,和java比它还非常年轻,不过随着kubenetes和docker等项目的成功,可以说go语言已经成为了非常好的中间层开发语言,并且逐渐流行起来。编译速度快,支持多平台,内存占用低,轻量级协程等。它的协程设计降低了开发者门槛,让更多人可以轻松地编写支持高并发的后台服务
为什么使用Go chassis
go chassis集成了很多的功能,提供了一站式服务,能够让用户在一个方案中,获得路由管理,注册发现,负载均衡,限流,指标监控,分布式追踪等大量功能。
go chassis是一个协议中立的开发框架,它不仅支持http,也支持rpc协议,甚至可以集成mysql等中间件的协议。并将它们纳入统一的治理。
go chasis支持Istio控制面板,也就是说你可以将它与envoy进行混合使用,但只需要使用istio即可,它支持原生的istio配置管理。以此使服务吞吐提升,CPU占用降低。
go chassis是插件化设计,支持用户开发定制模块,并接入到框架中
go chassis特性
主要有以下几点:
插件化注册中心: 默认支持Service Center,kubernetes,istio
动态治理框架: 通过此框架,开发者可实现进程运行时配置热加载
插件化协议: 开发者可实现自己的RPC协议,默认实现了 http 和highway(RPC)
熔断降级: 支持根据超时,并发,错误率等进行服务的熔断
容错:支持重试次数等配置,并支持backoff退让重试,
路由管理: 可根据流量权重和Header匹配等配置规则,轻松实现金丝雀发布
客户端负载均衡: 支持定制策略
限流: 支持客户端和服务端限流
插件化Cipher: 支持开发者自定义加解密工具,并应用于AKSK和TLS 证书
处理链: 可支持在通信的过程中加入定制的业务逻辑
Metrics: 支持自动导出Prometheus格式的运行时监控数据
Tracing: 使用opentracing,支持用户快速对接不同分布式追踪系统
Logger: 日志工具支持扩展并下沉到不同存储中
治理: 可通过动态治理框架,在运行时热加载,熔断,负载均衡,路由等配置信息
设计目标
最大的灵活性和扩展性
协议是允许开发者灵活扩展的,在通信管道中任意的插入自己的特殊业务逻辑。
易用性
开发者可以用最小化的配置和代码来启动框架,并且框架内部提供友好的API供用户使用,每个模块甚至可以拆开使用,功能任意剪裁。
服务可治理
提供客户端负载均衡,熔断降级,容错,限流,路由管理等功能使分布式系统可治理,同时提供错误注入功能,来提前模拟分布式系统中的错误,以使自己的系统更加强壮。
服务可视化
微服务运行时产生的监控数据能够导出到监控系统,使数据可视化。
运行时配置热加载
分布式环境中,存在大量进程,如果因为更改配置就要发布新的软件包,会有一定成本,如果登陆到机器上去改配置再重启,更是费时费力。go chassis提供动态配置框架来帮开发者解决配置热加载问题。这也是服务动态治理的基础。
架构概述
如下图所示:
架构思路
解耦的编程接口、运行模型、传输层
编程接口:拥有RPC和Rest 2种编程模型
运行模型:使用Handler Chain与Invocation概念统一了不同协议
传输层:一个进程拥有多种协议。同协议可运行多个协议服务实例,运行在不同端口,使用端口进行API隔离
基于Handler chain模式的插件化架构
Handler chain可任意插入业务逻辑
基于运行时动态配置的服务治理
相同的运行模型和统一的治理能力
相同的运维支撑方式
Http服务可支持自动挂载 Promethues数据到指定的API路径。
日志可支持扩展,比如输出到kafka等服务中
注册中心拆分为Registrator和Service Discovery2个接口分别负责注册和发现,可以支持平台发现和客户端注册
请求处理过程
不同协议请求进入到对应的Server,Server将具体的协议请求转换为Invocation统一抽象模型,并传入Handler chain,在这里Chassis已经默认实现了很多的Handler,比如熔断,限流,路由管理,客户端负载均衡,Metrics收集,分布式追踪,错误注入等,由于handler根据统一模型Invocation进行处理,不必每个协议开发出来都自己开发一套治理。处理链可通过配置任意剪裁。最终再进入Transport handler,使用目标微服务的协议客户端传输到目标。这里提到的几个关键对象在后面会详细介绍。
实现详解
基本概念
处理链与Invocation
这个概念是从Java chassis引入的, 框架的编程接口层、运行模型层和传输层就是通过这个对象进行解耦,它是多协议支持的基础。可以参考它的代码:
https://github.com/ServiceComb/go-chassis/blob/master/core/invocation/invocation.go
Invocation为一个结构体,它将各个协议的内容抽象了,运行不同协议的request都能够统一对应到一次Invocation中,比如request的Payload,以及框架的治理相关信息。
Handler
Handler是微服务在运行过程中在框架层面里的一个最小处理单元。go chassis通过handler和handler的组装实现组件化的运行模型架构。其基本的使用方式就是实现接口、注册逻辑:
1.实现基本接口
2.开发者实现该接口后可通过API注册进框架
Handler Chain
用于加载一系列Handler并处理消息,目前支持负载均衡,路由管理,监控等功能,用户可以通过配置文件定义加载多种handler。请求调用时,会按照配置文件中的定义的顺序进入handler进行处理
Handler的设计可以保证每一个handler都能得到后面的handler的执行结果。比如:熔断和网络穿的功能就在chain当中,每当传输失败,都会被熔断拿到错误结果,并计算,当达到一定阈值,便会出发熔断。
Invoker
由于RPC和Http的编程风格不同,go chassis使用2种不同的Invoker来解决调用,无论哪种Invoker都会初始化一个Invocation并最终进入处理链中进行处理,最终进入各协议的Client实现并传输到目标服务中,这一切对用户都是透明的。
RPC
为了降低用户学习成本,使用了go语言标准库中net/rpc的调用风格
Http
为了降低用户学习成本,支持了go语言通用的http调用方式,允许用户任意操控原生http request 与 response,并且没有任何限制
接下来,用一个微服务调用过程中最基本的Consumer到Provider的业务请求流程来看一下前面的那些关键对象是如何协同工作的.
客户端发送请求
开发者使用Invoker来发起请求,Invoker创建统一Invocation对象
Invocation进入处理链进行处理,比如熔断,限流等
进入Load Balancing后,会根据Strategy和目标协议选择一个IP:port
将协议和IP:port继续传送到Transport 后,根据协议选择具体的Client实现,并传入IP port进行发送
服务端接收请求
接收到协议请求后,由各协议Server转为统一的Invocation模型
Invocation进入处理链处理,比如限流,分布式追踪
处理结束后,进入具体的业务处理逻辑
插件化机制
go的动态能力相对有限,go 1.8提供了插件能力,但是会给build带来复杂度,我们先来看看Java怎么解决插件化的:
Class<?> act = Class.forName("com.bla.TestActivity");
基于这个能力也出现了Spring这样的项目,开发者可以轻松地解决插件化的问题
可是go语言该怎么做呢?
下面以Go chassis的实践为例
提供接口与Map定义
开发者需要实现接口,并实现NewFunc返回具体实现
注册插件
通过调用API进行插件安装
使用插件
考虑到易用性贴近Spring的风格,chassis使用yaml格式的配置文件来管理插件。
以下为实现思路
启动和初始化机制如下:
通过文件指定加载的插件,在Server之上我们封装Server manager管理所有协议的Server,并负责注册到注册中心,,收到系统终止信号时,负责反注册
使用了Client manager与
https://github.com/ServiceComb/gochassis/blob/master/core/handler/transport_handler.go
对client进行封装,按协议,微服务,实例的唯独进行client初始化,即每个实例都有专属client。
支持的插件
chassis框架支持以下插件,具体请参考gitbook文档
https://go-chassis.readthedocs.io/en/latest/。
Handler
Provider
Cipher
Bootstrap
Logger
Config Source
Registry
InjectFault
Server
Client
Strategy
Tracing
客户端负载均衡
客户端负载均衡器负责使用本地的注册中心缓存来进行服务发现。
go chassis 封装了很多的高级特性
融合了Backoff算法,以使网络流量稳定。
容错支持在请求错误后以怎样的策略进行重试
会话粘滞与延迟感知Strategy实现
动态治理,支持运行时热加载以上配置
支持目标服务级别的细粒度负载均衡策略配置(即一进程针对访问不同微服务,可控制负载均衡策略)
错误注入
为了能让用户轻松地制造系统混乱,在Consumer侧,实现了错误注入机制,可以根据配置定义错误或者故意制造调用延迟,来测试分布式系统遇到问题时的容错能力,同样支持运行时动态加载配置。目前只支持简单的错误和延迟以及发生百分比
开发者甚至可以通过此接口为一个协议安装错误注入插件,可完全替代目前的错误注入实现
与其他微服务开发框架的对比
go micro架构:
图片来自go micro官网https://micro.mu/docs/images/go-micro.png
这里我引用micro.mu的关于go micro与go kit对比
Go micro是一个插件化RPC分布式开发框架,可以开箱即用,也可以任意定制自己的RPC协议中的每个模块。他是一个eco system,现在已经有大量的插件实现,并在go-micro基础之上有了很多的新框架,Micro组织下有许多围绕go-micro建立的子项目。
Go kit是一个用来构建微服务的的工具包,每个包都是独立的,开发者自己选择需要的工具组装自己的微服务,包含了丰富的治理功能,熔断,监控,限流等,且拥有丰富的插件化协议和注册中心。
Go chassis是插件化框架,与Go micro的不同在于,go chassis提供的能力是插件化协议,你可以将http或RPC,甚至是Mysql,Redis等协议接入到框架中,并且提供一站式功能,将熔断,限流,监控等功能全部集成到框架中,开发者无需自己寻找这些方案。拥有3者中最丰富的治理功能。同样拥有开放的定制能力,但是作为一个新的框架,生态尚需完善。
开发者可以通过开发体验和特性支持对框架进行选型。
点击阅读原文,了解Go Chassis !
以上是关于Go语言微服务开发框架实践(上篇)的主要内容,如果未能解决你的问题,请参考以下文章