写点什么

才云开源 Nirvana:Golang REST API 框架

  • 2019-01-24
  • 本文字数:4945 字

    阅读完需:约 16 分钟

才云开源 Nirvana:Golang REST API框架

自 2009 年开源以来,Go 作为一种强大、高效、简洁、易上手的编程语言,在帮助阅读、调试和维护大型软件系统上发挥着越来越重要的作用。而依托其健康生态,Golang 社区也相继涌现出诸如 beego、gin、chi、go-restful 等知名框架,为 Go 提供额外功能支持。


但选择过多,反受其乱。面对层出不穷的优秀框架,不同团队、不同开发者在框架选择上往往会出现分歧,不同框架之间也彼此壁垒高筑,导致业务与框架耦合,开发效率大大降低。


为了解决这类问题,才云 Caicloud 实现了 Golang API 框架 Nirvana,把 API 从对框架的依赖中彻底解放出来。它专为提高生产力和可用性设计,可扩展、性能高,旨在成为才云 Caicloud 所有 Golang 服务的基石,助力业务的高速开发。

接轨 Kubernetes 这些痛点不可忽视

近年来,为了满足业务发展需要,应对日益激烈的市场竞争,大量企业开始使用容器部署云工作负载。而随着容器使用量的增长、Kubernetes 成为容器编排的事实标准,在 Kubernetes 上打造新一代容器云平台成了企业谋求发展的必由之路。


为了顺应时局,技术团队除了进行思维上的转变,还要应对团队和业务方向的调整,对团队项目和产品完成切割分化。这之中就涉及对 Go 框架变更的抉择。


两年前,才云 Caicloud 团队在构建基于 Kubernetes 的云平台时,在框架上遇到了不少麻烦:当时 Kubernetes 正值发展期,为了快速开发,工程师们往往倾向于选择自己熟悉的框架。因此,虽然大多数项目用的是 go-restful(Kubernetes 的选型),但用 beego、gin、chi 等框架的工程师也不在少数,这就给业务整合带来了很多问题:


  • 不同框架对 API 的描述形式不一致,这增加了不同团队间的沟通成本;

  • 不同框架 API 风格差距较大,文档自动化困难;

  • 错误定义和处理方式在不同项目之间存在差别,会导致客户端处理困难。


曾经开放的工程师文化成了变革的最大阻力。

Nirvana 的缘起

Nirvana 就是在这个背景下诞生的。


它借鉴了 Kubernetes 声明式 API 的设计,巧妙规避了框架对 API 的侵入。同时,为了实现业务和框架的隔离,它定义一个规范,让 API 按照规范书写,完全屏蔽了框架对 API 的影响。


一言以蔽之,Nirvana 框架的设计思路始终围绕工程师们亲历的种种痛点:


  • 构建风格一致的 API 项目;

  • 使用统一的 RESTful 路由与声明式 API 定义,避免业务对框架产生依赖;

  • 使用统一的错误生成和处理方式;

  • 提供开箱即用的基础功能,包括 Prometheus metrics、tracing、profiling 等;

  • 自动生成 API 文档和客户端代码。


在 Nirvana 中,我们用一套 API Definition 来声明式地描述业务 API。下面是一个列出消息列表 API 的例子:


