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 ...
随机推荐
- System.setProperty 与 System.getProperty
转自:https://www.cnblogs.com/woftlcj/p/8404451.html System可以有对标准输入,标准输出,错误输出流:对外部定义的属性和环境变量的访问:加载文件和库的 ...
- 12. Integer to Roman[M]整数转罗马数字
题目 Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from ...
- web.config配置文件使用总结
我们在开发web系统的时候,使用web.config进行配置是司空见惯的,那么web.confg到底是什么呢?什么时候使用web.config呢?有几种使用web.config方式呢? 如果不太明白的 ...
- The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online J Press the Button
BaoBao and DreamGrid are playing a game using a strange button. This button is attached to an LED li ...
- Codeforces Round #499 (Div. 2) F. Mars rover_dfs_位运算
题解: 首先,我们可以用 dfsdfsdfs 在 O(n)O(n)O(n) 的时间复杂度求出初始状态每个点的权值. 不难发现,一个叶子节点权值的取反会导致根节点的权值取反当且仅当从该叶子节点到根节点这 ...
- Pyhton学习——Day50
#HTTP协议# 又是转载:http://www.cnblogs.com/yuanchenqi/articles/6000358.html# 一 HTTP概述# HTTP(hypertext tran ...
- node——含有异步函数的函数封装
在写代码时我们会发现有大量的重复代码,为了使代码更加简洁,我们可以将重复的代码封装为一个可以在多个部分时候用的函数. 之前写的新闻代码中,经常出现的操作有对文件的读取,我们可以将它封装为一个函数rea ...
- NTP同步底层实现
RFC http://www.ietf.org/rfc/rfc5905.txt https://www.eecis.udel.edu/~mills/ntp/html/select.html https ...
- 郑晔谈 Moco 框架的开发:写一个好的内部 DSL ,写一个表达性好的程序
作者:张龙 出处:http://www.infoq.com/cn/news/2013/07/zhengye-on-moco 郑晔谈Moco框架的开发:写一个好的内部DSL,写一个表达性好的程序 作者 ...
- 使用面向对象技术创建高级 Web 应用程序
作者: 出处: 使用面向对象技术创建高级 Web 应用程序 来源:开源中国社区 作者:oschina 最近,我面试了一位具有5年Web应用开发经验的软件开发人员.她有4年半的JavaScript编程经 ...