Re:从 0 开始的微服务架构:(三)微服务架构 API 的开发与治理

阅读数:5768 2017 年 9 月 21 日 17:07

虽然已经红了很久,但是“微服务架构”正变得越来越重要,也将继续火下去。各个公司与技术人员都在分享微服务架构的相关知识与实践经验,但我们发现,目前网上的这些相关文章中,要么上来就是很有借鉴意义的干货,要么就是以高端的专业术语来讲述何为微服务架构。就是没有一个做到成熟地将技术传播出来,同时完美地照顾“初入微服务领域人员”,从 0 开始,采用通俗易懂的语言去讲解微服务架构的系列。所以,我们邀请青柳云的苏槐与 InfoQ 一起共建微服务架构专题“Re:从 0 开始的微服务架构”,为还没有入门该领域的技术人员开路,也帮助微服务架构老手温故知新。

这是专题的第三篇文章,聊聊内网环境中的 API 开发与治理

前面的文章中有说到微服务的通信方式,Martin Folwer 先生在他对微服务的定义中也提到“每个服务运行在其独立的进程中,服务与服务间采用 轻量级的通信机制 互相协作(通常是基于 HTTP 协议的 RESTful API)”。

那么,在各个微服务之间具体怎么进行轻量级的通信呢?这篇文章就来聊聊微服务 API 开发及治理的几个方面。

首先需要解释一下,标题中的“内网环境中 的 API”指的是提供给内网里的其它微服务调用的 API。与其相对应的是“开放给互联网 用户调用的 API”,它们的开发方法大体相同,但治理方法却不太一样。

例如开放给互联网用户调用的 API 需要在 API 网关上加上授权、鉴权、限流、限并发、统计、计费等等功能。

本篇文章分享的是内网环境中的 API 开发及治理。

API 开发

API 开发,首先考虑的就是该用什么样的协议,是 HTTP API 还是 RPC?

我们先来介绍一下这两种 API 类型:

HTTP API

HTTP API 指的是简单的基于 HTTP 协议的 API,具体的例子就是 Spring MVC 的 Controller,例如 

http://127.0.0.1/helloworld/myapi.do”

RPC

RPC 就是 Remote Procedure Call,中文名远程过程调用,在 API 调用的场景下,大多指的是基于 Socket 通信方法的远程调用(当然,我们也可以使用 HTTP 协议来实现 RPC 调用,例如 gRPC)。Json-RPC 和 Xml-RPC 指的是使用 Json 或 Xml 作为文本格式的方式传输命令和数据。

那么回到刚才那个问题,到底要使用 HTTP API 还是 RPC 呢?我们之所要对比 HTTP API 和 RPC,主要是因为大家都知道 HTTP 简单,而基于 Socket 的 RPC 性能更好

这个问题我们纠结了很久,直到后来,想明白了下面两件事,最终决定在绝大部分场景中使用 HTTP API。

HTTP API 的性能足以支撑大多数项目

通常来讲(根据资料),算上序列化的时间,RPC 协议的吞吐量是 HTTP 性能 两倍(没有亲测),例如 Protobuf、Thrift、Kyro、Dubbo 等等。

这里面,又以 Thrift 的性能最高。具体的性能测试报告可以参考《RPC 框架性能基本比较测试》。

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

我们团队在结合自身技术栈、成本、稳定性、易用性、可维护性、业务场景等等因素综合考虑后,觉得我们面临的大多数场景中,HTTP 和 RPC 的性能差别并不是主要问题

再加上下图所示的 HTTP 性能测试结果作为佐证,我们完全可以采用 HTTP API 的方式来进行微服务 API 开发。

再者,当业务发展到一定的程度,如果某些业务功能的性能压力变大时,我们还是可以使用 RPC 小范围地进行改造。这也是符合敏捷思想的一个决定。

下图是对 helloworld 页面进行 10000 次连续请求的测试结果,总耗时 1.504 秒,平均每个请求耗时 0.15 毫秒。

测试环境:原生 Tomcat7(没有任何优化)运行在本地虚拟机上

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

下面是对 helloworld 页面以 100 并发数进行 10 万次请求的测试结果,平均每个请求耗时 11.9 毫秒。

测试环境:原生 Tomcat7(没有任何优化)运行在本地虚拟机上

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

所以,按照上面的测试结果,HTTP API 方式的性能完全足以支撑绝大多数的微服务 API 开发。让我们把 RPC 方式留给那些可能出现双十一业务量的大型互联网公司去玩

RESTful API 适用于开放 API 的场景

这是另一个折磨人的问题。相对于 HTTP API,RESTful API 在 HTTP API 的基础上增加了一些非常抽象晦涩的概念,例如资源(Resource)、表述(REpresentation)、状态转移(State Transfer)、统一接口(Uniform Interface)……。

在经历了一次又一次的折磨,例如“login/logout 是什么 RESTful 方法?”、“批量删除该怎么实现?”、“RESTful 的 resource 究竟该怎么定义?”之后,越来越感觉这是一个形而上学的问题,太过于抽像。

我们不该盲从于时髦的技术,需要加上技术人的基于自身情况的理性思考。所以,RESTful 虽好,但不是我们团队的菜。

再者,即使团队中有些人可以理解并正确地实践,也很难或者说不可能让整个团队来正确地实践这样一种方法。

