给飞驰的法拉利换引擎,续谈如何边做业务边重构架构

上一篇文章中,作者李运华提到了《架构重构》系列文章的背景,他在阿里游戏曾参与过3个重要系统的重构,并且这几个系统的特点都不一样。在整个的过程中,他踩了很多坑,也遇到过很多问题,协作上的,代码上的,业务上的,在这系列文章中,作者将自己积累的经验和盘托出,分享给读者。

本系列文章着眼于如何在业务正常进行的同时,对已有的关键系统进行架构重构,正如作者的比喻,这件事情就像是给飞驰的法拉利跑车换引擎。第一篇文章中,作者总结了如下几个重要观点:

  1. 架构重构首要的任务是从一大堆纷繁复杂的问题中识别出真正要通过架构重构来解决的问题,集中力量快速解决,而不是想着通过架构重构来解决所有的问题。

  2. 要想真正推动一个架构重构项目启动,需要花费大量的精力进行游说和沟通。

  3. 如何才能有效的推动重构呢?我们的策略是“换位思考、合作双赢、关注长期”。简单来说就是站在对方的角度思考,重构对他有什么好处,能够帮他解决什么问题,带来什么收益。

下面是整个系列的第二篇文章,欢迎品读和反馈。另外,如果你对架构感兴趣,不要忘记关注聊聊架构(archtime)。我们保证您所读的每一篇文章,都是精品。

运筹帷幄

一般来说,需要架构重构的系统,基本上都是因为各种历史原因和历史问题没有及时处理,遗留下来逐渐积累,然后到了一个临界点,各种问题开始互相作用,集中爆发!到了真正要开始重构的时候,我们可能会发现千头万绪,感觉无法下手,随便整理一下就几十个大大小小的问题要解决。此时架构师或者技术主管面临的主要问题就是怎么去推进。

可以想象一下,假如我们拿到一个架构问题列表,其中有50个问题,那我们应该怎么去把这50个问题最终解决呢?

最简单的做法是每次从中挑一个解决,最终总会把所有的问题都解决。这种做法操作起来比较简单,但效果会很差,为什么呢?

第一个原因是没有区分问题优先级,所有问题都一视同仁,没有集中有限资源去解决最重要或者最关键的问题,导致最后可能出现做了大半年,回头一看好像做了很多事情,但没取得什么阶段性的成果。

第二个原因是没有将问题分类,导致相似问题没有统筹考虑,方案可能出现反复,效率不高。

第三个原因是会迫于业务版本的压力,专门挑容易做的实施,到了稍微难一点的问题的时候,就因为复杂度和投入等原因被搁置,达不到真正重构的真正目的。

以X系统为例,在我加入前,其实也整理了系统目前存在的问题,大的项包括:可用性、性能、安全、用户体验等,每个大项又包括十几二十个子项。但是实施的时候基本上就是挑软柿子捏,觉得哪个好落地、占用资源不太多,就挑来做,结果做了半年,好像做了很多功能,但整体却没什么进展。

我加入后成立了一个“X项目”,在原来整理的问题基础上,识别出架构和业务目前存在的主要问题是“可用性不高”和“可扩展性”不足,其中可用性不高有的原因是因为硬件资源不够用了,或者某些系统组件使用不合理,有的是因为架构上存在问题;可扩展性不足主要原因是系统耦合比较严重,这同时也是可用性不高的一个原因。

基于这些分析,我们制定了总体的策略:

上图是去年7月份的时候制定的,目前已经完成第一阶段和第二阶段的工作,第三阶段因为实际问题比我们预想的更加复杂,加上其它因素,目前还在进行中。

为什么确定这样一个策略呢?主要还是为了集中有限的资源,某个阶段集中解决某一类问题。这样做首先是效率高,因为阶段目标比较明确,做决策和方案的时候无需太多选择;其次是每个阶段都能看到明显的成果,给团队很大的信心。比如说第一阶段的“救火”,做完之后,系统很少因为机器过载、缓存响应慢、虚拟机挂死等问题导致的故障了;完成第二阶段的事项后,因为组件、外部系统故障导致系统故障的问题也很少了。完成前两个阶段后,我们就可以安心的做第三阶段的“服务化”工作了。

S系统的重构做法也是类似,但S系统当时面临的主要问题就是可用性不高,并没有系统耦合的问题,所以我们当时的策略是“先救火、后优化、再重构”,“救火”阶段做了扩容(防止资源不足导致系统被压死)和Nginx一键倒换功能(故障时快速切换);优化阶段将一些明显的可用性问题解决(包括性能问题等);重构阶段将原来的单点数据库改为多中心。

总结一下重构的做法,其实就是“分段实施”,将要解决的问题根据优先级、重要性、实施难度等划分为不同的阶段,每个阶段聚焦于一个整体的目标,集中精力和资源解决一类问题。这样做有几个好处:

  1. 每个阶段都有明确目标,做完之后效果明显,团队信心足,后续推进更加容易。

  2. 每个阶段的工作量不会太大,可以和业务并行。

  3. 每个阶段的改动不会太大,降低了总体风险。

