致传统企业朋友:不够痛就别微服务,有坑 (1)
此文已由作者刘超授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
一、微服务落地是一个复杂问题,牵扯到IT架构,应用架构,组织架构多个方面
在多家传统行业的企业走访和落地了微服务之后,发现落地微服务是一个非常复杂的问题,甚至都不完全是技术问题。
当时想微服务既然是改造应用,做微服务治理,类似注册,发现,熔断,限流,降级等,当然应该从应用开发组切入,一般一开始聊的会比较开心,从单体架构,到SOA,再到微服务架构,从Dubbo聊到SpringCloud,但是必然会涉及到微服务的发布和运维问题,涉及到DevOps和容器层,这些都不在开发组的控制范围内,一旦拉进运维组,对于容器的接受程度就成了一个问题,和传统物理机,虚拟机的差别,会带来什么风险等等等等,尤其是容器绝对不是轻量级的虚拟化这件事情,就不是一时半会儿能说的明白的。更何况就算说明白了,还有线上应用容器,一旦出了事情,谁背锅的问题,容器往往会导致应用层和基础设施层界限模糊,这使得背锅双方都会犹豫不决。
有的企业的微服务化是运维部门发起的,运维部门已经意识到了各种各样不统一的应用给运维带来的苦,也乐意接受容器的运维模式,这就涉及到容器直接的服务发现是否应该运维在容器层搞定,还是应用应该自己搞定的问题,还涉及Dockerfile到底是开发写还是运维写的问题。一旦容器化的过程中,开发不配合,运维单方面去做这个事情,是徒增烦恼却收益有限的。
下图是微服务实施的过程中涉及到的层次,具体的描述参考文章云架构师进阶攻略
在一些相对先进的企业,会在运维组和开发组之间,有个中间件组,或者叫做架构组,来负责推动微服务化改造的事情,架构组就既需要负责劝说业务开发实施微服务化,也要劝说运维组实施容器化,如果架构组的权威性不足,推动往往也会比较困难。
所以微服务,容器,DevOps的推动,不单单是一个技术问题,更是一个组织问题,在推动微服务的过程中,更加能够感觉到康威定律的作用,需要更高层次技术总监或者CIO的介入,方能够推动微服务的落地。
然而到了CIO层,在很多企业又体会不到技术层面的痛点了,而更加关注业务的层面了,只要业务能赚钱,架构的痛,中间件的痛,运维的痛,高层不是非常能够感知,也就体会不到微服务,容器化的技术优势了,而微服务和容器化对于业务的优势,很多厂家在说,能够说到表面,说不到心里。
因而微服务和容器化的改造,更加容易发生在一个扁平化的组织里面,由一个能够体会到基层技术细节的痛的CIO,高瞻远瞩的推动这件事情。这也是为什么微服务的落地一般率先落地在互联网公司,因为互联网公司的组织架构实在太平台,哪怕是高层,也离一线非常的近,了解一线的痛。
然而在传统行业就没有那么幸运了,层级往往会比较多,这个时候就需要技术上的痛足够痛,能够痛到影响业务,能够痛到影响收入,能够痛到被竞争对手甩在后面,才能上达天听。
我们接下来就梳理一下,在这个过程中的那些痛。
二、阶段一:单体架构群,多个开发组,统一运维组
2.1. 阶段一的组织状态
组织状态相对简单。
统一的运维组,管理物理机,物理网络,Vmware虚拟化等资源,同时部署上线由运维部负责。
开发组每个业务都是独立的,负责写代码,不同的业务沟通不多,开发除了做自己的系统外,还需要维护外包公司开发的系统,由于不同的外包公司技术选型差异较大,因而处于烟囱式的架构状态。
传统烟囱式架构如下图所示
2.2. 阶段一的运维模式
在传统架构下,基础设施层往往采取物理机或者虚拟化进行部署,为了不同的应用之间方便相互访问,多采取桥接扁平二层机房网络,也即所有的机器的IP地址都是可以相互访问的,不想互相访问的,多采用防火墙进行隔离。
无论是使用物理机,还是虚拟化,配置是相对复杂的,不是做过多年运维的人员,难以独立的创建一台机器,而且网络规划也需要非常小心,分配给不同业务部门的机器,网段不能冲突。所有这一切,都需要运维部门统一进行管理,一般的IT人员或者开发人员既没有专业性,也不可能给他们权限进行操作,要申请机器怎么办,走个工单,审批一下,过一段时间,机器就能创建出来。
2.3. 阶段一的应用架构
传统架构数据库层,由于外包公司独立开发,或者不同开发部门独立开发,不同业务使用不同的数据库,有用Oracle的,有用SQL Server的,有用Mysql的,有用MongoDB的,各不相同。
传统架构的中间件层,每个团队独立选型中间件:
-
文件:NFS,FTP,Ceph,S3
-
缓存:Redis Cluster,主备,Sentinel, Memcached
-
分布式框架:Spring Cloud,Dubbo,Restful or RPC不同的部门自己选型
-
分库分表:Sharding-jdbc,Mycat
-
消息队列:RabbitMQ, Kafka
-
注册中心:Zk,Euraka,consul
传统架构的服务层,系统或者由外包公司开发,或者由独立团队开发。
传统架构前端,各自开发各自的前端。
2.4. 阶段一有什么问题吗?
其实阶段一没有任何问题,我们甚至能找出一万个理由说明这种模式的好处。
运维部和开放部是天然分开的,谁也不想管对方,两边的老大也是评级的,本相安无事。
机房当然只能运维人员能碰,这里面有安全的问题,专业性的问题,线上系统严肃的问题。如果交给没有那么专业的开发去部署环境,一旦系统由漏洞,谁能担责任,一旦线上系统挂了,又是谁的责任,这个问题问出来,能够让任何争论鸦雀无声。
数据库无论使用Oracle, DB2,还是SQL Server都没有问题,只要公司有足够的预算,而且性能也的确杠杠的,里面存储了大量存储过程,会使得应用开发简单很多,而且有专业的乙方帮忙运维,数据库如此关键,如果替换称为Mysql,一旦抗不出挂了,或者开源的没人维护,线上出了事情,谁来负责?
中间件,服务层,前端,全部由外包商或者乙方搞定,端到端维护,要改什么招手即来,而且每个系统都是完整的一套,部署方便,运维方便。
其实没有任何问题,这个时候上容器或者上微服务,的确自找麻烦。
2.5. 什么情况下才会觉得阶段一有问题?
当然最初的痛点应该在业务层面,当用户的需求开始变的多种多样,业务方时不时的就要上一个新功能,做一个新系统的时候,你会发现外包公司不是能完全搞定所有的事情,他们是瀑布模型的开发,而且开发出来的系统很难变更,至少很难快速变更。
于是你开始想自己招聘一些开发,开发自己能够把控的系统,至少能够将外包公司开发的系统接管过来,这个时候,应对业务部门的需求,就会灵活的多。
但是自己开发和维护就带来了新的问题,多种多样的数据库,根本不可能招聘到如此多样的DBA,人都非常的贵,而且随着系统的增多,这些数据库的lisense也非常的贵。
多种多样的中间件,每个团队独立选型中间件,没有统一的维护,没有统一的知识积累,无法统一保障SLA。一旦使用的消息队列,缓存,框架出了问题,整个团队没有人能够搞定这个事情,因为大家都忙于业务开发,没人有时间深入的去研究这些中间件的背后原理,常见的问题,如何调优等等。
前端框架也有相同的问题,技术栈不一致,界面风格不一致,根本无法自动做UI测试。
当维护了多套系统之后,你会发现,这些系统各个层次都有很多的共同点,很多能力是可以复用的,很多数据是可以打通的。同样一套逻辑,这里也有,那里也有,同样类型的数据,这里一份,那里一份,但是信息是隔离的,数据模型不统一,根本无法打通。
当出现这些问题的时候,才是您考虑进入第二个阶段。
三、阶段二:组织服务化,架构SOA化,基础设施云化
3.1. 阶段二的组织形态
怎么解决上面的问题呢?
根据康威定理,组织方面就需要有一定的调整,整个公司还是分运维组和开发组。
由于痛点是从业务层面发生的,开始调整的应该是开发组。
应该建立独立的前端组,统一前端框架,界面一致,所有人掌握统一的前端开发能力,积累前端代码,在有新的需求的时候,能够快速的进行开发。
建立中间件组,或者架构师组,这部分人不用贴近业务开发,每天的任务就是研究如何使用这些中间件,如何调优,遇到问题如何Debug,形成知识积累。如果有统一的一帮人专注中间件,就可以根据自身的情况,选择有限几个中间件集中研究,限定业务组只使用这些中间件,可保证选型的一致性,如果中间件被这个组统一维护,也可以提供可靠的SLA给业务方。
将业务开发组分出一部分来,建立中台组,将可以复用的能力和代码,交由这几个组开发出服务来,给业务组使用,这样数据模型会统一,业务开发的时候,首先先看看有哪些现成的服务可以使用,不用全部从零开发,也会提高开发效率。
3.2. 阶段二的应用架构
要建立中台,变成服务为其他业务使用,就需要使用SOA架构,将可以复用的组件服务化,注册到服务的注册中心。
对于有钱的企业,可能会采购商用的ESB总线,也有使用Dubbo自己封装称为服务注册中心。
接下来就是要考虑,哪些应该拆出来? 最后考虑的是如何拆出来?
这两个题目的答案,不同的企业不同,其实分为两个阶段,第一个阶段是尝试阶段,也即整个公司对于服务化拆分没有任何经验,当然不敢拿核心业务上手,往往选取一个边角的业务,先拆拆看,这个时候拆本身是重要的,其实是为了拆而拆,拆的比较理想化,符合领域驱动设计的最好,如何拆呢?当然是弄一个两个月,核心员工大家闭门开发,进行拆分和组合,来积累经验。很多企业目前处于这个阶段。
但是其实这个阶段的拆法也只能用来积累经验,因为咱们最初要拆分,是为了快速响应业务请求,而这个边角的模块,往往不是最痛的核心业务。本来业务就边角,拆不拆收益不大,而且也没办法很好的做能力复用。复用当然都想复用核心能力。
所以其实最重要的是第二个阶段,业务真正的服务化的阶段。当然要拿业务需求最多的核心业务逻辑下手,才能起到快速响应业务请求,复用能力的作用。
例如考拉最初也是一个使用Oracle,对外只有一个online业务的单体应用,而真正的拆分,就是围绕核心的下单业务逻辑进行的。
那心业务逻辑中,哪些应该拆出来呢?很多企业会问我们,其实企业自己的开发最清楚。
这个时候经常犯的错误是,先将核心业务逻辑从单体应用中拆分出来。例如将下单逻辑形成下单服务,从online服务中拆分出来。
当然不应该这样,例如两军打仗,当炊事班的烟熏着战士了,是将中军大营搬出去,还是讲炊事班搬出去呢?当然是炊事班了。
另外一点是,能够形成复用的组件,往往不是核心业务逻辑。这个很好理解,两个不同的业务,当然是核心业务逻辑不同(要不就成一种业务了),核心业务逻辑往往是组合逻辑,虽然复杂,但是往往不具备复用性,就算是下单,不同的电商也是不一样的,这家推出了什么什么豆,那家推出了什么什么券,另一家有个什么什么活动,都是核心业务逻辑的不同,会经常变。能够复用的,往往是用户中心,支付中心,仓储中心,库存中心等等核心业务的周边逻辑。
所以拆分,应该将这些核心业务的周边逻辑,从核心业务里面拆出来,最终Online就剩下下单的核心路径了,就可以改成下单服务了。当业务方突然有了需求推出一个抢购活动,就可以复用刚才的周边逻辑了。抢购就成了另一个应用的核心逻辑,其实核心逻辑是传真引线的,周边逻辑是保存数据,提供原子化接口的。
那哪些周边逻辑应该先拆出来呢?问自己的开发吧,那些战战兢兢,自己修改后生怕把核心逻辑搞挂了的组,是自己有动力从核心逻辑中拆分出来的,这个不需要技术总监和架构师去督促,他们有自己的原有动力,是一个很自然的过程。
这里的原有动力,一个是开发独立,一个是上线独立,就像考拉的online系统里面,仓库组就想自己独立出去,因为他们要对接各种各样的仓储系统,全球这么多的仓库,系统都很传统,接口不一样,没新对接一个,开发的时候,都担心把下单核心逻辑搞挂了,造成线上事故,其实仓储系统可以定义自己的重试和容灾机制,没有下单那么严重。物流组也想独立出去,因为对接的物流公司太多了,也要经常上线,也不想把下单搞挂。
您也可以梳理一下贵公司的业务逻辑,也会有自行愿意拆分的业务,形成中台服务。
当周边的逻辑拆分之后,一些核心的逻辑,互相怕影响,也可以拆分出去,例如下单和支付,支付对接多个支付方的时候,也不想影响下单,也可以独立出去。
然后我们再看,如何拆分的问题?
关于拆分的前提,时机,方法,规范等,参考文章微服务化之服务拆分与服务发现
首先要做的,就是原有工程代码的标准化,我们常称为“任何人接手任何一个模块都能看到熟悉的面孔”
例如打开一个java工程,应该有以下的package:
-
API接口包:所有的接口定义都在这里,对于内部的调用,也要实现接口,这样一旦要拆分出去,对于本地的接口调用,就可以变为远程的接口调用
-
访问外部服务包:如果这个进程要访问其他进程,对于外部访问的封装都在这里,对于单元测试来讲,对于这部分的Mock,可以使得不用依赖第三方,就能进行功能测试。对于服务拆分,调用其他的服务,也是在这里。
-
数据库DTO:如果要访问数据库,在这里定义原子的数据结构
-
访问数据库包:访问数据库的逻辑全部在这个包里面
-
服务与商务逻辑:这里实现主要的商业逻辑,拆分也是从这里拆分出来。
-
外部服务:对外提供服务的逻辑在这里,对于接口的提供方,要实现在这里。
另外是测试文件夹,每个类都应该有单元测试,要审核单元测试覆盖率,模块内部应该通过Mock的方法实现集成测试。
接下来是配置文件夹,配置profile,配置分为几类:
-
内部配置项(启动后不变,改变需要重启)
-
集中配置项(配置中心,可动态下发)
-
外部配置项(外部依赖,和环境相关)
当一个工程的结构非常标准化之后,接下来在原有服务中,先独立功能模块 ,规范输入输出,形成服务内部的分离。在分离出新的进程之前,先分离出新的jar,只要能够分离出新的jar,基本也就实现了松耦合。
接下来,应该新建工程,新启动一个进程,尽早的注册到注册中心,开始提供服务,这个时候,新的工程中的代码逻辑可以先没有,只是转调用原来的进程接口。
为什么要越早独立越好呢?哪怕还没实现逻辑先独立呢?因为服务拆分的过程是渐进的,伴随着新功能的开发,新需求的引入,这个时候,对于原来的接口,也会有新的需求进行修改,如果你想把业务逻辑独立出来,独立了一半,新需求来了,改旧的,改新的都不合适,新的还没独立提供服务,旧的如果改了,会造成从旧工程迁移到新工程,边迁移边改变,合并更加困难。如果尽早独立,所有的新需求都进入新的工程,所有调用方更新的时候,都改为调用新的进程,对于老进程的调用会越来越少,最终新进程将老进程全部代理。
接下来就可以将老工程中的逻辑逐渐迁移到新工程,由于代码迁移不能保证逻辑的完全正确,因而需要持续集成,灰度发布,微服务框架能够在新老接口之间切换。
最终当新工程稳定运行,并且在调用监控中,已经没有对于老工程的调用的时候,就可以将老工程下线了。
3.3. 阶段二的运维模式
经过业务层的的服务化,也对运维组造成了压力。
应用逐渐拆分,服务数量增多。
在服务拆分的最佳实践中,有一条就是,拆分过程需要进行持续集成,保证功能一致。
而持续集成的流程,往往需要频繁的部署测试环境。
随着服务的拆分,不同的业务开发组会接到不同的需求,并行开发功能增多,发布频繁,会造成测试环境,生产环境更加频繁的部署。
而频繁的部署,就需要频繁创建和删除虚拟机。
如果还是采用上面审批的模式,运维部就会成为瓶颈,要不就是影响开发进度,要不就是被各种部署累死。
这就需要进行运维模式的改变,也即基础设施层云化。
虚拟化到云化有什么不一样呢?
首先要有良好的租户管理,从运维集中管理到租户自助使用模式的转换。
也即人工创建,人工调度,人工配置的集中管理模式已经成为瓶颈,应该变为租户自助的管理,机器自动的调度,自动的配置。
其次,要实现基于Quota和QoS的资源控制。
也即对于租户创建的资源的控制,不用精细化到运维手动管理一切,只要给这个客户分配了租户,分配了Quota,设置了Qos,租户就可以在运维限定的范围内,自由随意的创建,使用,删除虚拟机,无需通知运维,这样迭代速度就会加快。
再次,要实现基于虚拟网络,VPC,SDN的网络规划。
原来的网络使用的都是物理网络,问题在于物理网络是所有部门共享的,没办法交给一个业务部门自由的配置和使用。因而要有VPC虚拟网络的概念,每个租户可以随意配置自己的子网,路由表,和外网的连接等,不同的租户的网段可以冲突,互不影响,租户可以根据自己的需要,随意的在界面上,用软件的方式做网络规划。
除了基础设施云化之外,运维部门还应该将应用的部署自动化。
因为如果云计算不管应用,一旦出现扩容,或者自动部署的需求,云平台创建出来的虚拟机还是空的,需要运维手动上去部署,根本忙不过来。因而云平台,也一定要管理应用。
云计算如何管理应用呢?我们将应用分成两种,一种称为通用的应用,一般指一些复杂性比较高,但大家都在用的,例如数据库。几乎所有的应用都会用数据库,但数据库软件是标准的,虽然安装和维护比较复杂,但无论谁安装都是一样。这样的应用可以变成标准的PaaS层的应用放在云平台的界面上。当用户需要一个数据库时,一点就出来了,用户就可以直接用了。
所以对于运维模式的第二个改变是,通用软件PaaS化。
前面说过了,在开发部门有中间件组负责这些通用的应用,运维也自动部署这些应用,两个组的界限是什么样的呢?
一般的实践方式是,云平台的PaaS负责创建的中间件的稳定,保证SLA,当出现问题的时候,会自动修复。
而开发部门的中间件组,主要研究如何正确的使用这些PaaS,配置什么样的参数,使用的正确姿势等等,这个和业务相关。
除了通用的应用,还有个性化的应用,应该通过脚本进行部署,例如工具Puppet, Chef, Ansible, SaltStack等。
这里有一个实践是,不建议使用裸机部署,因为这样部署非常的慢,推荐基于虚拟机镜像的自动部署。在云平台上,任何虚拟机的创建都是基于镜像的,我们可以在镜像里面,将要部署的环境大部分部署好,只需要做少量的定制化,这些由部署工具完成。
下图是OpenStack基于Heat的虚拟机编排,除了调用OpenStack API基于镜像创建虚拟机之外,还要调用SaltStack的master,将定制化的指令下发给虚拟机里面的agent。
基于虚拟机镜像和脚本下发,可以构建自动化部署平台NDP
这样可以基于虚拟机镜像,做完整的应用的部署和上线,称为编排。基于编排,就可以进行很好的持续集成,例如每天晚上,自动部署一套环境,进行回归测试,从而保证修改的正确性。
进行完第二阶段之后,整个状态如上图所示。
这里运维部门的职能有了一定的改变,除了最基本的资源创建,还要提供自助的操作平台,PaaS化的中间件,基于镜像和脚本的自动部署。
开发部门的职能也有了一定的改变,拆分称为前端组,业务开发组,中台组,中间件组,其中中间件组合运维部门的联系最紧密。
网易云计算基础服务深度整合了 IaaS、PaaS 及容器技术,提供弹性计算、DevOps 工具链及微服务基础设施等服务,帮助企业解决 IT、架构及运维等问题,使企业更聚焦于业务,是新一代的云计算平台,点击可免费试用。
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 git 常用命令
【推荐】 应对羊毛党的老手段不管用了,但有些公司依然有办法,他们是怎么做的?