微服务架构下的系统拆分指南(一)
至从ThoughtWorks的 Martin Fowler 喊出来“微服务”,IT业界仿佛打了一阵强心剂,从互联网行业,到相对保守的电信,金融业,都在对着自己的系统,拿着拆迁大锤跃跃欲试,想一拆为快。微服务到底给我们带来了什么,用微服务真的就是万能解药吗?今天就来侃侃这个话题。
这文章本来计划要写一篇就搞定,后来发现内容还是比较多,就拆成几部分来写,这样可以写的更加透彻。
本文假定的读者是那些已经对微服务有了一点儿了解,并且已经计划要按照微服务风格进行系统改造了的拆迁预备队们。
1. 为什么要拆,单片系统的七宗罪
说到传统系统,大致可以想象成这个样子,系统在横向功能上按照模块分开,在纵向上分成控制层,业务层,数据访问层等几层。无论是模块间的调用,还是功能层次间的调用,几乎都是代码级调用。一个系统代码动辄10万行起步,极其庞大,我曾经用瑞士军刀来形容这种系统。
单片系统如瑞士军刀一样,功能齐全过去几十年我们一直在开发这样的系统,我们谨慎的建立业务模型,梳理业务流程,做好每一个模块的设计,并尝试做好通用模块。然后经过数月甚至经年的开发,再花费更长的时间进行各种测试,最后交付给客户。这种系统集所有功能于一身,什么都能干,用瑞士军刀来形容一点儿也不为过。
以下单片系统的这些问题会随着代码量的增大而变得严重,大就是原罪。
当今环境下,单片系统暴露出的不足:
- 代码规模庞大,难于读懂,难于修改,难于维护,甚至修改几行代码,要做超过预想的大规模测试。
- 开发周期长,很多系统都需要以半年为单位来计算上线时间,对于业务更新频繁的系统,单片系统模式更是难以应对,尤其是互联网产品。
- 技术栈单一,通常一个技术栈能够解决整个系统90%的问题,但是总有那么些特例,让架构师,让开发人员费尽脑筋去找一些折衷方案,不能用最合适的技术栈去解决问题。
- 难以部署,一个单片系统功能众多,配置文件有时真的如满天繁星,上线那几天彻夜的日子想必大家都经历过,上线之前烧柱香,祈祷疏通测试顺利通过这是常例吧。
- 某些bug会搞垮整个系统,单片系统内部功能模块通常共享一个进程空间,如果某个处理破坏了整体运行环境(比如内存泄漏),那系统就会崩溃,影响极其巨大。
- 对客户反馈慢,从笔者的经验来讲,客户第一次碰到能动的系统,常常是CUT结束的那个阶段,我们叫它 alpha版,但那通常已经是三个月以后的事情了。如果这个时候客户说这不是我想要的,就需要大返工,将影响后面的结合测试,系统测试,最终影响上线时间。而很明显的,修改时机拖的越晚,风险越大。
- 高可用要求下,通常以整个系统为单位,进行冗余扩张,也就是完全一样的系统拷贝一份儿留着当备份,极其浪费资源。而且当系统真正面对客户使用量潮汐压力的时候,又很难快速的扩张实例来进行扩容,灵活性差。
其实还可以写很多,但是为了切题,就不大批特批了,毕竟用了单片系统好多年,不能太过分。
2. 拆分时代的罪与罚
微服务的概念,特征,原则这些东西咱就不掰了。去中心化,各个服务协同,高内聚,低耦合,独立进化……天天的吹着交付快,部署快,修改快,性能伸缩快,耳朵磨一层茧子。好多人看完了马丁那书,对着自己眼前那几十万行代码,都跃跃欲试拿着锤子去过一把拆迁队的瘾,但是抡起你的锤子之前先等等,看看下面这一段再说。
微服务风格的架构就像工具箱,摆放清晰,但是总体变得更加庞大以下这些问题,会随着拆分粒度变细而变得显著,相对单片系统的大是原罪,微服务小也是原罪。
2.1.真的容易维护了吗?
拆分以后,各个服务代码规模变小(也许真的能够达到数千行的级别),对于单个服务来讲可能更容易维护,但是服务之间都使用MQ,RPC来进行通信,要弄懂全盘一样要跟着调用链跑遍整个系统,调用链的增长,随之而来的一样是难于读懂,难于修改,难于维护,出了bug难于调查,在这一点上,微服务和单片系统不分伯仲。
还有一点要说,就个人经验来讲,微服务风格实现同样一套功能,需要的代码实际更多了(后面还会讲哪些变多了),最简单的例子,有些通用代码例如StringUtils到处都要写(你总不能把StringUtils也做成一个服务吧 )。
2.2. 真的更加容易治理吗?
SOA时代还有一个ESB,要治理服务只要顺着ESB这条主线看过去就可以,到了微服务时代,ESB都被丢弃了,想在框架上做好治理,几乎成为一件不可能的事情,甚至都无法预测将来这个服务要被多少个其他服务调用。
其实用西方的民主制度做比喻非常形象,他们推崇的是每个人都有权利做决定,每个人都应该参与其中,但是这里有一个大前提,那就是每个人都有判断的能力,得“懂行”。西方的民主可以给自己选一个光明的未来,也可以让英国脱欧。
2.3. 真的降低了系统复杂性吗?
这个答案非常有可能是NO,微服务风格下,连数据库都要给拆开,有些服务之间的技术差异非常大,要画出系统图的话,那真是能看到“百家争鸣”,“百花齐放”的繁荣景象,最后连数据更新事务的一致性都保证不了,还得使用TCC,最终一致性之类的模式来替代。汇总报表要从各个服务数据库中抽取数据去做统计,有时候连个最简单的join都做不到了,“跨着数据库呢大哥,想要数据?用接口来调!”
2.4. 真的节省系统资源了吗?
单片系统通常部署在一个进程空间内,或者是一个集群内,代码级别相对调用较多,这是比较节约资源的,虽然这种方式难以扩张,但是在其性能容量容许范围之内是最快的。微服务风格体系是靠着网络通信来进行相互调用,从效率上来讲,被单片系统甩了不止一条街,系统拆完了以后消耗网络资源比以前大是肯定的事情。而且因为需要为每一个服务准备隔离运行环境(甚至要准备独立的数据库),因此和单片系统相比,CPU资源,内存资源,磁盘资源的消耗也会更多。
2.5. 真的省了钱了吗?
曾经有一些文章提到过这样的论点:“微服务降低开发成本。”,但就我个人的实践经验来讲,并不是这样,这里用吃饭这个事儿来说这个事儿,“以前做单片系统,就好像吃一顿饭,大家入座,端起碗筷,吃肉,吃菜,喝汤,放下碗筷,离席。”,“如今做微服务,吃饭流程都变了,大家入座,端起碗筷,吃肉,放下碗筷,离席;大家再入座,吃菜,放下碗筷,离席;大家第三次入座,端起碗筷,喝汤,放下碗筷,离席。”,很多项目初始化和收尾的工作都要重复的做,从工作的总量上来讲,也是比之前多了,而绝对不是少了。
比单片系统少写两点吧,批的太多,连我自己都快把微服务架构扔到垃圾堆里面去了。
(未完待续。。)