本文主要尝试回答两个问题:
- 客户运行在其他云平台(比如阿里云)的应用系统,如何搬迁到华为云,如何评估搬迁的可行性和工作量,具体方案是什么以及有什么优缺点。
- 针对客户担心的“如何避免被云厂商”绑定的顾虑,客户应该如何选择更好的技术架构来应对。
回答这两个问题并不容易,在考虑“云原生”、“微服务”等新概念的时候,不仅仅是一个技术导向的问题,还涉及到业务、组织和管理等方面的调整。本文会把问题缩小到技术方面。进行遗留系统改造,也可以借鉴多云架构落地方案,循序渐进的进行。
1 第一部分:平台和中间件迁移
假设客户的应用系统的部署模式如下:
这个部署图显示了客户应用对于平台的依赖关系。在不改变客户应用的情况下,首先需要搜集客户对于平台的依赖组件。一般的,如果华为云提供了对应的功能,那么迁移华为云就是可行的,迁移的工作量需要根据实际依赖情况和具体依赖的组件细化分析,下面针对不同的情况做一个简单的分解。
·对于开发/运维平台的依赖。这部分依赖一般都是和应用无关的,可以在不修改任何业务逻辑的情况下使用。但是需要注意,不同的云厂商,提供的能力集合都不一样,界面的操作体验也不一样。从一个云厂商,迁移到另外一个云厂商,需要考虑运维方式的变化给客户运维人员带来的影响。
·对于中间件的依赖。这部分依赖和应用开发强相关,应用需要选择合适的客户端程序/组件和中间件进行交互。有些中间件是业界标准,比如关系数据库,都可以通过JDBC驱动进行访问,这些标准中间件的迁移,一般用户不需要修改自己的应用。还有些中间件不是业界标准,比如对象存储,不同的云厂商提供的客户端接口不一样,客户需要修改自己的应用,适配不同的云厂商。对于中间件依赖改造的工作量,很大程度取决于客户应用在开发设计的时候,是否采用了合理的设计模式来屏蔽中间件的差异,良好设计的系统,通常只需要开发新的适配器,整体的改造工作量是可控的。
·对于领域应用的依赖。这块的功能业界普遍没有标准化,不同的云厂商,这些功能都可以通过能力开放的方式进行外部访问。即华为云也可以访问阿里云的功能,或者一个功能有多种可能的提供商,比如支付服务,阿里云、腾讯云、华为云都能够提供,用户可以选择一家提供商。和非标准化中间件一样,切换新的提供商,需要开发新的适配器,来使用新的供应商能力。
·底层的虚机、容器,以及IaaS层的网络、计算、存储,目前业界普遍的标准化了,在不同的云厂商迁移相对简单,通常不需要客户应用做出改变。但是有些特殊的场景,还是需要考虑对应的厂商是否提供了相应的技术支持,比如用于大型游戏需要的专门的图像处理器。不同厂商在基础设施在可靠性、性能方面的差异,也应该作为业务考虑的因素。
从上面的分析可以看出,如果客户担心被云厂商绑定,那么在进行技术选型的时候,需要考虑如下因素:
·选择提供标准接口的中间件服务。比如使用支持JDBC的关系型数据库、使用支持开放标准JMS的消息服务等。或者在开发代码的时候,对中间件访问的接口设计合适的适配器模式,用户针对不同云厂商开发不一样的适配接口。
·考虑所选择功能在市面上的可获得性,尽可能不要使用云厂商独有的功能。从业务的角度来讲,可以选择云厂商的独有特性,以提高产品竞争力。可获得性可以保证当供应商不能继续提供独有功能的时候,业务发展的持续性。
从上面的分析也可以看出,客户在追求“尽可能减少与云厂商绑定”与“使用最具竞争力的特性和减少工作量”这两方面的要求是存在矛盾的。一般的,使用云厂商的独特特性,可以减少客户开发工作量和使用最新最具竞争力的特性,同时增强了和云厂商的绑定关系,难以迁移到其他云厂商。对应的,客户自行实现业务需要的中间件和领域服务,减少对应平台中间件和领域服务的依赖,那么客户的应用越容易在不同的云厂商之间迁移,同时意味着客户的开发工作量和技术难度更高。
无论如何,客户的系统进行良好设计,为差异化预留接口,并对关键技术做好备份选型,能够让客户的应用系统具备更灵活的迁移空间。
2 第二部分:微服务开发框架迁移
接下来需要深入客户的应用,探讨应用迁移和改造问题,分析开发框架迁移的工作量和绑定关系。这个方面的迁移相对于平台层服务的迁移,更加难于评估和困难,通常需要和开发者进行比较深入的交流。同样的,我们可以把问题缩小到技术框架的迁移这样一个问题上,比如将Dubbo改造为CSE框架、Spring Boot改造为CSE框架等。
2.1 是否需要迁移
评估迁移工作量和可行性之前,先要回答是否要迁移的问题,迁移到哪个框架的问题。
迁移到哪儿?
·微服务开发框架的开放程度。首先看微服务开发框架是否有对应的开源版本。采用开源版本一方面可以从社区学习,还可以通过阅读源代码掌握细节,能够更容易进行灵活定制以适配未来的需要。然后看微服务开发框架是否是技术封闭的,能否在这个框架中轻松的集成其他开源开发组件,比如常见的数据库访问组件mybatic, hibernate, spring data等,比如是否可以使用Spring功能,是否可以使用Spring Boot、Web技术等。最后看微服务开发框架对于业界流行标准的支持,比如微服务流行使用REST通信,那么是否支持HTTP/HTTP2,是否支持JAX-RS、Spring MVC等流行的REST接口开发规则,是否支持使用RPC的方式访问REST接口等。
·微服务“云原生”方面的支持。从微服务的角度理解“云原生”,本质上就是要回答使用该微服务框架以后,是否能够专注于业务代码开发,而不需要考虑“微服务化”以后带来的各种问题,比如多实例时候的服务发现、负载均衡,微服务实例出现故障的时候的隔离和重试、微服务故障定界(通过调用链)和定位(比如超时)等微服务运维问题。很多微服务框架只是提供了“如何解决这些问题” 的功能模块和工具,但并没有帮用户解决这些问题。因为在规划自己的应用系统的时候,用户不知道这些问题是什么,在业务上线运行的时候,才慢慢浮出水面,用户自行解决这些问题的时候成本通常是非常高的。
为什么迁移?
迁移到哪儿部分回答了为什么迁移,但这些指标仍然不能作为迁移的根据。为什么迁移还是要回到最初的商业目标上来,比如现有框架的使用成本和问题,未来业务的发展是否需要选择更加合适的技术(比如是否需要选择容器和微服务来满足快速交付和用户增长带来的挑战)等等。
2.2 工作量和可行性评估
业务需要将一个开发框架换成另外一个开发框架的时候,通常期望保留现有业务处理逻辑,丢弃框架的运行时。最理想的情况,是业务逻辑代码原封不动,不做任何修改,平滑的将运行时切换过来,比如将业务代码的war包,从Tomcat容器切换到Jetty容器。
以war应用为例,可以看看war应用和容器之间的依赖关系:
采用一个框架,必然存在和框架功能有交互的地方,在这里的主要内容就是服务发布部分。由于Tomcat容器和Jetty容器服务发布都支持相关的协议和规范,因此业务代码可以完全平滑的进行迁移。
对于其他业务代码部分,比如处理流程、数据访问等,需要考虑目标系统是否支持运行这些组件,如果支持,那么这些代码不涉及修改,可以平滑迁移。
如果业务代码使用了对应容器提供的工具API,那么像Tomcat容器迁移到Jetty容器的场景,也可能需要代码改动,业务切换变得不平滑。
当出现目标框架不支持运行依赖的组件,或者服务发布方式没有对等的功能、或者工具API没有对等的API支持的时候,这种切换就会变得不可行。当然实际在选型分析的时候,非常难把握一些细节的不支持情况,不过倒不用悲观,实现一个业务逻辑的方式是有多种可能性的,换一种实现思路去调整实现逻辑,也能够解决单纯从技术上看,无法对等改造的问题。
2.2.1 工作量评估
从上面以war应用在不同运行容器之间的改造可以看出,一个框架改造为另外一个框架的工作量可以从两个维度进行评估:
1. 改造前的业务代码依赖于原来框架/运行时的程度。
2. 目标框架本身对于业务代码采用的技术的支持程度。
再看一下上面例子中,CSE框架的情况。
可以看到,和war应用对比,除了运行时的变化,服务发布的方式变化了,提供的工具API也变化了。 将war应用切换为CSE的工作量主要包含两部分:
1. 将服务发布方式修改为CSE的服务发布方式,即将Servlet定义修改为Spring MVC或者JAX RS或者RPC的方式。
2. 调用工具API的地方,需要分析CSE SDK是否有对等的替换方案,使用CSE SDK提供的API进行修改。
下面表格结合上面的分析,简单的评估了一下各个框架切换CSE的难度对比。这个难易程度只是近似的评估,主要考察可能的改动点多少。工作量的评估的一个很重要要素是原来业务系统本身在处理平台依赖上的成熟度(依赖的多少和程度),这个工作量不再这里评估,尽管这个可能是导致工作量最重要的因素。
上表的难易程度只是近似的估算,没有对应的数据支撑,侧重于服务发布方式之间进行调整适配的工作量,更细粒度来讲,就是数据类型支持方面改造的工作量,仅供参考。正如上面分析的,业务改造的工作量更多的来源于原来业务系统本身的耦合程度。
2.3 对开发者的建议
在上面的难易度评估矩阵中,有一个协议gRPC需要特别提到一下。在所有的框架中,将代码切换到gRPC,都是最难的,但是将gRPC切换为其他框架,都是最容易的。一般的,如果一个框架满足如下特征:
1. 更加贴近业务代码的书写形式,比如采用RPC的方式对外发布服务;
2. 更多的跨语言方面约束;
3. 更少的平台API
那么其他框架改造为这个框架会更加难,但是这个框架改造为其他框架更加容易。因为1,在切换为其他框架的时候,只需要将接口以其他框架的形式包装一次,不涉及任何代码修改;因为2,可以适配更多的接口约束和更多的序列化方式,支持的框架更多;因为3,不涉及平台API的整改和对等切换。
很多业务都会考虑对于平台绑定的问题,特别是那种需要长期发展的业务。因为平台技术日新月异,变化的场景驱动业务采用更加先进的架构技术改善业务的运行状况,比如JAVA技术的从Osgi到J2EE到WEB到微服务架构。那么业务如何去适应这个变化了?上面3个特性实际上给了一个指引。另外就是还需要加上:
4. 尽可能符合标准协议的约束。
这条规则和构造WEB应用时该选用那些功能一样的。在书写HTML的时候,尽可能的遵循HTML4、HTML5规范,能够让网站在更多的浏览器上精彩的呈现。
更好演进的另外一个方面,就是把使用的技术限制在能够跨平台的范围内。这块无疑会增加开发者的成本,需要学习更多的规范和培养更好的编码技能。有些业务场景,还必须使用平台特性去解决。这些复杂性都不会让我们的代码完美,总是在一个权衡和妥协中发展。
下面提供了一个代码设计方面的模式,这种模式解决了发布形式的切换问题。业务代码按照这样的模式进行组织,并且在接口定义上尽可能考虑跨语言数据结构(主要指数据类型),那么这种业务代码在配套平台升级的时候,将会是最快速的。
逻辑结构:
代码示例:
在CSE给的[项目例子中]( https://github.com/apache/servicecomb-samples/tree/master/porter_lightweight), 采用Spring进行了接口和实现分离的代码结构,这种代码结构实现的代码,迁移到CSE、Dubbo、Spring Cloud、gRPC等框架的时候,只需要修改Endpoint层的定义,而不需要修改任何实现逻辑。因此建议开发者按照这种代码风格组织代码,从而更加方便的切换框架。但是开发者需要注意,历史遗留系统很多不是按照这个方式组织代码的,那么历史遗留代码的重构的工作量,很大程度上决定了改造的工作量。
5. 尽可能选择开源的微服务开发SDK。
选择开源的SDK的好处是即使商业公司不提供SDK的开发支持,或者成本很高的时候,可以通过开源社区或者自行编译源码,去适配其他的中间件,从而让业务能够在不同的技术组合下运行起来。
2.4 总结
结合上面的观点,所有框架不会在各种方面都是完美的,CSE SDK在灵活性方面的折中做得非常的出色,CSE的SDK也通过ServiceComb项目进行了开源,并且代码是同源的。CSE通过提供业务代码的书写习惯支持大大减少了切换为CSE的工作量,同时后续如果将CSE迁移到其他框架,相对来讲也是非常容易的。可以通过ServiceComb的开放性设计,了解CSE SDK的设计思路。同时客户也应该认识到,应用系统进行良好的抽象设计,能够更好的适配不同的平台和开发框架,客户应该在平台能够提供的价值服务和绑定关系方面做出权衡取舍,以最优的方式选择适当的平台服务。单纯从技术上来讲,平台绑定的担忧很多时候是应用系统本身架构和代码质量的一个侧面反映。
作者:liubao68