“不要把所有的鸡蛋都放在一个篮子里”是众所周知的商业法则,很多公司在选择云平台时也遵循这一法则。构建基于多云平台的“业务中台”并不是一件简单的事情。需要构建快速继承、可持续迭代的路径,助力整体解决方案落地。本文以一个实际项目案例为例,分析项目架构设计、实施步骤,以及多云架构面临的挑战和机遇。总体思路不同的云厂商提供不同的云服务,同样的云服务在功能和性能上都会有或多或少的差异。你使用某个云提供商的云服务越深入,就越难迁移到另一个云提供商。如果选择自己搭建云服务,技术门槛高,维护成本高。确定多云架构后,首先需要在技术栈的选择上做出妥协。一个基本原则是通过业务架构的灵活性来适应不同的云厂商,尽可能利用云厂商提供的优秀特性,提高运行在云平台上的业务系统的可靠性,增强企业的竞争力。整体业务。以上思路与部分客户的普遍思路存在明显差异。部分客户选择使用开源软件搭建自己的PaaS平台;有些客户完全使用云厂商的技术栈开发两套业务系统。这两种方法是两个极端。前者开发和运营难度大。往往因为技术风险评估不够充分,导致项目无法如期交付,或者产品竞争力太弱,云厂商提供的服务不如云厂商。后者需要维护两套系统,代码重复率高,将完全被云厂商绑定,失去筹码,降低业务发展的灵活性。一些客户还期望云厂商能够提供足够的兼容框架支持,在不改变现有业务系统逻辑的情况下实现多云部署。由于客户系统的复杂性和多样性,云厂商在这方面的努力通常得不到落实。开发框架选择和架构设计开发框架设计是多云架构的核心,也是最抽象的部分。华为云主推ServiceComb作为微服务框架,阿里云主推HSF和Dubbo作为微服务框架,其他国外云厂商大多选择SpringCloud作为微服务框架,还有其他不同的语言和框架可以选择。虽然mesher等技术为多语言协同工作提供了良好的支持,但为了最大限度地利用框架特性,帮助快速构建稳定可靠的业务系统,选择微服务开发框架仍然必不可少。基于大体思路,多云架构希望在华为云上使用ServiceComb运行时,在阿里云上使用HSF运行时,并支持SpringCloud运行时。要完成这个目标,首先需要了解微服务运行时框架的运行时和主要组件。对于大多数中台系统来说,框架运行时的依赖一般是RPC框架,基于RPC框架的服务治理能力,包括服务注册发现、熔断容错、限流等机制。将业务逻辑的核心代码与微服务框架的能力解耦是设计的第一步。上图展示了基本的逻辑架构。业务核心:在技术选型上使用了Spring和SpringBoot。ServiceComb、HSF、SpringCloud等微服务框架的技术基础都可以基于Spring和SpringBoot技术栈构建。在逻辑架构下,微服务代码需要分层,主要包括以下三个目录:microservice-api:定义了微服务的接口。该目录包含接口定义(interface)和数据结构定义(models)。为了支持不同的微服务框架,对接口定义和数据结构定义都有一定的要求。microservice-service:业务逻辑实现代码。microservice-endpoint-servicecomb:作为ServiceComb发布的微服务项目。microservice-endpoint-hsf:作为HSF发布的微服务项目。microservice-endpoint-springcloud:作为SpringCloud的微服务项目发布。这种代码分层实现的核心关键是API设计,以及业务逻辑实现和服务发布的解耦。API设计需要满足不同微服务框架的设计需求。这就涉及到RPC编解码的基础。RPC编解码器一般分为语言无关(跨平台)和语言相关(不跨平台)。比如HSF和Dubbo默认的codecs都是语言相关的,只能支持JAVA程序之间的通信。ServiceComb默认使用Jackson编解码器或protobuffer编解码器。这两种方法都是基于OpenAPI2.0定义的,并且可以是语言无关的,SpringCloud相对复杂一些。它是一种混合编码格式,可以通过灵活的序列化来定制以满足多样化的需求,也可以严格遵循Jackson和OpenAPI标准。通常,与语言无关的编解码器可以完全包含与语言无关的编解码器要求。因此,在定义API时,需要做到与语言无关,以保证API在不同的微服务开发框架下都能得到最好的实现。由于本文描述的是工程实践,并没有详细讨论跨平台设计的原则,下面列出一些接口设计的指导原则:使用简单的类型(如Integer、String、Boolean等)来定义参数或返回值.或者使用包含简单类型并符合JavaBean规范的POJOBean来定义参数或返回值。尽量不要使用接口、抽象类、具有多个实现的基类、模板类作为参数或返回值。与运行环境强相关的对象不作为接口参数或返回值。比如HttpServletRequest、RpcContext、InvocationContext、ResonseEntity等。以上原理从用户的角度来说是非常容易理解的。界面语义清晰,没有歧义。您可以直接通过接口定义了解接口的参数个数以及如何传递参数,无需提供额外的文档或查看源代码。通过接口定义生成文档和swagger定义是有好处的。在实际项目中,开发者需要了解microservice-api是微服务之间的接口定义,接口设计需要考虑数据的序列化和反序列化。这与内部接口设计不同。为了减少业务实现逻辑的重复,增强内聚性,内部接口设计会使用更多的抽象和继承进行逻辑封装。内部接口的数据结构也会包含一些额外的控制逻辑。例如,数据库访问层的数据结构提供了延迟加载等机制。当访问getter方法时,实际上是调用代理对象的getter方法。因此,需要一些数据结构转换逻辑,将内部数据结构转换成外部接口的数据结构,从而保持服务与内部接口之间的接口清晰,防止内部数据结构被用作参数或返回值,造成内部信息泄露,造成不可预知的处理结果。api示例interfaceLoginService{SessionInfologin(Stringusername,Stringpassword);}publicclassSessionInfo{privateStringsessionId;privateStringusername;}service示例@Service@PrimarypublicclassLoginServiceImplimplementsLoginService{publicSessionInfologin(Stringusername,Stringpassword){//dologin}}ServiceCombEndpointLoginServiceEndpoint”)publicclassLoginServiceEndpointimplementsLoginService{@AutowiredprivateLoginServiceservice;publicSessionInfologin(Stringusername,Stringpassword){returnservice.login(username,password);}}客户端:@BeanpublicLoginServicegetLoginService(){returnInvoker.createProxy(SERVICE_NAME,"LoginServiceEndpoint",LoginService.class);}或者@RpcReference(microserviceName=SERVICE_NAME,schemaId=”LoginServiceEndpoint”)privateLoginServiceloginService;HSFEndpoint示例服务端:@HSFProvider(serviceInterface=LoginService.class,serviceVersion="1.0.0")publicclassLoginServiceEndpointimplementsLog在服务中{@AutowiredprivateLoginService服务;publicSessionInfologin(Stringusername,Stringpassword){returnservice.login(username,password);}}客户端:@HSFConsumerprivateLoginServiceloginService;从上面的代码示例来看,Endpoint层需要在逻辑上尽可能简单,实现所有的逻辑,对于Service层,只包含接口声明,或者包含必要的数据结构转换逻辑。以上方法演示了RPC接口声明。您还可以添加REST标记(SpringMVC或JAXRS)以支持REST接口。遗留系统的重构策略大多数公司的现有系统都运行在某个云上。推翻现有系统并开始新设计通常不是一个好主意。遗留系统的改造需要遵循不断迭代、继承改造的思想。以阿里云系统向华为云系统的改造为例,将原来基于HSF开发的微服务应用,改造为基于ServcieComb开发的微服务应用。按照之前的大体思路,首先需要将原项目中强依赖HSF的代码部分分离出来,建立如下目录结构:microservice-api:定义了微服务的接口。该目录包含接口定义(interface)和数据结构定义(models)。为了支持不同的微服务框架,对接口定义和数据结构定义都有一定的要求。microservice-service:业务逻辑实现代码。microservice-endpoint-hsf:作为HSF发布的微服务项目。这个过程比较简单,不涉及任何业务逻辑的调整,只是代码目录结构的改变和POM依赖的调整。调整完成后,可以对现有功能进行简单的自动化验证,确保项目的自动化测试用例能够通过。调整后的项目功能与遗留系统保持一致,拥有无损运行的系统,对于功能对比和问题发现非常有帮助。项目调整后,可以添加华为云项目:microservice-endpoint-servicecomb:发布为ServiceComb的微服务项目。本项目可以复制microservice-endpoint-hsf,将POM依赖改为ServiceComb的内容,将发布的接口(Endpoint)调整为ServiceComb的发布方式。项目调整后,可以用一段代码构建两个可执行的jar包,两个jar包分别部署在华为云和阿里云上。这个过程的工作量需要通过原始代码本身的复杂度、API接口的标准化程度、代码的大小来评估。如果原有代码结构复杂,api定义不规范,工作量会明显增加。使用组织良好的代码,这个过程会非常容易。实际的改造项目,有的一天就能完成,有的则需要一两个月的时间。获取产品的业务结构、代码量,简单识别现有代码的技术栈和开发方式,有助于有效评估工作量。遗留系统改造的核心工作在于梳理microservice-api中的接口定义。由于HSF不是跨语言开发框架,可能不支持接口定义中使用的数据结构ServiceComb。以支持跨语言的框架的接口定义为基准(一般可以通过IDL、WSDL或OpenAPI描述的接口定义来定义接口,如gRPC、WebService、ServiceComb),其他框架实现这个界面。服务架构适配的核心关键。数据库适配所有业务系统都使用数据库。每个云厂商都支持多种数据库形式,包括MySQL、Postgre、Oracle等,此外还有分布式数据库,分库分表等特性,支持数据仓库。虽然在连接池管理、事务管理、ORM框架等方面有大量的开源开发框架,如dbcp、springtransaction、MyBatis等,但仍然不能覆盖所有的应用场景。适配多云架构对业务代码开发有如下建议:尽量使用符合ANSISQL标准的SQL语句。例如MySQL在case、Columnreference、Limit、Groupbystatement等方面都有自己的特殊用法,为了更好的适配多云数据库,除非对业务价值有明显价值,否则应该避免特殊用法,并且没有等效的解决方案。选择广泛采用的ORM框架。比如MyBatis、JPA等,这些框架的支持很广泛,对多数据库的支持也得到了比较充分的验证。在使用数据库有差异的地方,提供了很好的扩展机制。比如使用MyBatis,可以使用DatabaseProvider接口来屏蔽语法差异。在使用JDBC或者JDBCTempate拼接URL的地方,可以通过接口的不同实现返回不同的SQL语句。
