在互联网技术突飞猛进的年代,在电商业务风声水起之时,在软件领域的变革悄然而至的“云计算”时代,"云"成了各大传统行业软件开发商和各大电信运行商争论不休的议题。
(特别说明:本文中所述观点,是个人在面向互联网,面向生态,面向急速交付,面向持续演进的实践基础上对业务不确定性和应对业务不确定性设计方式及服务能力沉淀的总结和领悟。非官方性言论,请勿对号入座,个人之愚见,不喜勿喷!)
记得那一年我们是在炮火中度过的,虽然不是在一线,但是快节奏和高压毫不逊于一线的交付局点。据统计那时我们的系统已占据了90%的市场份额。用现在的话说,我们躺着也能赢,但是我们真的能赢吗?那剩下的10%的市场可是最难啃的北美市场,除了苛刻的市场准入要求外,贸易保护政策也是我们无法逾越的鸿沟。
记得那年我们的节奏变得飞快,曾经一年发布一个商用版本变成一年发布两个商用版本到最后一年交付四个商用版本,简直是恐怖得要人老命。人员相继流失,局点需求应接不暇,技术债也是债台高筑,更让人吐血的是代码质量达不到保证,日常维护备尝艰辛,这可是有着十年悠久历史的系统不知经过多少人手,代码腐化严重,if else 多如牛毛,架构就不用说了,最让人无法忍受的是这个系统是异构系统,C++、Java、Phthon等语言,据我师父说这是有1500W+代码的系统,打个包比操作系统还大。
记得那一年我们非常的虚,可不是肾虚的虚,是虚脱的虚。最怕的就是过点了,简直是内心阴暗了,虚脱的要跪但是没办法,咬着牙补丁还是要出的,版本还是要按时GA的,局点需求还是要交付的,反正就是既要又要还要。
前面说了这么多,我无非就是想描述这个泥沼有多深,无奈词穷。我想这是所有软件都会遇到的通病,代码腐化、架构腐化,虽然有小范围的重构可毕竟杯水车薪。这可是全球拥有90%市场份额的系统,市场存量可想而知,到最后我们的开发变成了打补丁。
内忧:代码泥潭,维护成本,补丁发布成为日常,软件架构腐化
外患:公司内部业务兼并,外部行业强敌
交付:局点需求应接不暇
测试:回归迭代成本高昂
矛盾:开发&测试之间的矛盾甚至敌对
方向:前无古人后无来者,走在行业最前沿,没有目标和方向
团队:团队人员流失
政治:不同地域的法律条款积极人文因素
1 局点需求变化多端;
2 业务是否有复用价值;
3 服务能力如何沉淀;
4 软件商业化;
5 SDN(软件定义网络)如何实施;
6 业务能力和流程如何编排;
软件危机总会发生的,也总有应对之道,有战略之道也有战术之道,但此道非彼道总是要另起炉灶。随风潜入夜,润物细无声,电商、云计算、生态、互联网+、微服务、Devops这些前沿的词汇渐渐落到了实践应用中。开发语言从传统的C++走向Java/NodeJs/Python/Go;软件风格从面向过程走向面向对象/面向服务/面向接口/面向微服务;复用力度从函数复用走向功能复用模块化/组件化/平台化/云化。
其实我在那个时候心里对这个系统的演进方式完全没有概念,对于面向互联网,面向生态,面向极速交付,面向持续演进并没有过多深入的思考,也不觉得会解放我们的生产力。那个时候在互联网方面,内部已投入大量的人力财力,甚至有行业内的咨询顾问指导我们在这一块的技术落地。
为什么要服务化解耦,我不说大家也明白。其实,微服务很多人都误解了,我们不是为了服务化而服务化,不是为了最求最新的技术而采用服务化。首先,微服务是为了解决单体应用架构臃肿服务耦合的问题。其次,我们是为了解决团队协作的问题。最后我们是为了解决业务域服务编排和组装的问题。
当时的背景下我们是希望通过采用服务化架构,能够让各服务之间松耦合,可根据业务场景灵活的进行服务编排和组装,让每一个服务都成为底层能力,实现可插拔和业务定制。这样做的好处是微服务都运行在核心的基础框架之上,不同的厂商和局点可以按需定制产品。
在这一块,为了更好的面向生态,对生态提供开放能力,在北向提供了开放的OpenApi接口,供腾讯等云业务上接入。南向提供驱动插件机制,供第三方快速接入,基础服务提供服务化接口供第三方快速开发。
基础数据模型增加租户维度,各服务提供多租户模型,提供多种数据共享方式,提供租户应用供租户自运维。
服务支持多实例,通过扩容实例支持更大的管理容量。
服务多实例负载分担,支持主备和集群保护。
系统架构能灵活根据用户的场景进行组网部署,如单机模式,集群模式。
服务化的改过过程我们经历了三个阶段:
第一个阶段:C++/Java异构架构走向Java,从集中式走向分布式;
第二个阶段:微服务化;
第三个阶段:Pipline的接入/Devops模式的接入;
我们在基于开源的Tomcat基础上对其进行了安全加固,做了定制化开发,我们的系统运行在定制化的Tomcat之上;后来开始往Docker方向演进。
我们对服务路由进行改造,服务路由基于最短路径的原则,服务间有限调用本JVM的服务提供者,其次是同机、同VM、同机房最后是跨网络调用。
同步调用、异步调用、并行调用
线程级别、进程级别、容器级别、VM级别、物理机级别故障隔离,监听和守护。后续在同探索容器化沙箱化等方式。
在做了服务化后我们进一步对不同的业务域做了拆分,我们进入了微服务架构。当我们踏上了微服务这趟列车,数据一致性成为做大的考验。这一块内部在向数据层这一环节开发自己的中间件。这里可能有人有疑问,开原件那么多为什么不用?运营商系统对软件安全性要求非常苛刻,一般我们不使用开源中间件,都是自己造轮子。对于万不得已只能使用开原件,这个就需要层层审批。
我们尝试引入缓存机制
我们使用外部路由和内部路由
借鉴各种一致性方案和一致性算法出了自己的一致性方案。
借鉴阿里的鹰眼和谷歌的论文,造出了自己的轮子。
1 服务独立交付
2 服务并行安装
3 服务并行启动和停止
4 服务原子化的业务单元,完成单一业务职责
5 服务数据库去中心化
6 通过配置方式定制服务能力
7 服务无状态
8 Http会话数据共享
9 数据禁写本地文件系统
开放平台、北向开放API(面向腾讯、阿里、京东)
南向提供驱动插件机制
Devops基础设施,面向组织、面向研发过程、面向集成验证环境、面向运维。
从面相业务的架构向面向生态的架构演进
从微服务向领域模型沉淀
领域能力商业化演进
面向生态开放
在进行一系列的演进之后,我们的产品成为了具有特色的SASS平台。 其分为三个层面对外提供服务,分别是数据面、管理面、运维面。其具备了底层的运行内核,业务基于微服务注册在内核之上。
在演进方面,产品在架构设计上主要的思想是:
产品服务与平台分离的插件化架构: 平台提供服务包注册机制,实现业务方的服务包的注册。业务代码只允许存在于业务域的微服务中,与平台代码严格分离。业务包的代码配置库也与平台的代码库分离,通过二方包的方式,提供给容器加载。(简而言之,平台相当于一个操作系统内核,业务运行在内核之上)
管理面/运维面/数据面视角分离的架构: 管理面/运维面/数据面是基于用户不同的角色,从功能上做了划分。管理面可以对租户内部的账号、功能模块、内部操作权限进行管理;运维面用于支持租户在系统内存、流量、数据库使用情况等方面的运维管理;数据面是租户的业务操作工作台,用于日常的业务定义和下放;
基于服务编排的业务间隔离架构:产品需要能有按运营商需求定制软件包的能力,软件提供商在Devops上选择沉淀后的商业能力(微服务/产品/功能)进行定制化的业务编排。