具体如何制定“分段实施”的策略呢?以下经验可以参考:

划分优先级

将明显且又比较紧急的事项优先落地,解决目前遇到的主要问题。例如扩容在S系统和X系统中都是最优先实施的,因为如果不扩容的话,系统隔三差五一会来个响应超时报警,一会来个过载报警,一会来个大面积不可用。这些问题耗费大量的人力和精力,也就没法做其它事情了。

问题分类

将问题按照性质分类,每个阶段集中解决一类问题。例如X系统的第二阶段,我们将多个底层系统切换到UC统一的公共组件,提升整体可用性。

先易后难

这点与很多人的直觉不太一样,有的人认为应该先攻克最难的问题,所谓的“擒贼先擒王”,搞定最难的问题后其它问题就不在话下。这样看起来很美好,但实际上不可行。

首先,一开始就做最难的部分,会发现要搞定这个最难的问题,要先搞定其它容易的问题;

其次,最难的耗时都比较长,占用资源比较多,如果一开始做最难的,可能做了一两个月还没有什么进展和成果,会影响相关人员对项目的评价和看法,也可能影响团队士气;

第三,刚开始的分析并不一定全面,所以一开始对最难的或者最关键的事项的判断可能会出错。

采取先易后难的策略,能够很大程度上避免“先难后易”策略的问题。

首先,随着项目的推进,一些相对简单的问题逐渐解决,会发现原来看起来很难的问题已经不那么难了,甚至有的问题可能都消失了;

其次,先易后难能够比较快的看到成果,虽然可能不大,但至少能看到一些成效了,对后续的项目推进和团队士气有很大好处;

第三,随着项目的进行,原来遗漏的一些点,或者分析和判断错误的点,会逐渐显示出来,及时根据实际情况进行调整,能够有效的保证整个重构的效果。

文武双全

前面讲了那么多,看起来都是和项目管理相关的的,例如“有的放矢”是关于找目标的、“合纵连横”是关于沟通协调的、“运筹帷幄”是关于项目规划的。架构师怎么变成了项目经理了,说好的技术呢?

真正的架构师,当然必须具备一定的项目经理技能,但更重要的还是技术能力,道理很简单:再好的饼,最后实现不了,都是扯淡!我将“项目管理能力”称之为“文”的能力,“技术能力”称之为“武”的能力,架构师必须文武双全,才能最终把事情搞定!

架构师的“武”体现在很多方面,既有微观层面的,例如如何设计一个高性能的并发框架(可以参考Disruptor,大量的技术细节,例如CPU cache,cache line,false sharing等);也有宏观层面的,例如采用HBase还是用MySQL存储;还有和业务相关的,例如某个功能应该如何设计才能具备可扩展性。业务层面的相关的技术问题,如果没有相关的业务背景,讲起来比较费劲,也不好理解,这里就不展开了。我们讲讲这些重构项目中和业务无关的一些技术。

我被问到的最多的问题其实也是宏观层面的。其中一个主要的问题是“这些系统的业务都不一样,你之前也没有类似业务背景,你怎么识别出M系统重构的目标是数据解耦,S系统重构的目标是高可用呢,X系统重构的目标是系统解耦呢?”

秘密就在架构设计和重构其实是有一定的通用的“道”,不管什么业务,这个“道”都是适合的,详细的阐述可以参考我的博客专栏《BAT解密:互联网技术发展之路》(聊聊架构接下来将会发布),这里我提炼一下就是3个关键词:复杂度、性能、可靠性,也就是说,架构设计或者重构的主要目标是解决业务在这三方面遇到的问题。

以M系统为例,重构前性能不高,且只有单机,但由于是后台系统,用户都是内部用户,每天就几百个人使用而已,所以还不是关键问题;关键问题是“不合理的耦合带来的复杂性”:将特定业务的数据和所有业务的公共数据耦合在一起,数据正确性难以保证,且每次修改都是“牵一发动全身”,效率很低,所以重构的目标就是将“不合理的耦合”进行拆分。

而对S系统来说,前期团队在设计的时候已经基于业务进行了拆分,各个子系统职责比较明确,边界清晰,所以复杂度不是主要问题;每天访问量都是亿级以上,之前的架构设计上已经考虑了多机房和平行扩容的能力,所以性能也不是主要问题。

主要的问题就是有一个全局单点,一旦这个单点故障,就会导致所有业务全部不可用,而游戏相关业务可靠性要求又非常高,只要有5分钟不可用,客服电话已经被玩家打爆了,论坛也都被刷爆。所以我们重构的目标就是解决“全局唯一单点”的可靠性问题。

