虽然已经红了很久,但是“微服务架构”正变得越来越重要,也将继续火下去。各个公司与技术人员都在分享微服务架构的相关知识与实践经验,但我们发现,目前网上的这些相关文章中,要么上来就是很有借鉴意义的干货,要么就是以高端的专业术语来讲述何为微服务架构。就是没有一个做到成熟地将技术传播出来,同时完美地照顾“初入微服务领域人员”,从 0 开始,采用通俗易懂的语言去讲解微服务架构的系列。所以,我们邀请青柳云的苏槐与 InfoQ 一起共建微服务架构专题“
Re:从 0 开始的微服务架构
”,为还没有入门该领域的技术人员开路,也帮助微服务架构老手温故知新。
这是专题的第三篇文章,聊聊内网环境中的 API 开发与治理
。
前面的文章中有说到微服务的通信方式,Martin Folwer 先生在他对微服务的定义中也提到“每个服务运行在其独立的进程中,服务与服务间采用
轻量级的通信机制
互相协作(通常是基于 HTTP 协议的 RESTful API)”。
那么,在各个微服务之间具体怎么进行轻量级的通信呢?这篇文章就来聊聊微服务 API 开发及治理的几个方面。
首先需要解释一下,标题中的“
内网环境中
的 API”指的是提供给内网里的其它微服务调用的 API。与其相对应的是“
开放给互联网
用户调用的 API”,它们的开发方法大体相同,但治理方法却不太一样。
例如开放给互联网用户调用的 API 需要在 API 网关上加上授权、鉴权、限流、限并发、统计、计费等等功能。
本篇文章分享的是内网环境中的 API 开发及治理。
API 开发,首先考虑的就是该用什么样的协议,是 HTTP API 还是 RPC?
我们先来介绍一下这两种 API 类型:
HTTP API 指的是简单的基于 HTTP 协议的 API,具体的例子就是 Spring MVC 的 Controller,例如
“
http://127.0.0.1/helloworld/myapi.do
”
。
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。
通常来讲(根据资料),算上序列化的时间,RPC 协议的吞吐量是 HTTP 性能
两倍
(没有亲测),例如 Protobuf、Thrift、Kyro、Dubbo 等等。
这里面,又以 Thrift 的性能最高。具体的性能测试报告可以参考《RPC 框架性能基本比较测试》。
我们团队在结合自身技术栈、成本、稳定性、易用性、可维护性、业务场景等等因素综合考虑后,觉得我们面临的大多数场景中,
HTTP 和 RPC 的性能差别并不是主要问题
。
再加上下图所示的 HTTP 性能测试结果作为佐证,我们
完全可以
采用 HTTP API 的方式来进行微服务 API 开发。
再者,当业务发展到一定的程度,如果某些业务功能的性能压力变大时,我们还是可以使用 RPC 小范围地进行改造。这也是符合敏捷思想的一个决定。
下图是对 helloworld 页面进行 10000 次连续请求的测试结果,总耗时 1.504 秒,平均每个请求耗时 0.15 毫秒。
测试环境:原生 Tomcat7(没有任何优化)运行在本地虚拟机上
下面是对 helloworld 页面以 100 并发数进行 10 万次请求的测试结果,平均每个请求耗时 11.9 毫秒。
测试环境:原生 Tomcat7(没有任何优化)运行在本地虚拟机上
所以,按照上面的测试结果,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 好?》
,几位大神讲得都挺好。
[
https://www.zhihu.com/question/28570307
]
API 存在的意义在于有人调用它,如果调用方在调用 API 的时候很麻烦,甚至不能正确地调用,那么团队内部及团队之间的沟通成本及配合程度就会大受影响。
我们是通过文档来沟通的,项目开始的时候还好,但随着时间的推移,文档的更新变得不是那么及时(
这其实是个自我辩解的说法,事实是大部分情况下文档都不更新了
),API 变更时,也不容易找出哪些模块调用了这个 API。
所以,得先解决
文档不及时更新
的问题。虽然我们可以通过流程管理的方式来强制大家更新文档,但这对于开发人员来说,显然是不够科学或人性化的,因为变更一个 API,就要在两个地方进行修改,一是 API 代码,二是 API 文档,程序员的思维就得在代码和文档之间不断切换,工作效率必然受影响。
我们就想,能不能只需要在同一个地方修改,如果能做到,API 文档的更新就没有那么麻烦了,于人于已都是好事。
经过调研,我们选择使用 Swagger 来编写文档,按照 Swagger 的规范,在 API 上加一些描述性的 Annotation 就可以了。