Definition{    // 这个 API 返回的是资源数组,所以使用 List 方法。    Method:     def.List,    // Summary 是一个短语,用于描述这个 API 的用途。这个短语在生成文档和客户端的时候用于区分 API。    // 这个字符串去掉空格后会作为生成客户端时的函数名,因此请确保这个字符串是有意义的。    Summary:    "List Messages",    // 详细描述这个 API 的用途。    Description: "Query a specified number of messages and returns an array",    // 业务函数    Function:   message.ListMessages,    // 对应业务函数的参数信息。用于告知 Nirvana 从请求的那一部分取得数据,然后传递给业务函数。    Parameters: []def.Parameter{        {            // 参数来源            Source:     def.Query,            // 参数名称,作为 key 从 Source 里取值。            // 与业务函数的参数名称无关。            Name:       "count",            // 默认值            Default:    10,            // 参数描述            Description: "Number of messages",        },    },
// 对应业务函数的返回结果。用于告知 Nirvana 业务函数返回结果如何放到请求的响应中。 Results: def.DataErrorResults("A list of messages"),}
复制代码


而对应业务 API 的形式则是:


type Message struct {    ID      int `json:"id"`    Title   string `json:"title"`    Content string `json:"content"`}
func ListMessages(ctx context.Context, count int) ([]Message, error) {
messages := make([]Message, count) for i := 0; i < count; i++ { messages[i].ID = i messages[i].Title = fmt.Sprintf("Example %d", i) messages[i].Content = fmt.Sprintf("Content of example %d", i) } return messages, nil}
复制代码


很显然,业务函数并不关心自身是如何暴露给外部的,实现方法也和其他内部函数没有差别(这只是一个简单的例子,更多详细内容请查阅 Nirvana Definition 文档)。


在这个例子里,API Definition 描述了完整的 API 结构,包括 RESTful 路径、请求方法、请求描述、请求参数、请求响应和请求 handler。框架只需要解析 API Definition,就能得到业务逻辑的入口和出口处理方式。对开发者而言,API 的开发过程从“ 命令式路由 + 数据转换 + 业务逻辑” 变成了“API Definition + 业务逻辑”。框架与业务逻辑之间通过 API Definition 进行桥接。

Nirvana 框架

API Definition 作为声明式 API,除了让框架读取信息生成路由和对外提供服务,它本身也完整描述了一个 API 的工作方式。因此,我们还能用它生成 openapi 文档和客户端。在接下来的几个小节中,我们将详述 Nirvana 提供的这些能力。


路由工作流


任何一个 API 框架都具备基本的 HTTP Serve 能力( HTTP 接口服务能力)。在 Nirvana 中,HTTP Serve 由 Golang 基础库 http 提供。HTTP 请求的路由方式如下图所示:



在这个请求的工作流中:


  • Filters 是请求过滤器,可以对不符合要求的请求进行提前响应,而不会进入路由匹配过程;

  • Middlewares 是围绕请求的中间件,能够控制请求的处理行为;

  • Executor 是最终处理请求的执行器,负责通过参数生成器(ParameterGenerators)和结果处理器(DestinationHandlers)将请求注入到业务逻辑之中,并将返回结果处理后返回。


在这里,Filters、Middlewares、ParameterGenerators 和 DestinationHandlers 都是可以被开发者重新定义的。这也意味着开发者可以改变 Nirvana 的原生处理行为,使之符合自身需求。


服务构建工作流


Nirvana 另一个工作流是将 API Definition 构建到路由中去,并完成整个服务的启动工作。



在 Nirvana 启动时,除 API Definition 之外,它还能够通过插件往框架里注入一些功能,包括注册 Filters、Middlewares、添加其他路由 endpoint 等。目前 Nirvana 已经提供对 metrics、profiling、tracing、log 等常用插件的支持。


通过以上两个工作流,以及 Nirvana 中大量的模块方法注册接口,开发者可以自行扩展 API Definition 的能力,让 API Definition 与业务逻辑更加贴合。API Definition 单向依赖并描述了业务逻辑,并作为框架和业务之间的桥梁,既达到了声明式 API 的定义形式,也满足了业务不依赖框架的目标。


框架扩展


无论是路由还是服务构建过程,Nirvana 的实现都不是 hardcode 的。在框架的大部分包里,你能发现类似以下形式的代码结构:


var consumers = map[string]Consumer{    definition.MIMENone:        &NoneSerializer{},    definition.MIMEText:        NewSimpleSerializer(definition.MIMEText),    definition.MIMEJSON:        &JSONSerializer{},    definition.MIMEXML:         &XMLSerializer{},    definition.MIMEOctetStream: NewSimpleSerializer(definition.MIMEOctetStream),    definition.MIMEURLEncoded:  &URLEncodedConsumer{},    definition.MIMEFormData:    &FormDataConsumer{},}
// RegisterConsumer register a consumer. A consumer must not handle "*/*".func RegisterConsumer(c Consumer) error { if c.ContentType() == definition.MIMEAll { return invalidConsumer.Error(definition.MIMEAll) } consumers[c.ContentType()] = c return nil}
复制代码


在这种结构里,开发者可以自定义每一块的实现方式,甚至替换框架默认行为。帮助自己最大限度地利用 Nirvana,使它符合业务特定需求。


插件机制


在服务构建工作流中,我们提到了插件机制。下面我们会介绍三个重要插件 metrics、profiling 和 tracing。


  1. metrics 插件


Prometheus 作为 CNCF 的开源项目,为我们提供了非常适于描述业务指标的格式:Prometheus Metrics。Nirvana 提供的 metrics 插件可以在启动时默认暴露 /metrics 接口。对此,开发者可以将业务指标注册到 Prometheus 中,通过这个接口让 Prometheus 采集。也就是说,Nirvana 不仅能帮助开发者了解业务的运行状态,也为开发者定位业务问题提供了强有力的帮助。


  1. profiling 插件


Golang 提供了进程级别的 profiling 能力。Nirvana 通过 profiling 插件直接将这个能力注入到框架中。开发者只需要启用插件即可获得这些调试和性能测试能力,获得业务内部执行的状态信息。


  1. tracing 插件


在 CloudNative 时代,业务通常会以微服务或 Serverless 的形式进行架构。多个服务之间的交互通常是黑盒的,这易导致我们难以定位分布式架构中的服务问题。Tracing 作为解决分布式架构下的调用链方案,可以在分布式系统出现问题时为开发者提供大量的信息,帮助开发者排查问题。Nirvana 的 tracing 插件使用了 open-tracing 的接口规范,并借助 CNCF 开源项目 jaeger 的能力,为开发者提供一站式 tracing 方案。


文档和客户端生成


API Definition 和 Nirvana 的结合帮助我们完成了服务构建。在服务之外,通过 API Definition 的描述能力,Nirvana 还实现了基于 openapi 的文档生成和客户端生成。


Nirvana 的文档生成基于 openapi 2.0(即 swagger 2.0)规范,从 API Definition 中提取 API 信息,生成 API 描述文件 swagger.json。除了生成 API 描述文件之外,它还能通过 ReDoc 直接提供文档服务(更多信息请查看文档)。


在 Nirvana 中,生成文档的方式十分简单:


$ nirvana api --serve=":8081"


只需一条命令,API 文档即可生成,并通过 8081 端口提供服务。之后我们就能通过网页查看文档了:



Nirvana 的客户端生成同样基于 API Definition ——读取类型信息,生成客户端包(目前仅支持生成 Golang 包)。客户可以直接引用这个包来调用服务,整个客户端的使用方式与本地调用一致(更多信息请查看文档)。


下面是一键生成客户端的示例:


$ nirvana client


这个命令会在当前目录下生成一个 client 目录,在这个目录内生成 Golang 客户端代码:


type Client struct {    rest *rest.Client}
// ListMessages returns all messages.func (c *Client) ListMessages(ctx context.Context, count int) (messages []Message, err error) { err = c.rest.Request("GET", 200, "/apis/v1/messages"). Query("count", count). Data(&messages). Do(ctx) return}
复制代码


如果您想进一步了解 Nirvana,可以参考才云 Caicloud 云原生 CI/CD 项目 Cyclone。它包含一个 API 组件 Cyclone Server, 基于 Nirvana 对外提供简单易用的 API。

Nirvana:涅槃

Nirvana,梵语中的涅槃。


一如我们对它的期待:让 API 从对框架的依赖中涅槃重生。


经过一年多的开源,目前 Nirvana 在基础 API 服务能力上已经经过内部验证。由于数据传输层和转换层的复杂度被大大降低,才云 Caicloud 也切实体验到了这个开源框架带来的便捷,以及它在加速业务开发上的显著效果。


未来,Nirvana 将在以下几方面继续发力:


  • 持续优化扩展文档和客户端生成的能力,降低开发者在这两块上的心智负担;

  • 持续优化 metrics、profiling、tracing 的能力,并增加新的云原生能力,让这些能力成为云原生应用的标配;

  • 框架模块化加强,让 Nirvana 的每一块代码皆可定制;

  • 优化框架性能,降低反射对服务的影响;

  • 让 Nirvana 成为 Golang 的 CloudNative & SOA 框架。


Nirvana 正致力于成为让业务无感知的框架。目前,才云 Caicloud 正在这条路上踽踽独行,我们也真诚地希望将来能有更多开发者愿意加入进来,一起构建 Nirvana,一起建设 Golang 社区,一起拥抱开源的胜利。


也许你的加入,能让这场涅槃更加炫目!


感谢参与开源本项目的所有开发者!


Nirvana GitHub:https://github.com/caicloud/nirvana


Nirvana 文档:https://caicloud.github.io/nirvana/zh-hans/


2019-01-24 02:0016255

评论 1 条评论

发布
用户头像
2-3年没更新了,公司不在了吗
2023-10-24 10:33 · 北京
回复
没有更多了
发现更多内容

Nginx No, Traefik Yes

newbe36524

软件测试/测试开发丨Pytest结合数据驱动

测试人

Python 程序员 软件测试 数据驱动 pytest

应用管理平台Walrus开源,构建软件交付新范式

SEAL安全

开源软件 企业号 8 月 PK 榜 Walrus

代码随想录Day46 - 动态规划(八)

jjn0703

我可能开发了世界上最快的通用排序算法,比快排快 60%

java易二三

Java 程序员 计算机

如何在SAM时代下打造高效的高性能计算大模型训练平台

GPU算力

25. matplotlib

茶桁

Python matplotlib

在 Go 中如何编写出可测试的代码

江湖十年

golang 后端 单元测试

Python爬虫实战:根据关键字爬取某度图片批量下载到本地(附上完整源码)

小满大王i

Python 爬虫案例

MySQL运行时的可观测性

GreatSQL

数据库 greatsql

在探索的道路上持续“做对”,火山引擎A/B测试成为这家企业数字基建

字节跳动数据平台

大数据 A/B 测试 企业号 8 月 PK 榜

GPT-4 全面开放,首部 AIGC 监管法规出台,字节入局大模型 | AIGC 月报速览

码上跃见

AI AIGC GPT #科技 GPT-4

Java中的常量:让程序更加稳定和可维护

java易二三

Java 程序员 常量 计算机

MySQL : 好好学习一下InnoDB中的页

java易二三

Java MySQL 数据库 程序员 计算机

手机直播源码开发,协议讨论篇(三):RTMP实时消息传输协议

山东布谷科技

软件开发 RTMP 源码搭建 手机直播源码 实时消息传输协议

Kafka 开飙了!5分钟,带你体验一把“速度与激情”

java易二三

Java Docker 计算机

GC的前置工作,聊聊GC是如何快速枚举根节点的

Java随想录

Java JVM

中型敏捷GenAI模型:面向企业垂直领域应用的实用型AI

Baihai IDP

AI AIGC LLM 白海科技 敏捷AI

Nautilus Chain 主网上线拉开模块化序幕,一文纵览生态项目

鳄鱼视界

2023上海国际智慧停车展览会

AIOTE智博会

城博会 智慧停车展 智慧停车展会 智慧停车博览会

校源行丨开放原子开源基金会赴南大和南理工走访交流

开放原子开源基金会

开源

我们招聘啦!(Java、测试、后端)

数新网络官方账号

大数据 数据仓库 企业招聘

使用Dubbo这么久,才知道这些功能竟如此“亮眼”

java易二三

程序员 dubbo 计算机

IPD(集成产品开发)与CMMI的对比

禅道项目管理

稳定高效!NineData x SelectDB 完成产品兼容互认证

NineData

数据管理 大数据分析 SelectDB NineData 产品兼容互认证

才云开源 Nirvana:Golang REST API框架_架构_才云_InfoQ精选文章