X系统的情况更加特殊。首先存在和M系统相同的“复杂度”问题,只是表现形式不一样而已:M系统是数据耦合导致的复杂度增加,X系统是业务全部放到一个系统中实现导致的复杂度增加。其次是存在和S系统类似的“可靠性”问题,也只是表现形式有所差别:S系统是全局单点导致可靠性问题,X系统是有问题就整站挂掉的可靠性问题。

所以我们最初在讨论X系统重构的时候是定了两个目标:解决复杂性和可靠性的问题,但随着对问题的分析逐步深入,我们发现如果不解决复杂性问题,可靠性问题是无论如何都解决不了的。所以最终我们调整目标,将X系统的重构目标聚焦在将“大而全的系统拆分为多个分工合作的子系统”。
从上面的3个实例我们可以看到,其实只要掌握了架构设计的“道”,不管什么业务,在宏观层面的判断和决策都可以用这一套方法论去应对。

明白了架构设计和架构重构宏观层面的关键之“道”,我们来看看微观层面的“术”:即我们如何才能设计出一个方案来满足复杂度、可靠性、性能的需求呢?

说出来你可能不相信,架构设计或者架构重构有一把“屠龙宝刀”,复杂性、性能、可靠性都可以通过这一个方法去搞定。这把屠龙宝刀就是“拆”!

  • 数据耦合? 系统太庞大?—— 将系统“拆”分为多个子系统。

  • 性能比较低?—— 将一台机器“拆”为两台,两台不够“拆”为4台。

  • 可靠性不行?—— 单点“拆”分为集群,单机房“拆”为双机房。

到目前为止,看起来架构设计好像很简单:“复杂性,性能,可靠性,拆”,感觉随便一个人掌握了这4个关键字就可以做架构设计或者重构了。看起来架构师也不过如此嘛!其实不然,“道”是很简单,但面对具体问题、具体业务的时候,将“道”落地实现才是关键!

以X系统为例,将原有大而全的X系统拆分为多个子系统,关键不在于是否要拆,而是在于“怎么拆”。是拆分为2个呢,还是4个呢,还是10个呢?好像都可以,那又怎么取舍?例如:

  • 随便取一个?好像心里没谱!

  • 发个微信红包看最大的红包整数?好像是碰运气,选错了怎么办!

  • 现在不是流行微服务么,咱们拆的越细越好,参考淘宝,拆分为100个?你看研发和运维要不要打死你!

  • 不知道就让老大拍板吧?是你做架构设计还是老大做架构设计!

  • 找一群人来投票 ?大家都选拆分最少的投,因为这样工作量最少!

所以,“拆”的方向是没问题的,但“细节决定成败”,“如何拆”才是体现架构师能力的关键。要具备这样的能力,需要大量的实践、积累、思考、探索,因此要想成为一个牛逼的架构师是很难的,尤其是在国内这种过了30就不做技术的氛围下,更加需要对技术的热爱和不断的追求,同时要有比较好的机遇,才能够成长为真正的架构师。

对应到X系统的案例,我个人的经验就是7+-2原则,也就是说将系统拆分为5 ~ 9 个人能够维护的粒度,也就是说假如你的团队有20人,拆分成3 ~ 5个系统是比较合适,即使再拆的更细,最低要保证3个人负责一个系统的粒度,如果出现一个人负责1个系统,甚至一个人要负责多个系统,就说明拆的太细了,会带来很多问题。

为何按照这个原则来拆分呢?科学研究证明,人脑同时关注的目标大约就是7+-2个,对于一个9个人负责的系统来说,每个人基本上都可以覆盖到系统的所有方面,如果20个人才能维护一个系统,说明1个人可能要关注20个点,但人很难关注这么多的点的。

其次为何至少要3个人负责一个系统呢?这是从团队管理的角度出发的,如果2个人甚至1个人负责一个系统,首先是人员没有足够备份,一个人请假或者变动,整个系统的效率就要受到影响;其次如果1个人负责一个或者多个系统,思考难免有遗漏,容易出问题。

作者介绍

李运华,十余年软件设计开发经验,经历了电信行业和移动互联网行业,曾就职于华为和UCWEB,先后担任软件开发工程师、系统分析师、架构师、技术leader等角色; 现担任阿里巴巴移动事业群(原UCWEB)资深软件工程师,带领多个研发团队,承担架构设计、架构重构、技术团队管理、技术培训等职责。 

技术上专注于开源技术、系统分析、架构设计,对互联网技术的特点和发展趋势有较深入的研究和理解。先后负责过游戏接入高可用项目、飞鸽事件发布订阅系统、交易平台系统解耦项目,对于系统解耦、高性能、高可用架构有丰富的经验。

文章标签: 阿里巴巴 重构 架构


关注微信公众号“架构说”,加入Q群微群,让架构师带你飞︿( ̄︶ ̄)︿。


原文链接: 阅读原文
免责申明: 架构说任何转载的文章都会明确标注原文链接。如有侵权,请与本站联系。
转载说明: 架构说原创文章转载时请务必注明文章作者、链接和来源。