Go chassis 微服务开发框架实战系列(一)

Stella981
• 阅读 792

什么是 Go chassis


go chassis 是一个 go 语言微服务开发框架,专注于云原生应用的开发,我们主要的使用场景是云服务开发。我们将自己在云服务开发过程中沉淀的能力融入到了开发框架中,以帮助开发团队快速编写云原生应用。

文章目标

本文介绍我们的设计理念和目标,为何 go chassis 会诞生。后面的系列文章会着重介绍使用方法,项目实战。对于微服务架构模式,云原生要素,为什么选择 go 语言等将不再过多赘述。

诞生背景

公司开发云服务,要构建健壮,韧性,安全,高可靠的云服务,必然有大量基础能力需要编写,为了加速开发,我们将这些能力便沉淀在了该框架中。为什么呢?我们希望加速每一个组件也就是微服务的开发速度。有的人看到的只是冰山一角,真的要达成微服务架构模式的愿景,其实需要繁重的工作量。就像冰山那样,我们要将通用能力沉淀下去,能够复用。如果让各个业务团队同时照顾冰山上下,各自开发各自的,那结果将是灾难性的,企业用人成本极高。

Go chassis 微服务开发框架实战系列(一)

在业务交付的过程中,各个云团队有大量的管理服务需要对接,每个团队都在写重复的代码,通过框架能力,将交付职责分离,减少开发成本:

Go chassis 微服务开发框架实战系列(一)

如何快速开发一个微服务

可以跟随这个文档体验: https://github.com/go-chassis/go-chassis/edit/master/docs/getstarted/install.md

统一治理和协议模型

想要复用统一的一套能力,我们自然要先统一模型。我们使用 Invocation 概念来统一协议描述,当协议请求到来后,go chassis 会把 request 转换为 Invocation 进行治理(如负载均衡,限流,熔断,重试,金丝雀发布等),这样就可以允许任意的协议接入到 go chassis,并无缝使用 go chassis 提供的核心功能,当前默认提供原生 grpc 和 http 两种协议的接入。

为什么会有这样的设计呢?

  1. 每个协议层的优化空间非常大,用户态到内核态的调用速度本来就相对内部代码来说是很慢的,优化这一层代码很重要,RPC 怎么也比 http 来得好。

  2. 不同部门可能有私有协议诉求,那么服务治理就交给核心框架完成。协议由业务部门决定自主研发或是集成现有协议。当你发现公司内部不同部门都在开发自己的协议做自己的服务治理时,再向将业务统一一个架构,一个工具链上,将非常困难。

可扩展的处理链条:handler chain as middleware

我们以 Java 为例,大家在写一个拦截器或者过滤器的时候可以对请求进行处理,处理完,这个拦截器的的执行过程就结束了,那么如何达成以下目标?

1.跟踪业务执行结果指标,比如 http 状态码,并导出他们让 prometheus 收集。

2.跟踪关键的业务执行结果,审计这些信息。比如请求返回的一些结果信息

3.分布式调用链追踪,end span 必须等到请求返回才能拿到。

  1. 客户端调用远程服务时,也需要进行中间处理,比如客户端负载均衡,请求重试,这些不能够耦合在业务代码中

Java 的答案很简单,注解。那么 go 呢?我们引入了 handler chain 编程模型,chain 中每个 handler 都可以拿到后面的 handler 的执行结果,包括业务代码的执行结果。

Go chassis 微服务开发框架实战系列(一)

看下接口定义

type Handler interface {
    Handle(*Chain, *invocation.Invocation, invocation.ResponseCallBack)
    Name() string
}



// ResponseCallBack process invocation response
type ResponseCallBack func(*Response)

ResponseCallBack 用于接受后置 handler 返回的结果,所以每一个 handler 处理时都可以按需定义自己的 ResponseCallBack 来获取后面 handler 甚至是业务逻辑代码的执行结果。帮助通用逻辑(即中间件)和业务逻辑彻底解耦。可以看下现在已经支持的中间件,无论限流,熔断,负载均衡,认证鉴权,审计,我们都用此机制实现:https://go-chassis.readthedocs.io/en/latest/middleware.html 将公司全部的工具链,服务治理手段,安全合规等都落入到处理链中,可快速加快研发速度,并统一规范,减少管理负担。

不只是 API,通过配置简化开发过程

只举 2 个例子

监控

减少让开发者自己调用 API 的过程,将他们简化为配置项 例如可观察:引入一行代码

import _ github.com/go-chassis/go-chassis/v2/middleware/monitoring

加上配置

handler:
  chain:
    Provider:
      default: monitoring

就可以在服务端进行监控,导出请求数,延迟等指标,大大加速开发人员效率

# HELP request_count
# TYPE request_count counter
request_count{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0"} 14
# HELP request_process_duration
# TYPE request_process_duration summary
request_process_duration{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0",quantile="0.5"} 3
request_process_duration{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0",quantile="0.9"} 80
request_process_duration{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0",quantile="0.99"} 80
request_process_duration_sum{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0"} 315
request_process_duration_count{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0"} 14

需要自定义指标:

err := metrics.CreateCounter(metrics.CounterOpts{
        Name:   “user_login”,
        Labels: labelsSlice,
    })
metrics.CounterAdd(“user_login”, 1, labelMap)

通用能力

我们也将通用的部分都落地到了框架中,通过简单的配置文件启用,不再需要不同团队重复编写代码

servicecomb:
  transport:
    failure:
      rest: http_500,http_502 #统计错误率时,例如只把500和502作为错误
    maxIdleCon:
      rest: 1024
    maxBodyBytes:
      rest: 20 #只需要指定我的服务能接受的body体大小,访问的超时时间即可不再需要各个团队维护代码。
    maxHeaderBytes:
      rest: 1 #限制http header大小
    timeout: #限制客户端超时
      rest: 30s

插件化


为了应对不同业务诉求,我们总是要考虑 “可替换性”。而这个的优先级总是大于 “可复用性”。这就是 go chassis 的插件理念。基本所有的重要组件都是插件化的,框架已经定义好标准接口,只需要开发者实现好,注册到框架中,就可以在配置文件中配置并生效了,业务开发者是完全不感知的。可以参考我们对 quota 组件的扩展过程,他负责资源的配额管理 https://go-chassis.readthedocs.io/en/latest/dev-guides/backends.html

后续

我将详细剖析 go chassis 的内部设计和特性使用。

在下一篇文章中,我将讲述 go chassis 如何快速开发出一个微服务。由于是系列文章,随着文章不断更新,如果有期望了解的话题,内容可以留言反馈,我会加入到后续文章中。

项目地址

https://github.com/go-chassis/go-chassis

目前的用户

本文来源为 GoCN 社区原创投稿,点击“阅读原文”前往社区。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Peter20 Peter20
3年前
mysql中like用法
like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\
Easter79 Easter79
3年前
SpringBoot自定义序列化的使用方式
场景及需求:项目接入了SpringBoot开发,现在需求是服务端接口返回的字段如果为空,那么自动转为空字符串。例如:\    {        "id":1,        "name":null    },    {        "id":2,        "name":"x
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
SpringBoot自定义序列化的使用方式
场景及需求:项目接入了SpringBoot开发,现在需求是服务端接口返回的字段如果为空,那么自动转为空字符串。例如:\    {        "id":1,        "name":null    },    {        "id":2,        "name":"x
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这