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 框架性能基本比较测试》。
我们团队在结合自身技术栈、成本、稳定性、易用性、可维护性、业务场景等等因素综合考虑后,觉得我们面临的大多数场景中,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 代码,二是 API 文档,程序员的思维就得在代码和文档之间不断切换,工作效率必然受影响。
我们就想,能不能只需要在同一个地方修改,如果能做到,API 文档的更新就没有那么麻烦了,于人于已都是好事。
经过调研,我们选择使用 Swagger 来编写文档,按照 Swagger 的规范,在 API 上加一些描述性的 Annotation 就可以了。
通过以上的 Annotation,将自动生成以下在线 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)的几个效果图:
查看微服务之间的调用关系,调用性能
查看调用失败原因
图形化查看调用关系,太乱 ,下次迭代改进一下 [摊手]
站在技术管理者的角度,可以从调用链里看出来,哪些模块之间发生了不正当关系 [噗嗤];哪些模块之间本该有关系的,事实却没有;通过对比 Swagger 和调用链的 API 清单,找出僵尸 API……
API 测试
使用微服务架构后,API 是每个微服务的 唯一能力出口。由于互联网行业的快速发展,软件需求变更变得越来越频繁,迭代升级的速度变得越来越快。
对于提供方来说,需要保证变更和迭代的过程中,不影响之前承诺的功能(包括正确性、稳定性和性能等)。
对于调用方来说,同样需要确保自身依赖的 API 能正常使用,不能因为其它模块的错误而导致自身业务受到影响(包括正确性、稳定性和性能等)。
毕竟,从组织角度来看,系统出错就是出错,不管原因是自身导致的还是服务提供方导致的,所以 服务调用方就需要对服务提供方进行管理。
这也就是前几年契约测试(Pact)方法大行其道的原因。有兴趣的朋友可以去看看这种测试方法。
对于 API 白盒测试,推荐使用基于 Java 的 REST-Assured 测试框架,用起来特别方便。
[https://github.com/rest-assured/rest-assured]
更进一步,基于 HTTP 协议、JSON/XML 报文的规范性,完全可以开发一个 API 测试小工具(暂且叫它 小鹰 吧)来替换 REST-Assured。我们也暂未实践,只是觉得会很有用,供大家参考。
基础步骤是:
服务提供方开发 API,并正确书写 Swagger 文档。
服务提供方在小鹰的界面上选择需要测试的 API,并填写测试参数。(API 清单和参数都可以通过调用 Swagger 的 API 获取)
服务调用方根据自已的理解,也将对自己有用的服务方提供的 API 配置到小鹰上。
小鹰 7*24 小时为服务提供方和调用方巡视这些 API,并在异常出现时发送警报。
总 结
所以,对于微服务 API 开发,我们
使用最常见的技术(例如 Spring MVC)进行 API 开发
使用 REST-Assured(以及未来的 小鹰)进行测试
使用 Swagger 来管理 API 文档
使用自研的 DCTrace 进行调用链管理
Re:从 0 开始的微服务架构--(三)微服务架构 API 的开发与治理--转的更多相关文章
- 开源微信管家平台——JeeWx 捷微4.0 微服务版本发布,全新架构,全新UI,提供强大的图文编辑器
JeeWx捷微4.0 微服务版本发布^_^ 换代产品(全新架构,全新UI,提供强大的图文编辑器) JEEWX 从4.0版本开始,技术架构全新换代,采用微服务架构,插件式开发,每个业务模块都是独立的 ...
- 【CHRIS RICHARDSON 微服务系列】微服务架构中的进程间通信-3
编者的话 |本文来自 Nginx 官方博客,是微服务系列文章的第三篇,在第一篇文章中介绍了微服务架构模式,与单体模式进行了比较,并且讨论了使用微服务架构的优缺点.第二篇描述了采用微服务架构的应用客户端 ...
- 用Nacos做微服务架构里的服务注册与发现中心
转自:https://www.jianshu.com/p/61608ff86344 Nacos 另一个非常重要的特性就是服务注册与发现,说到服务的注册与发现相信大家应该都不陌生,在微服务盛行的今天,服 ...
- Java 18套JAVA企业级大型项目实战分布式架构高并发高可用微服务电商项目实战架构
Java 开发环境:idea https://www.jianshu.com/p/7a824fea1ce7 从无到有构建大型电商微服务架构三个阶段SpringBoot+SpringCloud+Solr ...
- 学习一下 SpringCloud (一)-- 从单体架构到微服务架构、代码拆分(maven 聚合)
一.架构演变 1.系统架构.集群.分布式系统 简单理解 (1)什么是系统架构? [什么是系统架构?] 系统架构 描述了 在应用程序内部,如何根据 业务.技术.灵活性.可扩展性.可维护性 等因素,将系统 ...
- 8.rabbitmq RPC模拟微服务架构中的服务调用
标题 : 8.rabbitmq RPC模拟微服务架构中的服务调用 目录 : RabbitMQ 序号 : 8 { var connectionFactory = new ConnectionFactor ...
- Chris Richardson微服务翻译:微服务架构中的服务发现
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现(本文) 微服务之事件驱动的数据管理 微服 ...
- [转]系统架构演变--集中式架构-垂直拆分-分布式服务-SOA(服务治理)-微服务
一.系统架构演变 1.1. 集中式架构 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本.此时,用于简化增删改查工作量的数据访问框架(ORM)是影响项目开发的关键. 存在的 ...
- 【转】「Chris Richardson 微服务系列」微服务架构的优势与不足
Posted on 2016年5月4日 编者的话|本文来自 Nginx 官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战. 作者介绍:Chris Ric ...
随机推荐
- NEU2016年一月月赛回顾
月赛传送门 http://acm.neu.edu.cn/hustoj/contest.php?cid=1066 月赛已经结束十天了...才把题目补完真是大失误... 茅巨巨四天前就补完了,,,总结写得 ...
- React中多行文本省略不生效原因
在普通的前端项目中,在不考虑兼容问题的时候,可以用以下代码实现: overflow : hidden; text-overflow: ellipsis; display: -webkit-box; - ...
- 8.QList QMap QVariant
QList int main1(int argc, char *argv[]) { QApplication a(argc, argv); QList<,,}; mylist << ...
- 算法入门经典-第七章 例题7-4-1 拓展 n皇后问题 回溯法
实际上回溯法有暴力破解的意思在里面,解决一个问题,一路走到底,路无法通,返回寻找另 一条路. 回溯法可以解决很多的问题,如:N皇后问题和迷宫问题. 一.概念 回溯算法实际类似枚举的搜索尝试过程,主 ...
- java代码实现python2中aes加密经历
背景: 因项目需要,需要将一个python2编写的aes加密方式改为java实现. 1.源python2实现 from Crypto.Cipher import AES from binascii i ...
- IIS之虚拟目录学习
从刚实习开始就了解到虚拟目录这个词,但是一直没去研究过什么意思,而且也没实际用过.一晃两年过去了,今天正好趁休息,补补脑学习下. 通过百度了解到,虚拟目录创建的目的是为了应对磁盘容量爆满,部署的网站不 ...
- 【转】C# ABP WebApi与Swagger UI的集成
以前在做WebAPI调用测试时,一直在使用Fiddler测试工具了,而且这个用起来比较繁琐,需要各种配置,并且不直观,还有一点是还得弄明白URL地址和要传递的参数,然后才能调用. 最近新入职,公司里 ...
- struts2学习之基础笔记4
拦截器 1.自定义拦截器类,必须继承AbstractInterceptor类(抽象类) 重写public String intercept (ActionInvocation arg0) 2.在Str ...
- animate.css引入实现动画效果
最近在网上看到很多代码都通过引入animate.css来实现动画效果,后来我便使用这种方法来尝试着写了个小案例,结果真的很好用,比我们通常情况下使用css或js实现动画效果好得多,便在此做个总结. 第 ...
- px 与 pt
px:pixel,像素,屏幕上显示的最小单位,用于网页设计,直观方便: pt:point,是一个标准的长度单位,1pt=1/72英寸,用于印刷业,非常简单易用: em:即%,在CSS中,1em=100 ...