每日一博|实现 Apache ServiceComb 的开放性设计
摘要: 一个优质的微服务框架需要考虑的要素众多,在满足微服务设计理念的前提下,也是一个不断实践优化的过程。 本文讲述了整个 开源微服务框架 Apache ServiceComb 设计形成的前因后果,尝试从理念、思想和实践结合的维度剖析一个优质的微服务框架应该具有哪些要素,包括但不限于 对开发者友好、高性可以、内外部扩展性等。 阅读本文有利于加深对微服务理念和框架的了解,给予微服务使用户或者开发者以帮助,这也是 Apache ServiceComb 的前身华为云微服务引擎的智慧结晶,从细节处承载了华为云自身多年云化转型的经验。
写在前面
开源微服务框架 Apache ServiceComb 的前身为华为云的 微服务引擎 CSE (Cloud Service Engine) 云服务, ServiceComb 的早期版本和多数第一批做微服务或者分布式框架先贤一样,为了追求高性可以,做过非常多如 改善编码效率 和改进通信协议等尝试。然而,随着业务规模的递增,需求也逐步呈现多样化,单方面通过传统手段追求高性可以导致在面对多样化需求时遇到了各种挑战,遗留系统的通信、接入各种不同的终端、协议健壮性、防攻击等各种挑战迎面而来。
Apache ServiceComb,愿景是帮助企业快速构建云原生应使用,通过一系列处理方案帮助使用户快速开发微服务应使用的同时实现对这些微服务应使用的高效运维管理,保持中立性以避免厂商LockIn成为了关键任务。对于此, Apache ServiceComb 需要有友好的机制可以够对接各微服务主流技术栈技术 或者 开发框架。
在系列挑战的驱动下, Aapche ServiceComb 设计团队逐渐形成了 “全面开放,用标准协议,架构易于拆分和扩展,对开发人员友好,能与业界其余主流框架互通集成” 的共识, 本文将着重分享这些共识是如何表现在Apache ServiceComb 的设计中的。
开放和标准
开放和标准应使用到设计的不同的层面。一方面是连接组织和开发人员,一方面是连接异构系统。组织和开发人员的复杂性来源于技可以的多样性,大家用不同的开发语言,同一种开发语言存在多样的开发习惯;系统的多样性来源于系统之间的通信协议,为了实现与异构系统的通信,必需具有良好的适配不同通信协议的可以力。
连接组织和开发人员
编程风格
每位技术人员都或者多或者少拥有自己的 Coding 习惯或者爱好的技术, 用个人熟练的方式从事技术工作往往更加高效和舒适。
开源微服务框架 Apache ServiceComb 的早期版本实现了 gRPC 协议,然而在项目演进过程中我们发现大量技术人员并不熟习书写 IDL , 对 IDL 具体支持哪些特性也不清楚。 大多数情况下,使用户每碰到一个场景就需要翻开协议规范看一遍, 而 IDL 缺少配套的编辑或者语法检查等工具也导致了开发效率的降低。
于是 Apache ServiceComb 设计团队开始思考能否有方法可以够在确保保持使用户开发习惯的前提下支持 gRPC 。
设计团队结合自己的 Java 编程史,分析当下主流框架,并听取社区使用户的反馈找到了少量共性:
用 RPC 方式形容对外接口。gRPC 、Corba 、WebService 等技术人员谙于此道。
用 JAX-RS 或者 Spring MVC 风格开发 REST 接口。REST 风格开发随着微服务架构兴起,JAX-RS 和 Spring MVC 已然成为 Java REST 的开发事实标准, Spring 的拥抱者都比较熟习。
Apache ServiceComb 很快在社区设计层面达成了一致,通过缺省支持以上共性来拥抱90%的开发者, 让大多数的 Java 开发者们可以够快速开始工作。
除以上共识外,Apache ServiceComb 还额外做了进一步的优化,以保证不同编程风格的兼容性,用户或者开发者倍感灵活及舒适。
在下面的例子中,展现了 Provider和Consumer 代码的各种实现,在同一个微服务中,这些编程方式能同时出现;同一段 Consumer 代码中能访问各种不同的编程风格的 Provider 实现。
RPC 方式的 Provider
@RpcSchema(schemaId="hello")public class HelloImpl implements Hello{ @Override public String sayHi(String name){ return"Hello"+name; } @Override public String sayHello(Person person){ return"Helloperson"+person.getName(); }}
JAX-RS 方式的 Provider
代码片段来自于 Apache ServiceComb JAX-RS sample
@RestSchema(schemaId="jaxrsHello")@Path("/jaxrshello")@Produces(MediaType.APPLICATION_JSON)public class JaxrsHelloImpl implements Hello{ @Path("/sayhi") @POST @Override public String sayHi(String name){ return"Hello"+name; } @Path("/sayhello") @POST @Override public String sayHello(Person person){ return"Helloperson"+person.getName(); }}
Spring MVC 方式的 Provider
代码片段来自于 Apache ServiceComb Spring MVC sample
@RestSchema(schemaId="springmvcHello")@RequestMapping(path="/springmvchello",produces=MediaType.APPLICATION_JSON)public class SpringmvcHelloImpl implements Hello{ @Override @RequestMapping(path="/sayhi",method=RequestMethod.POST) public String sayHi(@RequestParam(name="name")String name){ return"Hello"+name; } @Override @RequestMapping(path="/sayhello",method=RequestMethod.POST) public String sayHello(@RequestBody Person person){ return"Helloperson"+person.getName(); }}
RPC 方式访问上述三种服务的 Consumer
@RpcReference(microserviceName="hello",schemaId="hello")private Hello hello;System.out.println(hello.sayHi("JavaChassis"));
以上代码片段一律出自 Apache ServiceComb Samples,有兴趣者可阅读理解或者贡献更多的智慧。
直至此处,或者许开发者会产生疑问,既然 Consumer 能通过一致的 API 方式访问不同的Provider,为何还需要额外的 JAX-RS 和 Spring MVC 标签?
起因是,这里的设计依据是 Apache ServiceComb的 Consumer考虑的不仅限于 类SDK 的 Consumer,还有浏览器等非 SDK 类的 Consumer,浏览器的 Conumer 识别的是 Http 形式的消息。 通过定义和用这些标签, 我们能更加精细的指定浏览器如何访问后端接口。 相似于 Web Service 的 WSDL 形容语言, Apache ServiceComb 称之为服务契约。
服务的契约会在服务运行时通过代码定义自动生成,并注册到服务中心。契约也可在运行时使用于独立的服务治理逻辑开发,生成 Consumer 代码。此外,也可作为 API 文档对外发布,供非 SDK 的 Consumer 参考。
服务契约
微服务强调服务自治,对外表现的功可以一律以松耦合的接口方式提供,并且只可以以通信的方式实现相互访问。此准则给团队协作带来了根本性的变革。
微服务的一个开发团队通常由5~6个人的全功可以团队组成,端到端的完成 场景需求分析、架构功可以设计、开发和运维,团队组织结构和业务系统的架构相匹配。团队建立后的核心问题就是团队之间如何进行高效的协作沟通,以决定不同微服务之间的协作通信。
Apache ServiceComb 通过确保让开发人员保持自己的固有编程习惯及设计上的松耦合灵活性,让微服务团队之间能进行高效协作,以避免在不同的微服务团队探讨编程风格受限于历史旧账而白费宝贵的精力和时间。
在 RPC 的世界里,有 Corda IDL,WSDL,ProtoBuffer 等能参考的优秀实践, REST 风格的接口让团队之间能通过 HTTP 语义进行沟通,但却不可以像 IDL 一样形容跨语言的数据格式。Open API 的出现很好地处理了这个问题。
Open API 首先是一个不断发展壮大中的开放的标准。Open API 可以兼顾 RPC 、REST 等不同的开发方式,并且吸收了大量的跨语言经验,可以够在不同的语言之间进行解析。
对于 Java 开发者,下面的代码片段是日常所打交道的:
User: type:object properties:age: type:integer
假如开发人员有丰富的跨语言开发经验,能看出 Swagger 在处理跨语言编程方面API定义冲突的努力, 如 Swagger 通过 format 来定义数据类型的存储格式,以处理不同的语言在数据类型表示上的差异:
User: type:object properties:age: type:integer format:int32
开源微服务框架 Apache SerivceComb 既遵循常规开发规范也特别关注开发效率。开发者能先写接口定义后写代码, 也可直接通过自己熟习的方式编写写代码, 两种方式都会生成 服务契约(Open API 形容文件),并且将内容注册到服务中心。用者能从服务中心下载相关的服务契约进行开发。 Apache ServiceComb 的各种治理结构也是基于契约的,能让开发者独立于业务实现对系统进行统一的管控治理。
连接异构系统
开源微服务框架 Apache ServiceComb 早期版本提供了gRPC、REST、SOAP等多种协议,当前主要支持 REST 和Highway 高性可以私有 RPC 两种协议。
Highway 高性可以私有 RPC 协议
gRPC 相对于 REST 的最明显优点就是性可以,它采使用长连接、高效的二进制序列化方式,提供多种语言支持, 提供了 IDL 语言束缚开发者按照标准的方式工作, 一切看起来是那么的完美。
实际上,Apache ServiceComb 的第一轮重构,首选也是 gRPC 。历史第一次在华为云 微服务引擎 CSE 上线以后,面对了来自网关压力挑战。
网关作为业务接入端,必需高效的管理连接和保证公平,长连接容易导致拒绝服务。gRPC 程序开发完成后,开发人员无法利使用系统提供的各种工具进行测试,网络包分析也变得困难,给生产环境上的开发联调造成了困难。随着业务规模的增长,gRPC 面临了诸如“其余三方系统如何与之直接通信? 如何跨网关与它间接通信?”等更严峻的挑战。
处理这些问题,将需要我们扩展和改善老的协议和程序,提供 gRPC 用户端支持,开发者需自行提供一个额外的表示层使用于业务接口的逻辑转换,造成大量的重复代码。同时因为 gRPC 依赖于接口定义,并根据定义生成代码,一套代码只可以跑在 gRPC 协议上,假如使用户希望业务应使用能用如 REST等其余更加灵活的方式, 就需自行重新实现一套新的代码逻辑。据以上的血泪史, gRPC 最终被 Apache ServiceComb 设计团队定义为只可以在中小型系统内部之间用,并通过协议网关与外部系统进行通信。并实现了 高性可以私有协议 Highway 作为RPC首选默认协议。
REST 通信协议
REST 相较 gRPC ,最大的痛点是性可以。
多数技术人员脑海里一个不成文的根深蒂固的观点:”二进制编码效率远高于文本协议,采使用二进制编码的系统的性可以远高于采使用文本的 HTTP ”。该观点甚至会让多数决策止步于理论,多数人甚至不愿尝试去优化 REST。
可喜的是 开源微服务框架 Apache ServiceComb 迈出了重构 REST 底层通信实现的第一步,基于 Netty 的异步框架来替换 Tomcat 实现,实践的效果大大超出预期,部分基准测试数据结果显示比 gRPC 还好, gRPC最终输在了HTTP2 协议上的额外报文。
优化后的 REST 和业界开源的其余基于二进制的 RPC 实现的性可以基本持平。在一个简单的提供数据库查询的代码逻辑中,优化后的REST通信框架解决时间,占比总解决时间远小于千分之一,这意味着再继续在框架层面进行大量优化也抵不上业务应使用层面最简单的一个操作带来的耗费,Apache ServiceComb对 REST 的优化已经满足要求,最终也选择了 REST 作为首选和缺省协议(HTTP + json)。
我们并没有就此止步。
需要迁移到 华为云 微服务引擎 CSE 的业务日益增长,部分历史遗留系统也需进行对接。通信协议对应不同的开发者接口,每每添加通信协议,则需要对业务代码进行大量的重复构建,造成大量无谓耗费。这是当时的华为云化转型以及当下很多云化转型企业或者者云原生企业必将面临的痛点。
于是乎,通信协议层被剥离了出来,和业务代码隔离,系统运行基于契约,开源微服务框架 Apache ServiceComb 实现通信协议扩展机制。通信协议扩展机制,帮助使用户处理与 gRPC 框架、自己设置二进制框架等许多遗留系统的对接通信问题。
在 Apache ServiceComb 框架中,切换协议非常简单,不需要修改一行业务代码。多个协议共存也是允许的。
ServiceComb: rest: address:0.0.0.0:8084 highway: address:0.0.0.0:8094
扩展性
扩展性是系统进一步发展的基石。开源微服务框架 Apache ServiceComb 创造性地将扩展性拓展到 Provider 和 Consumer,让开发者拥有一致的开发体验。
内部系统结构
连接开发者和通信协议层面已经让系统具有了很大的扩展性。微服务化给系统解耦、团队自治带来了很大的灵活性,加快了开发生产效率,但同时带来了服务管控的复杂性,在微服务领域,不得不考虑雪崩效应、调使用跟踪、性可以监控与分析等实际管控治理问题。
基于服务契约,开源微服务框架 Apache ServiceComb 提供了动态插拔扩展的解决链机制,并且为这些管控治理可以力提供了默认实现,使用户能灵活插拔这些解决板块,或者调整它们的顺序以应对不同的解决场景,或者自行实现以添加新的解决板块。Provider 和 Consumer 都会经过该解决链,这给用户端治理功可以开发带来了极大的便利性。Apache ServiceComb 的运行结构如下:
图1 Apache ServiceComb 运行时架构
Apache ServiceComb 同时支持同步和异步两种编程接口,并在通信实现上采使用了纯异步方式,对于运行模型的扩展,也是基于异步回调接口的。该方式提供了比同步模式(比方 Filter)更加优雅灵活的扩展方式。
在Apache ServiceComb 结构中,几个核心的扩展机制均在 core 板块 进行定义:
Producer Provider
Provider 编程模型的扩展,通过实现这个接口,能适配不同的 Provider编 程风格;默认支持 RPC、Spring MVC 和 JAX-RS 三种风格。
Consumer Provider
Consumer 编程模型的扩展,通过实现这个接口,能适配不同的 Consumer 编程风格;默认支持 RPC和RestTemplate 两种风格。RestTemplate 是 Spring MVC 提供的 REST 编程接口,能在服务层解除接口依赖,只依赖数据模型。
Handler
解决链的接口,通过扩展该接口,能在解决过程中插入任意的逻辑。默认已经支持负载均衡、错误注入、流量控制和调使用链跟踪等多个解决链。开发者能针对 Consumer 和 Provider 定义不同的解决链,并且为访问不同的微服务定制不同的解决链。
Transport
通信协议扩展,默认支持REST over Vertx、Rest over Servlet、Highway协议。
Invocation
中立的对象。所有的运行模型都面向这个中立的对象进行编程,当定义好服务接口后,对服务的治理和服务业务逻辑的开发可并行进行。在编程模型和通信模型里面,也面向这个对象进行编解码。
对接外部系统
Apache ServiceComb Java-chassis 预留了对接外部系统的接口,以让开发者或者使用户能灵活快速切换用第三方提供的服务,这里所指的外部系统包括但不限于:服务注册发现的服务中心、配置管控和治理的配置中心、运行监控和运维的治理中心等。
下图展现了不同的开发框架支持和运行的第三方系统情况,这些基础服务都给开发者预留了能进行支持接入的接口。
图2 Apache ServiceComb 外部扩展接入
重要的扩展:
ServiceRegistryClient
实现这个接口以对接不同的注册服务。
ConfigCenterConfigurationSource
实现这个接口以对接不同的配置服务。
此外,ServiceComb还提供了对接Zipkin、Servo等开源系统的功可以,这些能从github代码中查找到对应的例子。
运行环境集成
一个完整的业务系统不是用RPC框架就算完成了,它们还需要其余的计算资源。对于一般的业务系统都需要访问数据库,或者者基于 J2EE 的设备进行工作。
开源微服务框架 Apache ServiceComb 能以轻量级的方式运行,也可集成到其余系统框架。下面的示用意说明了 Apache ServiceComb 的少量工作环境。
图3 Apache ServiceComb 运行环境集成
若业务只要 REST 接口,能轻量级的方式运行 Apache ServiceComb 。所有的REST接口运行于ServiceComb 提供的 Netty HTTP 之上。
若业务是基于 J2EE 来构建,那么 Apache ServiceComb 能作为一个 Servlet ,运行于 Web 容器里面(如 Tomcat、Jetty 等)。
若业务基于 Spring Boot 生态构建,Apache ServiceComb 可作为一个starter对外提供 REST 服务,开发者能自由用其余基于 Spring Boot 的功可以。
因为 Apache ServiceComb 用了Spring,因而天然继承了Spring的原有优势,可和很多通使用的组件很好的集成,如 mybatis、JPA 等。各种集成方式,都能从ServiceComb官网或者者ServiceComb 示例库找到对应的例子。
写在最后
开源微服务框架 Apache ServiceComb 的主体代码是由华为云微服务引擎捐赠给 Apache 软件基金会的,愿景是帮助企业快速构建云原生应使用,通过一系列处理方案帮助使用户快速开发微服务应使用的同时实现对这些微服务应使用的高效运维管理。本次设计团队将开放性设计部分细节点点滴滴分享出来也是为了可以够对解放微服务开发者和使用户可以有所帮助。
当前越来越多的贡献者已加入到 社区行列,Apache ServiceComb 会和这些志愿者们一起一如既往坚持这个理念,争取给业界带来更多好的技术和分享。也期望有更多有志者一起行动。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 每日一博|实现 Apache ServiceComb 的开放性设计