转载

通过基于Go的微服务框架goa,实现对服务API的定义、审查与实现

Raphael Simon是来自于RightScale的一位高级系统架构师,他创建了一种基于Go语言的HTTP微服务框架,名为 “goa” 。这一框架允许开发者通过 领域特定语言 (DSL)定义服务的API,并且通过自动代码生成功能创建“样板”式的服务端和客户端代码以及文档。

Raphael在他的博客 Gopher Academy 上发表了一篇介绍goa框架的帖子,他提到RightScale的工程师团队正在将一个一体性的Ruby on Rails应用迁移为一系列基于Go语言创建的微服务应用。这次迁移工作的一个主要挑战在于如何创建设计良好的服务API,为了支持整个微服务API的设计、审查以及实现,他们创建了一系列的工具。这一项目所产生的结果之一就是基于Go语言的框架goa的诞生,它的出现受到了在RightScale中所应用的一个基于Ruby的API开发框架 Praxis 的启发。

InfoQ与 Simon 进行了一次访谈,他既是 RightScale 的高级系统架构师,也是goa的主要 贡献者 之一。这次访谈主要问及了关于goa这一微服务框架的设计目标、使用方式以及未来的发展计划。

InfoQ:欢迎你Raphael!请你为读者说明一下“goa”是个怎样的产品,以及创建这一架构的动力是什么。

Simon:RightScale正在向微服务风格的架构进行迁移,这项工作已经开展了一段时间了,而最近一段时间团队开始使用Go语言编写部分服务。总体来说,无论在开发还是运维方面,Go都证明了它是一个优秀的选择。这门语言很容易上手,并且所创建的服务表现也很出色。

不过,采用Go语言进行开发也意味着在开发与部署阶段要引入一种新的技术栈,因为直至最近,RightScale基本上都是使用Ruby进行开发的。团队在创建与运行REST API(RightScale已经将这一使用Ruby语言打造、用于创建REST API的 Praxis框架 开源了)方面已经具备了丰富的经验。由于目前还没有一种现成的解决方案可以应对我们的需求,因此有理由运用这些经验去打造基于一种Go语言的服务开发栈。

这项工作的成果就是goa的诞生,它是一个微服务的开发框架,通过它能够以代码的方式描述API的设计。与goa框架一同推出的还有一个goagen工具,它能够通过设计代码生成各种输出,包括http服务器的封装、代码脚手架、文档、客户端,甚至是自定义的输出。goa包还包括大量的支持性模块,服务本身与生成的代码都能够利用这些模块进行服务的实现。

InfoQ:与使用标准的Go类库(或者使用Peter Bourgon开发的go-kit)相比,“goa”通过怎样的方式简化了微服务的开发?

Simon:goa框架能够描述API的 意图 。通过使用goa设计语言,开发者能够定义API所暴露的资源与行为(即API的终结点)。对于每种行为的描述包括所期待的请求状态,以及各种可能产生的响应。这种方式能够带来许多益处:举例来说,它在设计阶段就能够起到很大的作用,各个团队能够通过Swagger UI生成Swagger的规格说明,从而提出反馈意见。这一反馈循环能够为负责生成UI或编写面向用户的文档的团队带来极大的便利。最大的优点在于,这一切都发生在实际编写代码实现之前。

这种方式的另一优点在于,一旦设计完成之后,goa就将负责生成所有样板逻辑,包括请求的验证以及用于描述请求状态的自定义数据结构。这样一来, 设计就变成了实现所必需的一部分 。这就体现出了这一方式具有很高价值的一面,否则的话,维持实现与设计之间的同步就成了非常一项非常繁琐的流程。对于每个暴露了访问功能的行为来说,goa能够生成特定的请求处理逻辑的上下文,从中返回符合设计所描述的数据结构。这种做法减少了对“绑定”方式的需求,也不必手动地验证所传入的请求的格式。

goagen也能够为API生成相应的客户端,包括一个命令行工具、Go包和JavaScript的客户端。这种方式显而易见的好处是免去了手动进行这一过程所花的时间,除此之外,它还有助于维护多个客户端之间的一致性,并且保持他们与API的同步。在微服务的世界中,服务的数量是持续增长的,因此保持他们之间的一致性是一种非常有价值的做法,它大大地简化了构建整合的流程。

InfoQ:“goa”看起来为开发者提供了很多内容,包括一个运行时“引擎”、支持日志记录、能够对“中间件”进行自定义、还支持错误处理。你是否打算为基于Go的微服务架构提供一个单一的解决方案?

Simon:goa中的请求上下文是运行时引擎的核心,它引用了golang这个包的开发者所做的工作,主要是 跨接口传递上下文 的功能,从而实现一些强大的特性,例如设置deadline,以及在goroutine之间共享状态信息。举例来说,上下文信息能够一路传递至负责生成外部请求的软件模块,因此,在整个周期中的任何阶段,都能够获取包括deadline在内的整个请求状态。生成的代码将以一种特定于行为的数据结构对上下文进行封装,通过在设计代码中所描述的字段暴露已验证的请求的状态。

