2016 年,容器化技术如火如荼,诞生于 2013 年的 Docker 成了行业的宠儿,它让炒了 8 年的 DevOps 有了更具体可落地可执行的工具。虽然有一定程度的过火现象(所谓的 hype),虽然有很多 IT 人(尤其是在传统垂直行业的信息技术部里)依然怀疑容器与虚拟机的差别,但总体来说,容器化可能算的上是软件开发领域的又一次“运动”。
每一次“运动”,都是有很多人追随、有很多技术架构被(一窝蜂的)重新设计、有很多系统被迁移,形成一种潮流(好像不那么干就被时代抛弃),代码的开发调试、架构设计和交付部署的方式发生巨大变化:
- Mainframe:大型机、大集中、傻终端(dumb Terminal)。
- 2 层架构 Client-server 和 4GL:整个 90 年代 - 中小型机 /x86 服务器、工作站 /PC 终端。Mainframe 应用很多被采用 C/S 架构重写。一时间都是 DCE RPC、DCOM、CORBA-IIOP。
- 3 层架构通行:Web 1.0 时代开始到现在,浏览器、中间件、关系型数据库服务器的架构依然在很多企业中通行。C/S 架构应用很多被迁移至三层架构。Struts+Spring+Hibernate(传说中的 SSH)成为这一时代的 web 应用标配,JEE 应用服务器曾经是“State of the art” 的技术,甚至成就了上市公司(例如 WebLogic)。
- SOA + RIA:SOA 最开始是互联网技术(例如 HTTP、XML 等等)生态回归企业 IT,新的技术载体实现企业应用所需要的 RPC 语义、服务注册与发现机制,再结合 Flash、AJAX 技术实现的富客户端(Rich Client),实现企业类应用所需要的、比一般网站类应用交互复杂的交互。
- 在 CAP 定律制约下的分布式架构:Web 2.0 时代产物,participation age 的社交网络、UGC,海量数据海量流量促成。
- 容器化的分布式架构:为什么这算的上一次里程碑式的运动?因为它可能导致 ISV 的软件产品(例如 MongoDB、Redis 等)被容器化、导致行业解决方案容器化(例如交易系统)、甚至导致操作系统容器化(例如 RancherOS 和其他“极简主义”下支持运行容器服务的操作系统),它促进 DevOps 工具链的发展,它和 CI/CD 深度整合,它直接影响开发人员的思考方式。
- Serverless 架构:类似 Amazon lambda、Google Compute Engine 等,对于应用开发者而言交付方式部署方式都是有变化的,能否称的上“运动”,有待商榷,姑妄列出。
- 未知的运动与变革:技术的进步与变化,是加速度的,并且这个加速度本身的变化,也是指数级的,这是“奇点临近”作者库兹威尔(Kurzweil)的观点。总之,新的变革一定会来,快到你还没学会容器,新技术的“飞饼”已经摔到脸上。
其实,“软件开发”这个世界,依稀也是遵循“合久必分”(Divide-and-conquer)、“分久必合”(Combine-and-conquer)的规律的,例如:
- 从 Mainframe 向 Client-Server 到 Web/3-tiered 架构的发展,可以算是一个分层分治的过程
- Client-Server 架构下的系统一多,造成服务器端资源的浪费,然后以 IBM、Sun、HP 为首的厂商,在本世纪初开始推销所谓 Server Consolidation 的解决方案。随着虚拟化技术的成熟,物理服务器逐渐变成虚拟服务器,世界又回归一个逻辑上分布、物理上集中的“超级 Mainframe”
- 有些技术,往往是“似曾相识”,是新技术世代下用新技术手段对旧的理念的回归。例如 SOA 架构 +RIA,是对 C/S 架构某种程度上的回归、虽然技术载体大不一样。同理,Micro Services 也体现 SOA 的理念(虽然两者是巨大的不一样,见后文)
(点击放大图像)
容器化,也许算的上近年来最重要的“运动“,很快成为一种潮流 - 无论有无必要,开发工程师的代码都以容器交付,否则就像 Web 1.0 时代还在开发 Client-Server 甚至 Mainframe 的应用都不好意思出去跟人说。这潮流里,有厂商的有目的性推波助澜,有一窝蜂的赶潮流,也有切实的业务场景驱动,无论如何,容器化将(1)常态化 - 尤其是当 ISV 也把它们的产品容器化后;(2)促进分布式架构在传统企业 IT 里的采用(此前,大部分垂直行业 IT 并不擅长互联网企业所擅长的分布式架构,现在只要接受了容器的概念,显然就走向分布式);(3)促进已经讲了 8 年以上的 DevOps 落地可操作。
说到传统企业 IT 的技术架构,就不得不提一下“去 IOE”,因为尤其在金融机构,IOE 是无可辩驳的存在。
容器化也许帮助你“去 IOE”
乍一听,这标题有点哗众取宠。但仔细想想,其实还真可以拉扯点关系。
首先, “去 IOE” 本身是一个伪命题。企业 IT 降低对一些外国厂商和商业技术的依赖,固然从节省成本上有那么些好处,但如果不上升到 “民族产业”、“信息安全”的层面,减少几个数据库软件的 license 对于企业本身的效益是有限的,其伤筋动骨的技术迁移也许是得不偿失的。去了 IOE,也没什么值得自豪 - 别高估了自己在国家信息安全方面的重要性,如果没有为业务经营、客户利益带来价值,恐怕只能是“然并卵”。
如果我们不带偏见的把 IOE 看成一些象征性的符号而不是具体的某些公司的话,IOE 一定程度上代表了上一个世代的技术,对于只生存在开源技术世界里的互联网企业的年轻工程师尤其如此。IOE 甚至在一定程度上是 Client-Server 架构思潮下的产物,代表了以关系型数据库为中心、以中央存储阵列为主导、以品牌服务器硬件为载体的技术架构风格,这类技术的存在依然有充分必要的业务应用场景,盲目的“去”,只能是自找麻烦和浪费资源。
但换一个角度看,“去 IOE 思维”却又是有意义的,因为在实践中我们已经发现:
- 关系型数据库被企业里的应用开发者们过度滥用。事无大小,都被存入数据库,包括一些配置信息。事务型操作往往也没有控制好粒度,开发者为了“稳妥”起见囫囵吞枣的把 CRUD 操作都丢到事务里,期望由数据库来解决自己的不求甚解和懒惰
- 很多问题,其实是可以不用关系型数据库解决的
- 互联网时代尤其是 Web 2.0 开启后,从 3-tiered 向分布式架构演进,RDBMS 为中心、高端硬件为依托的架构已经力不从心
- 就算不搞互联网,传统业务系统在当今这个时代沿用旧的技术架构依然扛不住,2015 年疯狂的股市下,高频、高并发、海量的交易就是股票交易系统的梦魇
“去 IOE”其实最难的是观念的改变,传统企业 IT 的工程师,非常习惯于用关系型数据库的语义、概念作为对业务领域(business domain)的建模工具,一言不合就开始设计表结构、画 ER(Entity Relationship)图。开发过程中,可能大部分时间消耗在 ORM(Object-Relationsal Mapping)上 - 从数据模型出发封装一些对象以便于数据持久层和内存之间关联起来。这导致传统 IT 系统的升级动辄涉及数据库迁移,功能扩展通常导致表结构改变。实际上用关系型数据库的理念对世界进行建模(modeling),是有很多局限性的,一是无法对业务逻辑进行抽象,二是无法对业务数据进行封装。这样做的缺点,是所建立的模型无法低成本扩展、重构,以快速应对持续变化的业务场景,在当今这个“只有变化才是唯一的不变”并且变化频率本身是指数级改变(《奇点临近》作者 Ray Kurzweil 所言)的世界,这样的设计导致的显然是一个变更成本非常高的“脆弱系统”,无法拥抱改变应对黑天鹅(关于脆弱系统,见塔勒布《反脆弱》)。
“世界观决定方法论”,中医和西医对人体的建模差别,决定治病的方法截然不同。例如前者用经络、寒热、干湿、虚实、阴阳来描述病理,后者用细胞、基因、细菌、病毒来看待问题,导致同一个疾病的不同处理手段。有些问题用这种模型来看容易解决,有些问题则用另一种模型描述更有效。盲目的用关系型数据库看待一切,是很多问题的根源。
以关系型数据库为中心的应用,一般都是单体应用(monolithic),虽然它们可能也会融合一些分布式的技术元素,扩容、扩展、弹性伸缩、响应变更等等这些非功能性需求,依然是它们所难以满足的。在看到这类架构的问题后,技术界开始出现混合编程(polyglot programming)、混合存储(polyglot persistence)和混合处理(polyglot processing - 例如大数据里的 zeta 架构)的潮流,微服务(Micro Services)的架构风格与理念也逐渐形成。
微服务具体实施的问题在于,停留在“理念”、“最佳实践”层面的东西,很难在一般垂直行业的 IT 落地,因为面向业务的工程师们,关注点不在底层技术细节,无法投入资源去研究自己的平台,凡是能在垂直行业推广的技术,必须是具体有形的工具、API、框架。容器类技术作为看得见摸得着的、同时被运维人员和开发人员使用的工具链,对微服务的开发和运维,提供了无比巨大的推动力。虽然微服务本质上不依赖于容器,但是没有容器技术的支持,微服务在一般企业 IT 里的落地是不乐观的。
这就产生一个非常有趣的副作用 - 一旦技术人员习惯了容器化的观念,他们很可能不知不觉就走上了分布式架构的道路、潜移默化接受了微服务的思维,我们知道技术人员是很容易“心为物役”的,他们的抽象思考往往需要寄托在有型的工具上。例如 Heroku 的 12-Factors(12 律),总结了 12 项在云上开发分布式应用的最佳实践,我们可以看到,采用容器化的架构,很自然的就吻合这些实践。
总而言之,“去 IOE”从它最开始的起源来看其实是去单体应用架构、去“数据库中心主义”,是分布式架构对传统企业技术套路的颠覆,而容器化一旦成为主流,分布式架构即会潜移默化不知不觉中成为企业 IT 架构的主流。
但不要把微服务和容器化本末倒置
容器化既然被说的这么玄乎,那么是不是我们就该蜂拥而去的采用?个人认为,如果阁下的企业环境,并无特别适合 “微服务化” 的应用,那么个人揣测,阁下也并无采用容器技术的必要,即便是已经采用了 SOA 的技术架构与技术治理,千万别以为就顺理成章可以换一个时髦点的名字“微服务”。
SOA 与微服务,其实有一些本质区别,哪怕是表面上有一些相似性 - 例如都叫“服务”(技术名词有时确实导致巨大的歧义)、都有服务注册与发现机制、甚至具体实施技术有一定重叠。在此列出一些区别(有商榷处,姑妄列出供讨论):
- 从根本思想看,SOA 是强调中央治理(central governance)的,服务之间大致松耦合但实践中其实有一定耦合,例如 shared storage 是常见的 - 同一个数据库上封装几个服务,避免数据直接暴露到外面,可后面依然是一个数据库;事实上当用到“治理”(governance)这样的字眼,本身就充满了中心化的意味。微服务则以去中心化为原则,强调 share nothing、服务间高度松耦合,数据持久层被抽象为 backing store - 甚至不需要是关系型数据库,每个服务各有自己的 backing store
- 总体架构设计,SOA 是一个 top-down 思维 - “顶层设计”,从业务切分模块,把模块之间关联变成封装服务之间的调用、集成。微服务是一个自下而上的 bottom-up 的思维,服务的粒度更小(否则何为“微”服务?),对服务本身上下文的假设更少,最重要一点,微服务通常是从当前服务的上下文衍生出来的
- 组织结构上看,SOA 类型的项目团队,模块负责团队隶属于一个更大项目之下,实际中几乎不会独立运营运维。微服务,粒度小,强调单一责任,独立部署运维、自有生命周期。某种角度看,不同 SOA 项目之间是不同的 Silo 型团队负责的,而微服务严格来说一个服务对应一个跨职能团队
- 从关注点看,SOA 强调的是 SLA、compliance/regulation(合规)、audit(审计)等大型企业特色的“治理”,微服务关注点从来都是快速响应客户要求和市场变化以及快速创新,是敏捷型的。(所以微服务并不替代 SOA)
- 从部署运维角度看,SOA 出现于云计算之前,自动化部署、自动化运维并不是它的天然基因。微服务几乎可以说是云计算时代的产物,高度碎片化(与 SOA 型服务比),高度依赖于解决底层非功能性技术问题的 PaaS/CaaS 平台,天然符合多租户、需要 DevOps 支持
一个微服务通常很可能是通过从现有服务 fork(开分支)、clone(直接复制)、mutate(变种)出来,这很有可能是违反我们在软件工程中一个所谓 DRY(Don’t Repeat Yourself)的原则 - 我们已经习惯于认为,剪贴代码是糟糕的、粗暴复制功能不好的,在理想主义的软件王国里,绝对没有拷贝粘贴的代码,也没有冗余的数据,更不应该有复制的服务。
然而,我们对世间事物的认识,往往是螺旋上升的,没有绝对的赞好、也不能武断的说坏,在现实这个不完美的世界里,除了编程大拿、代码洁癖者、技术原教旨主义者,我们必须接受一个现实,就是只关注快速实现业务需求的程序员、普通运维工程师是大多数,粘贴代码、复制部署服务可能就是大部分以业务功能为终极目标、以快速上线为首要任务的普通工程师的本能,quick-n-dirty 是任何团队绕不开的取舍。微服务,通过结合容器技术,一定程度上接受了普通程序员克隆服务、克隆代码的“陋习” 。
- 系统升级,在条件允许的情况下,运维工程师最喜欢的可能是部署一套新的,旧的不碰。新的没问题,把旧的关闭;新的有问题,把旧的切换回来。微服务天然是考虑支持同一个服务的多个版本并存的,而容器则刚好是实现“不可变基础设施”(Immutable infrastructure)的最佳套路,这俩一拍即合
- 同一个服务,也许会逐渐演变成需要接受不同的运营约束(operational constraints)、或者针对不同的用户群,是不断收集新需求、重构代码、升级服务以保持单一服务支持不同业务需求?还是复制代码、克隆服务,在不同环境各自独立发展?对于快速敏捷支持不同的业务线、产品线,也许复制代码克隆服务是一个更高效的做法
Michael Nygard,一位曾任职私募股权交易机构的架构师,在他的“新常态”系列技术文章中,举了一个例子:他的公司有四十多个不同的交易席位(trading desk),分别在不同的市场采用不同的策略进行交易。每个交易席位都有自己的技术团队负责交易应用开发。如果他们像很多大企业一样采用一套单一的、集中式的交易系统,则任何交易组对系统的变更均会对其他组产生潜在的损害 - 因为变更影响他人、bug 产生系统性风险、测试需要更繁复覆盖更充分、变更发布周期需要更长、升级需更复杂慎重、交易系统受影响面更,他把这些潜在能导致失败的影响称之为“失败域”(failure domain)。
Michael 的雇主选择让每个交易组独立维护自己的小型、单一、功能聚焦的交易应用 - 开发工程师和交易员坐在一起工作、小团队作战、快速迭代,以此来最大程度缩小各交易组被动关联产生的“失败域”。这个场景,对于从事证券交易系统开发的工程师,是非常熟悉的。在这里我们看到两个极端的取舍:
- 交易系统从架构和基本功能的角度上看都是大同小异的,以一套理想的、大而全的、集中式的系统服务各条业务线、各个交易市场、各种交易产品,好处也许是集中运维统一监控,服务归一、数据完备,消灭了信息孤岛,公司能获得跨市场、跨产品、跨业务线的最完整的经营数据,轻易实现合规监管、统一风控。但是这种中心化系统,本身的任何变更都是牵一发动全身,任何缺陷都导致公司级风险,是一个典型的“脆弱系统”。也不利于任何业务线的单独敏捷运作
- 类似上述私募股权公司的做法,则是完全去中心化,多套交易系统冗余建设,在一定规模的证券公司里,几十套交易系统是常见的,确实产生很多问题 - 例如一个合规要求或交易市场的新业务,必须在几十套系统里变更升级,硬件资源得不到充分的共享利用,不同交易系统往往是异构技术形成一个个竖井(Silo),信息孤岛的形成给统一风控统一经营造成巨大困难,等等。然而,这个去中心化的做法,却是符合”反脆弱“精神的,它把失败域变小。每条业务线有自己的交易员、业务专家、工程师以及系统,响应市场竞争的效率最高
作为一个例子,微服务架构很可能对上述情形的解决是有帮助的。首先,在实际操作中,去中心化基本上是共识 - 避免全局、系统性风险比什么都重要,所以功能相同相似的服务在不同业务线、不同约束条件、不同目标用户环境下冗余部署是必须的;其次,越复杂、越大块头、越黑箱型的代码模块,越难弄明白,越怕被触碰,也就隐含越高风险,微服务化使之增加透明度;第三,一些服务例如交易引擎,架构大同小异但是细节很不一样,与其反复抽象、重构、支持一切交易市场、交易产品、资产类型,还不如克隆一下,把相互依赖以及对某些共同设施的依赖均降到最低,各自迭代发展,让每条业务线获得最不相互掣肘的、最高效率的技术支持。
但是正如我们常说的,“软件工程没有银子弹”,微服务架构带来的更多的碎片化,对架构设计、开发运维挑战更大,对开发者技能要求更高 - 例如需要掌握一系列 Cloud-native patterns(原生云架构设计模式诸如 throttling、circuit-breaker、bulkhead 等等)。容器技术作为一种工具链和微服务载体,则在此时发生了很大的促进作用,甚至是微服务化实际落地的可行性的一个重大保障。
显然,正如上述例子,我们是因为考虑微服务化单体应用而考虑容器工具,平白无故容器化一个系统则是毫无意义的,“容器化与否”本身也是一个伪命题。事实上,脱离业务特点谈“微服务”本身也是个伪命题 - “如果你都不能构建一个有效的单体应用,你凭什么认为微服务能解决你的问题?”(Simon Brown,”Distributed big balls of mud”)。
采用微服务类架构,则需要调整一些“传统”的观念,例如关系型数据的高度归一性(Normalization)、代码的可重用性(Re-usability)和系统的精益化(Lean),可能不再是无可辩驳的“美德” :越归一则数据关系的变更成本越高、代码越可重用则模块组件的依赖关系越复杂(dependency hell)、越精益的系统则变更越困难,这些都是对构建”反脆弱“型系统不友好的,而且很多时候,强韧性(Resiliency)、灵活性(Flexibility)和效率(Efficiency)之间是有冲突和代价的(还是 Fred Brook 的银子弹理论)。
事实上,随着大数据技术发展应运而生的 NoSQL 运动,一定程度可以说是对高度强调归一性的传统关系型数据库理论的“反动”。在微服务的思潮下,我们的服务首先是不共享任何东西(share nothing),每个服务可能都有自己的持久化存储(backing store),形成所谓的混合存储(polyglot persistence);其次,基于领域建模的开发(Domain Driven Development - DDD),对于实现微服务更加重要,以完整业务逻辑为中心,并解耦了对开发语言、数据存储技术等等的假设。虽然单体架构或者微服务架构更恰当的说只是不同的架构风格而不是架构本身,但是,一些开发语言、技术工具确实是更适合或者更导致实现出单体架构系统的,例如上述这位 Michael Nygard 先生就认为,传统的 Java 企业应用服务器市场里的技术,包括 Oracle Weblogic、IBM Websphere、Redhat JBoss 等等,是“鼓励”开发单体架构的技术,这又回归到本文关于“IOE”技术风格的讨论 - 分布式架构、微服务、容器化,是脱离技术分层(layering)的单体架构风格的,和大部分企业 IT 所熟悉的技术生态截然不同。
微服务、分布式架构是比单体架构更复杂的,可移动零部件特别多,零部件之间的关联关系复杂、通讯耗损大,为了解决这些问题,技术团队需要掌握此前不需要的知识 - 例如上述的 Cloud-native patterns、Heroku 12 要素、Reactive 技术风格与技术工具等等。一个企业如果没有具备这些知识与能力的技术团队,都不应该去考虑做微服务。
“架构风格”、“开发理念”、“最佳实践”、“技术原则与技术哲学”等等这些,通常只适用于优秀的技术团队,对于普罗大众的、以业务功能为开发目标的团队而言,也就是听完一次、佩服一下,结束。只有通过工具才能把这些抽象的东西实际落地,否则它们也就只好留在教科书、别人的 PPT、网上文章里。幸运的是,容器工具链的发展,也许正在成为这么一系列工具,会促进微服务在传统企业 IT 的落地。
会计准则、代码“库存”与进化式架构
在微服务架构的思维下,归一性(nomalization)不再是一个绝对的 “健康目标”,服务们通过克隆、变异、分叉而诞生,然后迭代发展、存活、消亡,在这过程中冗余、重复是被允许的,而淘汰则是必须的,所谓“有生有灭”,有用的服务(被使用的频繁、被高度依赖)存活,没用的服务关闭,我们设计微服务不是在一张白纸上凭空绘画,而是不断在现有的服务中派生、演变。这种架构,可以称之为进化式架构(evolutionary architecture)。
进化式架构有一个有趣的作用,就是代码“去库存”。这里说的”代码库存“,不是指代码的技术载体 - Git、SVN 等代码库,而是一家企业多年开发积累下来的代码,究竟是“无形资产”(Intangible asset)还是“债务”(Liability)和“库存”(Inventory)。根据美国的会计准则(US GAAP),一家企业的内部自研发软件费用是这么被划分的(粗略罗列):
- 项目启动前的相关内部和外部费用,被认为是开销(expensed)
- 自研发供自己使用(internal-use)的应用软件所投入的相关外部和内部费用,被认为是资产(capitalized)
- 让新系统接入历史数据、或者转换旧数据格式,所投入的费用,被认为是资产(capitalized)
- 系统投入运营后的相关培训、运维费用,被认为是开销
显然,一家企业 IT 的 R&D 产出,被认为是公司资产,软件研发的投入是一种投资,所以其产出软件承载着一种期望 - 增加企业的生产力。但软件毕竟不像机房、机器、网络设备那样看得见摸得着,对于大部分的企业管理者而言,无形资产恐怕总是有点说不清道不明,在这个连软件都不再以盒装 CD 加大部头手册的方式卖的时代,IT 管理者们量化自己的无形资产的一个本能,就是自豪的宣称,自己的系统含有多少百万行代码。可是,这几百万甚至上千万行代码,真的是资产吗?
首先,在现实中,一个系统的代码量基本上是逐年增加的,对于大部分团队,系统维护就是增加代码,真正有动力和能力对自己的已上线系统进行重构的团队是很少的,当一个团队跟老板报告系统代码行数下降百分之十的时候,该老板除了疑惑不解之外可能还有恐惧不安,业务部门和用户也不会为节省了几十万行代码而感谢你给你发奖金。可是代码越多的另一个潜台词,是风险点越多。有些风险是程序员引入的,有些风险,则是因为世界发生了变化、原来的运行环境业务规则发生了变化,原来的假设忽然不再成立,例如用一个十年老的网站改造去支持智能手机出现后的移动应用,原来已经稳定的架构和逻辑在修修补补后就产生新的缺陷。总之,世界的变化总是快于软件的进化的,而积累了十年的几百万甚至几千万行代码,总体来说是很难对变更友好的。这个时候,代码库就变成了库存、技术债、阻碍业务创新的惯性。
过去十几年来的企业软件,我们可以认为大部分是单体架构的,它们中的许多是内部逻辑铁板一块的交织着,甚至没有做到代码级别的松耦合(例如通过良好的面向对象设计与设计模式实践),陷入依赖关系地狱(dependency hell),无用的代码很可能继续存活在系统中从来没被淘汰。新工程师对老系统是拒绝的,因为技术套路和理念两年就过时了 ; 用户对老系统内心是崩溃的,因为让 IT 去维护修改它的效率永远是低下的。作为程序员,我们每个人心底里都讨厌接手他人的代码、抱怨前人的愚蠢设计或怪咖风格,我们基本上倾向于认为历史遗留代码(legacy code)是阻碍生产力的,总是恨不得除之而后快。
例如我们为了不触碰前人的代码,通过模拟接口绕开旧代码、换上自己的实现,然后旧代码就成为一段 dead code,但谁也无法确定它是否死透,因为它也有可能在其他地方被调用,于是谁都不敢把这段代码删除,于是代码只做加法越积累越多,而后来者则理解越来越困难… 可以想象,依赖这样的系统去创新,就像戴着脚镣跳舞。金融行业的应用系统,有很多这样的东西,庞大而沉重,日益成为厌恶害怕变更的“脆弱系统”, “我就是喜欢你看我不惯却不得不和我一起建设社会主义的样子” – 面对这样的技术库存我们很无奈。
普通程序员(尤其是被业务部门蹂躏着、无暇学什么理论的)的“本能”偏好和习惯是这样的:情不自禁的剪贴代码 ; 上线新功能最好部署整套系统而别让我折腾里面的细节,出了问题马上切回旧的那套 - 还好好的在那跑着呢 ; 永远喜欢做新项目写新代码,而不是去消化前一个傻帽的代码 ; 有些代码就是没法子写的优雅的,尤其是临时性运营性的代码,能不能用完即丢… 别轻视这些草根的、不高大上的“陋习” - 简单的、符合“本能”的、有“群众基础”的东西,才往往是有生命力的。
微服务架构风格之下,也许更符合草根习惯的开发平台终于有机会出现:高度碎片化,大家都在写小组件小程序,除个别关键服务外一般难以对整个系统产生坍塌风险,任何小程序可以被丢弃被重写,小程序们可能多个版本同时存活但是监控程序会告诉我们哪些已经逐渐没人用可以被销毁,面向一个有略微差别的新客户也许就克隆一个新服务稍微修改一下、避免修改现有服务增加判断条件… 微服务基于业务需要、市场变化、经营策略而持续不断的出现和消失,这就是一个像流水一样的持续变更中的有生命力的系统。
当然,前提是我们指望容器编排技术结合监控技术和 cloud-native 的各种架构模式把服务底层的运行平台搞定,所以一个强的平台团队依然是需要的。把一个一百万行代码的系统拆成 100 个一万行代码的独立运行协同工作的小程序,绝对不是一件随便可行的事。
当我们有非常好的工具以支持我们在短时间内快速开发出代码、极大程度释放生产力的时候,我们才敢于丢弃过时代码,让服务派生与进化、用完即扔,才可能不再把历史积累的代码当作什么珠宝般的贵重资产,才不再拖着充满风险的“库存”前行。
从生产工具到生产组织关系
新技术带来新工具,容器只是又一种工具而已。然而,鸟枪换炮不仅需要相应的新操作技能与观念,还需要与之相适应的组织结构,工具使用者之间的协作方式、运作流程、管理模式都需要作相应变更 - “二炮”变成“火箭军”,肯定不仅是改个名字那么简单,是和先进科技武器的发展相适应的。自从微服务开始流行的这两年来,网上越来越多架构师在讨论康威定律,不是偶然现象,是大家不约而同意识到,服务的切分、模块的解偶、技术系统的最终形态,很大程度取决于开发者所在组织的交流沟通形态。
单体架构应用开发的团队,很可能是这么一个 silo 团队:一到多个界面及交互设计师、几个前端开发(Web 1.0 时代,是 HTML 及模板编写者 ; Client-server 时代,是 MFC、JFC/Swing 甚至 X/Motif 开发者)、几个服务器端开发(EJB/JSP 的、更古老一点是 CORBA/IIOP 或者 DCOM 的)、一两个数据库的 DBA。这种团队虽然有多个角色对应多个技术层,但严格来说不算“跨职能”,因为他们基本上既不运营也不运维自己的应用,业务人员和运维人员并不在团队内。为什么称之为 silo 团队呢?因为多个这样的团队之间,信息是不透明不流动的。
微服务架构下的组织结构,适应如下特点:
- 有 Gartner 所谓的“外架构”与“内架构”之分,内架构主要围绕微服务的标准化设计,例如每个服务必须是实现单一责任(single responsibility)、服务边界(scope)清晰、接口约定(contract)明确稳定。外架构主要是平台,聚焦于系统性解决基于内架构的微服务实例的注册发现、编排、资源伸缩、生命周期管理、监控、高可用等等,解决服务碎片化带来的各种共性问题
- 平台团队负责平台的构建、优化、维护,持续整合新技术、持续向服务开发团队提供工具与公共设施便利,例如利用 Kubernetes、Swarm 或者 Mesos 之类的技术构建容器云支持多租户,基于行业(例如金融业)特有环境与要求定制网络与安全解决方案,用符合自身企业环境的技术解决 Docker 的网络问题,诸如此类。微服务团队则由业务专家和工程师组成,联合维护和保障一个服务的功能、有用性(没人用的服务就没有生命力)、运维,其中工程师很可能是全栈的、开发自运维的 - 虽然系统层面的高可用由平台团队支持,可是服务运行中的业务逻辑故障显然只有负责开发的人自己直接搞定
- 平台团队主动向企业各业务线的团队布道、宣传自己的工具与平台,争取更多的租户。而微服务的团队,同样需要向其他部门、团队布道、宣讲自己的服务,找到更多的应用场景和使用方。最后,各业务线的应用开发项目,则是在产品开发过程中组合、集成各种服务(同时也可能提供自己的微服务)以服务终极客户。所以,这是一个服务型的、“人人为我、我为人人”的组织。衡量这些团队的表现也好办,看看平台团队争取了多少租户、微服务团队支持了多少应用…
结合容器技术,基于微服务架构的组织,都可以成为 DevOps 型组织,因为容器工具链也许是迄今为止真真正正让开发与运维共同使用的同一套工具,把开发、测试与运维工程师通过 CI/CD 串在了一条协作生产线上 ; 此前虽然有 Puppet、Chef、其他所谓实现“infrastructure as code”的工具,实际上不同角色的工程师依然是没有标准化的工具分享的。别少看了共用一套工具的厉害之处,工具所附带的整套技术语言、概念、词汇表,往往成为工程师们交流沟通、描述问题的标准语言,否则他们往往是“鸡同鸭讲”,同一个词汇说的完全不是一回事。
虽然我们一直强调工程师的抽象思维,避免“心为物役”(过度依赖于某种技术、某个开发商的系统所定义的概念词汇来作为自己分析思考问题的基础),可是实际中具备良好抽象思维的人并不多,所以依靠一套比较好的工具作为技术解决方案领域(solution domain)的思考依据,也不是一件糟糕的事情。
掌握新技术新工具,需要传统企业 IT 的组织思维与时俱进,作相应调整、重构。否则,无论打着“互联网 +”的旗号还是标榜“科技”(例如所谓“科技券商”或者“金融科技机构”等等),都有点“意淫”的味道 - 生产组织基因不对,无法有效使用科技生产工具。实际上,任何复杂业务应用系统的架构,都涉及两大因素:技术和人。不考虑人与组织因素的架构,有伪架构之嫌。
纯粹卖容器技术解决方案的厂商,恐怕生意不好做,因为光卖武器而没有相适应的组织结构与操作方式,武器很难推广,尤其是现在传统行业甲方的 IT 恐怕依然没有把虚拟机和容器的本质区分好的环境下。
企业级 IT 向左、科技独角兽向右
企业级的 IT 方案,往往突出一个“大”字:总是庞大而沉重,总是大而全,总是显示出一副很强大的样子,它们强调的,往往是“治理”、规范、流程、管理… 而不是互联网独角兽们所聚焦的敏捷、把握市场机会、以快打慢、以创新迅速争夺客户… 这两种理念的区别,体现在对变更的适应程度上。
仅就金融科技这个领域而言,技术能适应变更甚至从中获益壮大是非常必要的。Zvi Bodie 和 Robert C.Merton 合著的金融领域经典著作《Finance》一书,定义诠释了金融学:“金融学是一门研究人们在不确定环境下如何进行资源跨期配置的学科”。Nassim Taleb 则在《Anti-fragile》中从金融世界开始讨论如何从无序(disorder)中获利。可见金融世界天然关注不确定、无序、随机、紊乱,金融机构的本质是通过风控从不确定中获利,这就是 Taleb 所说的“反脆弱”。金融机构的科技,是否也需要具备“反脆弱”基因与之相适应?
有技术同行以适应变化的能力、喜爱不确定性的程度为标准,把公司分成两极,一端是拖着几千万行代码“库存”的“雷龙”俱乐部成员们,另一端是轻资产、迅猛、快捷逮住市场机会的“独角兽”们。侏罗纪的雷龙们长五十米重三十顿,最终在没有在物竞天择、适者生存的游戏中存活下来。
独角兽(一个由 Cowboy Ventures 创始人和风投家 Aileen Lee 所发明而被投资界广为使用的概念,专指发展迅猛、所做的创新为世界所未见、具有高度价值的公司),则是不断颠覆行业让雷龙们疲于奔命。一个把自己变成雷龙的例子是 GE,它把绝大部分的软件开发都外包出去。问题是,软件开发商的收入模式就靠替客户开发 - 开发任务越多、工作量越大、代码越庞大越好,所以,“不管你需要还是不需要,它们会继续替你构建东西”(Michael Nygard “新常态”文),最终这些代码形成一个“价值 15 亿美元的船锚,并且被咨询顾问们镀了一层金以显得有价值” - 但实际上这 15 亿的锚不一定是你的资产,也可能是把你的船拖沉的债。
扯远了,脑洞有点大。回归到企业级 IT 的技术方案话题:作为一个在互联网企业和创业公司以及传统 IT 的甲方乙方都呆过很多很多年的技术人,个人虽然一本正经严谨讨论“企业级”解决方案,可是心底里喜欢的是互联网自由散漫那套,那就是开放(open)、轻量(light)、敏捷(agile)、精益(lean),而不是“企业级套件”、重型中间件和大中央数据库技术的粉丝(它们确实有存在的道理,用的恰当的话,但个人喜好无关合理性)。个人粉的以下例子,上升一下下到哲理高度,是符合极简主义、精益的理念的:
- UNIX,以及此后的 Linux,操作系统保持小的内核,开放接口,由大量小程序形成各种小工具,完成更复杂的任务可以通过脚本来粘合各种小工具
- REST,在 SOAP、UDDI、各种“WS-*”前缀的企业标准把 Web 服务搞的无比沉重后,REST 真是一股技术清风,用最基本的 HTTP 原语,更简单透明轻量的描述了服务
- Mechanical Sympathy,这个由 Martin Thompson 等人提倡的理念,指出要把一个高性能的程序做好,程序员必须对计算机底层硬件的基本原理(例如 CPU 的缓存机制)有一个认识,才能通过合理的数据结构与算法设计,去发挥运算能力(现在的企业软件开发,更像“考古”工作,应用开发者的代码只有一点点,下面是第三方框架层、JVM 虚拟机层、并发线程库、操作系统的系统库、操作系统内核… 顶层的工程师可控的东西非常少,大部分人对计算机原理不求甚解)
微服务加容器,和小程序加 UNIX,是否有那么点哲理上的可比性?正如写 UNIX 小工具的人需要直接了解操作系统,写微服务的人需要直接了解一点容器与容器编排、原生云架构模式 - 这是开发者真正第一次介入云计算,此前基于虚拟机的云计算只对运维有意义,对开发者透明(试问此前有多少开发工程师在自己的应用系统里调用过虚拟机的 API,基于业务需求控制云计算资源?又有多少人在意自己的代码跑在物理机还是虚拟机里?)。虽然不久的将来,容器技术很可能又被大技术厂商们搞成一个个冠以各种高冷术语命名的、不透明的“企业平台”。
套用网上“鸡汤”的常用语,技术的“初心”是提高效率增强生产力。不想变成雷龙的企业,需要引入科技工具。以前建房子用铁铲挖泥,现在用挖掘机。那么问题来了(还不是“挖掘机哪家强”,还没到那份上,挖掘机性能可能都差不多…), 一个十年前或者更久远的企业组织、生产关系,能有效掌握新生产工具吗?
微服务、容器神马的,都是浮云,这种现象级的技术浪潮会一浪接一浪,等学会了,又已经过时。所以,本文想扯的观点其实是,去一家“兄弟单位”调研容器技术怎么用、和技术界大牛学习微服务最佳实践…等等,其实很可能没有什么显著效用,因为很快你会发现超容器、超超容器、去容器化又出来了,当我们总算丢弃了青铜剑进入汉朝斩马剑的时代,发现别人已经在舞弄连人带马都能劈碎的唐朝陌刀。
最可怕的是,还有几个哥们已经在比划着玄铁剑、叫嚣着“重剑无锋,大巧不工”的理论 ; 但最最可怕的是,还有哥们已经在玩剑气搞“无招胜有招”… 按照金庸金大侠的理论,最根本的还是内功。企业 IT 的内功是什么的?个人认为是组织结构、体制、文化,在这个时代,只能通过构建有科技基因的、对技术友好的组织,让团队和新技术共同成长(而不是等它成熟再去向“兄弟单位”学习),保持精益的技术文化和理念,才能“去库存”,稍稍具备一点独角兽的特质 - Swift(迅捷)、Nimble(灵巧)。
作者介绍
梁启鸿,广发证券 IT 研发,董事总经理首席架构师。哥伦比亚大学计算机科学系毕业,出道于纽约 IBM T.J. Watson 研究院,后投身华尔街,分别在纽约 Morgan Stanley、Merrill Lynch 和 JP Morgan 等投行参与交易系统研发。本世纪初加入 IT 界,在 Sun Microsystems 大中华区专业服务部负责金融行业技术解决方案。后加入雅虎担任北京研究院首席架构师。三年前回归金融业,企望做些能改变传统面貌的、有趣又有用的事情。
感谢郭蕾对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论