所以,我们在一番挣扎后,选择了 HTTP API 方式,原来怎么开发,现在还是怎么开发,把主要精力放到了 API 的监控和治理上面。

这里推荐大家看看知乎上的这篇讨论 《WEB 开发中,使用 JSON-RPC 好,还是 RESTful API 好?》, 几位大神讲得都挺好。

API 治理

API 文档

API 存在的意义在于有人调用它,如果调用方在调用 API 的时候很麻烦,甚至不能正确地调用,那么团队内部及团队之间的沟通成本及配合程度就会大受影响。

我们是通过文档来沟通的,项目开始的时候还好,但随着时间的推移,文档的更新变得不是那么及时(这其实是个自我辩解的说法,事实是大部分情况下文档都不更新了),API 变更时,也不容易找出哪些模块调用了这个 API。

所以,得先解决 文档不及时更新 的问题。虽然我们可以通过流程管理的方式来强制大家更新文档,但这对于开发人员来说,显然是不够科学或人性化的,因为变更一个 API,就要在两个地方进行修改,一是 API 代码,二是 API 文档,程序员的思维就得在代码和文档之间不断切换,工作效率必然受影响。

我们就想,能不能只需要在同一个地方修改,如果能做到,API 文档的更新就没有那么麻烦了,于人于已都是好事。

经过调研,我们选择使用 Swagger 来编写文档,按照 Swagger 的规范,在 API 上加一些描述性的 Annotation 就可以了。

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

通过以上的 Annotation,将自动生成以下在线 API 文档。

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

调用方可以在 API 文档界面填入参数并点击“Try it out!”按钮尝试调用这个 API。这样,在没有 API 提供方支持的情况下,即可以自行完成绝大部分的 API 调用,是不是很爽?

调用链管理

API 开发出来了,API 文档也写好了,接下来就是被调用了。前篇文章讲到,通过 Spring Cloud 的 Eureka + Ribbon + Zuul 可以很方便地调用到这些 API。

那么,如何来追踪 API 被谁调用了,调用是否出错及出错原因,调用链路里各个 API 的性能怎么样,是不是存在僵尸 API……这些都是关于 API 治理的问题。

实现这个目标,有一个比较取巧的方法,就是在 Ribbon 的客户端里做点文章,在调用 API 之前记录一下开始时间,API 调用返回后,记录 API 调用耗时、调用状态,如果有错则记录一下错误原因。

如果还想追踪调用链,可以在请求头里加上一个调用链 ID,这样就来把调用关系都串连起来。

下边是我们自己研发的调用链管理组件(DCTrace)的几个效果图:

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

查看微服务之间的调用关系,调用性能

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

查看调用失败原因

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

图形化查看调用关系,太乱 ,下次迭代改进一下 [摊手]

站在技术管理者的角度,可以从调用链里看出来,哪些模块之间发生了不正当关系 [噗嗤];哪些模块之间本该有关系的,事实却没有;通过对比 Swagger 和调用链的 API 清单,找出僵尸 API……

API 测试

使用微服务架构后,API 是每个微服务的 唯一能力出口。由于互联网行业的快速发展,软件需求变更变得越来越频繁,迭代升级的速度变得越来越快。

对于提供方来说,需要保证变更和迭代的过程中,不影响之前承诺的功能(包括正确性、稳定性和性能等)。

对于调用方来说,同样需要确保自身依赖的 API 能正常使用,不能因为其它模块的错误而导致自身业务受到影响(包括正确性、稳定性和性能等)。

毕竟,从组织角度来看,系统出错就是出错,不管原因是自身导致的还是服务提供方导致的,所以 服务调用方就需要对服务提供方进行管理

这也就是前几年契约测试(Pact)方法大行其道的原因。有兴趣的朋友可以去看看这种测试方法。

对于 API 白盒测试,推荐使用基于 Java 的 REST-Assured 测试框架,用起来特别方便。

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

更进一步,基于 HTTP 协议、JSON/XML 报文的规范性,完全可以开发一个 API 测试小工具(暂且叫它 小鹰 吧)来替换 REST-Assured。我们也暂未实践,只是觉得会很有用,供大家参考。

(点击放大图像)

Re:从0开始的微服务架构:(三)微服务架构 API 的开发与治理

基础步骤是:

  1. 服务提供方开发 API,并正确书写 Swagger 文档。

  2. 服务提供方在小鹰的界面上选择需要测试的 API,并填写测试参数。(API 清单和参数都可以通过调用 Swagger 的 API 获取)

  3. 服务调用方根据自已的理解,也将对自己有用的服务方提供的 API 配置到小鹰上。

  4. 小鹰 7*24 小时为服务提供方和调用方巡视这些 API,并在异常出现时发送警报。

总结

所以,对于微服务 API 开发,我们

  • 使用最常见的技术(例如 Spring MVC)进行 API 开发

  • 使用 REST-Assured(以及未来的 小鹰)进行测试

  • 使用 Swagger 来管理 API 文档

  • 使用自研的 DCTrace 进行调用链管理

作者介绍

苏槐,微信号 Sulaohuai,青柳云研发总监,现服务于神州数码青柳云团队,曾就职于 Oracle,新加坡电信等企业。擅长容器技术、微服务架构、敏捷开发及技术管理。


感谢雨多田光对本文的策划和审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

评论

发布