而其余部分的行为都是能够进行替换的:goa的设计遵循了“提供内置支持”的模型。举例来说,如果你对于如何进行错误处理并没有非常确定的想法,那么goa将为你提供一种恰当的默认实现(在这种情况下所返回的响应将包括500状态码)。不过,开发者也能够方便地覆盖默认的错误处理逻辑,以实现任何自定义的逻辑,goa还提供了一种备选的错误处理逻辑,在响应中将不包括调用栈的信息。另一个例子是对中间件的支持:goa定义了一种专用类型的中间件,可以通过它利用丰富的上下文信息,但同时也能够使用普通的http中间件。

目前来说,并非所有特性都能够被轻易地替换(例如日志记录),因为goa最初的关注点在于代码的生成。总体目标是提供一个完整的、模块化的微服务开发框架,因此,曾使用过go-kit或其它Go包的开发者依然能够继续使用它们,而同时又能够受益于goa所提倡的基于设计的API设计方式。

InfoQ:我们很有兴趣了解一下关于生成能够调用服务API的客户端代码的特性。通常来说,有关代码生成的讨论总是会得到一些消极的回应,例如生成的代码过于复杂,或是生成过程不够透明、也无法进行自定义。你能否为我们解释一下你选择这种实现方式的原因?

Simon:这里的诀窍在于所生成的代码实现的功能只是一些繁琐的样板代码,这些生成代码的结构与你“手写”这些代码的结果是相同的。goagen尽了最大努力以试图遵循“尽量减少令人惊讶的部分”的原则。你甚至可以说生成的最终代码看起来更“标准”(并且更高效)。举例来说,它减轻了对反射的依赖,否则的话,实现相同的功能可能要写上几千行代码。我们可以以客户端的Go包为例,你恐怕很难想到它居然是自动生成的。好吧,或许有些本地变量的命名看起来有点古怪,这可能会使你查觉到真相 :)

goa的代码生成还有一个十分重要的特点,即所生成的代码始终处于一个不同的包中,而无需进行手动修改,从而清晰地区分了用户代码与生成的代码。goagen将始终重新生成整个包,因此不可能出现用户代码与生成代码相混合的情况。这里有一种例外情况,即goagen可以在编码的起始阶段生成一种一次性的脚手架代码。

最后,goagen只会生成必要的代码,所生成的代码将使用goa包实现各种通用的功能,例如日志记录、错误处理等等。它提供了一种优秀的方式对生成代码的行为进行自定义,而无需进行手动修改。举例来说,你可以实现一种自定义的服务错误处理逻辑,并且让所有生成代码自动调用这段自定义逻辑。你可以将这种生成代码想象为一种goa包的“插件”,并暴露相应的调节器以修改它的行为。

goagen也支持插件系统,它实质上就是一种标准的Go包,其中包含了一个公开的Generate函数。由Brian Ketelsen所编写的 gorma插件 是对这一项目最早的贡献之一,它能够通过API设计中所描述的类型生成 gorm 模型。整个项目最令人惊讶的部分就在于通过代码(以及其他功能)生成所带来的各种可能性。在我看来,这一设想已经很明显地在Go语言中得到了很好的表现。

InfoQ:如果InfoQ的读者有兴趣加入“goa”项目,或是为其贡献代码,最好的途径是什么?

Simon:在GitHub库上的wiki中包括一份 路线图的文档 ,其中可以找到许多建议,但这些仅仅是建议而已。这一项目最值得赞扬的一点在于它在社区中得到了快速的应用,而且在我所没有考虑到的方面也得到了许多代码贡献。goa依然是一个很新的构架,整个项目的发展方向存在于许多可能性。此外,在 gophers.slack.com 上还有一个活跃的#goa slack频道。因此,建议大家去访问GitHub库、加入slack频道,并且开始尝试!

本项目 确实 有一个地方或许需要大家的帮助:它需要一个logo! 它的网站 页面可能也需要动一下整形手术 ;)

InfoQ:Raphael,感谢你参加今日的访谈。对于InfoQ的读者,你还有什么内容想同大家分享的吗?

Simon:感谢你的邀请!我推荐所有希望创建API的读者们去尝试一下goa,我真的相信它能够帮助你们更高效地打造服务。微服务风格的架构如今已经快速地成长为事实上的标准,这使得设计优秀的API这一任务显得更为关键,而优秀的工具能够起到极大的作用。随着goa的使用率不断增长,我对于它的发展充满期待,并且迫不及待地想看到用户能够通过它实现哪些功能。

如果想了解有关goa微服务框架的更多信息,可以阅读Gopher Academy博客上的“ goa: Untangling Microservices ”这篇帖子,并访问 goa的GitHub库 。

查看英文原文: Defining, Reviewing and Implementing Service APIs with “goa”, a Go-based Microservice Framework

正文到此结束
Loading...