作为技术人员,通常很容易碰上需要接手,别人维护过的屎山代码和系统。最近有几个朋友问到了我关于接手屎山系统怎么处理的问题。如何能保证屎山不倒,还不被屎山拖死,让公司愿意给一定资源让你有时间愚公移屎山,能做到“万屎丛中过,片屎不沾身”,这都是很有技巧和方法的,本文将为你详述。
这里把多年前在高效运维微信群中讨论的话题整理成文,为了让大家有完整的感受,以下为全文目录:
-
一、背景说明(糟糕的老系统)
-
二、加油!造新系统
-
三、奋斗!新老系统并举
-
四、YES!新系统上位
-
五、老系统很糟糕,怎么办?
-
六、赠送:如何管理老板的预期
-
七、Q&A
本文来自于顾强同学的提问:关于如何对建设时间比较长,原有架构不是很合理的企业核心系统做优化,我想请教一下群里的大侠。有相关经验的高手还请分享一下,多谢。
本人刚好有空的情况下,耗费约4小时,不停敲字完成此文。
一、背景说明(糟糕的老系统)
2013年我过去的时候出现的就是老系统烂的要死,没人能维护,新系统没有配备资源可以做,老的垂死挣扎,新的嗷嗷待哺,老板不给资源。当然我这边是做开发的,因为开发的系统跟业务结合比较紧密,所以带有一定运维的工作量。
当时老的系统出现的问题是代码结构极端的不合理,我去的时候有五个开发人员,能动手直接大面积改代码的只有一个人,剩下的四个都是小修小补,在周边做一些外围的工作,能改动老系统的那个人,之前是做嵌入式开发的,所以代码极端的生涩难懂。
但是那个阶段只有他能改,而他改完了别人更没法改了,而这人手还非常的慢,所以阻塞了非常多的需求,经常加班,他自己疲于奔命,别人也帮不上手。
我做的是广告系统中的竞价引擎也就是RTB,我拿到代码之后,看了一周的代码发现这代码让谁后续维护谁都得疯掉,后续开发和维护的成本太高。
为了能收拾这个烂摊子,我向公司老大额外申请了两个headcount,老的五个人不动,直接划给负责这个业务运营的团队老大直接管理和维护,给他承诺了几个期限(确保他心里有底愿意接这个老系统,为我腾出精力和时间迭代),同时分别向CEO,CTO(我直属领导),以及业务运营部门的VP不断的灌输和洗脑,老系统不迭代,半年之后等死。
最后他们也都答应了,这样我拿着两个headcount,把老的系统交给可以暂时维护的VP,我重新组建团队,重新开发新系统。
这里面需要注意的是新系统开发的人手一定要精简,人员质量(代码质量和架构设计能力都要相对强),否则将会给你在公司内部带来极大的压力,从而你事情没做完,别人就想把你干掉了。
二、加油!造新系统
于是从6月底到7月中旬做老系统的需求调研和新系统的架构设计,7月底开始编码,框架8月初搭建完成,初步进行了压力测试,其中并不包含真实业务逻辑代码,做这个测试的目的在于尽快出一套东西,让CEO,CTO看到希望,给自己留一些余地和时间。
测试完成后表明同样机器资源的情况下,新系统的框架并发是老系统的6倍还绰绰有余,响应时间远小于老系统的一半(当然里面不包含业务逻辑代码也是效果好的原因之一)。
差不多到8月中旬开始梳理老系统业务逻辑,新系统采用针对业务逻辑分层,各层之间去耦合,模块采用动态链接库形式动态加载,在线热插拔,多算法并行运行,流量任意拆分比例到各种算法进行灰度AB测试这一些功能都是在框架设计之初就考虑进来的,这样后续的并行开发和测试就不会有太多问题。
老系统业务逻辑需求初步整理到八月下旬。八月下旬到九月下旬,一个月在新系统中对算法进行分模块实现,十月初,内部测试没有问题的情况下,找业务运营部门的VP要少许真实业务流量进行测试,跑通全流程后,差不多到十月中旬,新系统基本上完成了和老系统大多数功能的开发。
三、奋斗!新老系统并举
这个阶段老系统和新系统进入并行开发和维护阶段,即,所有需求之前都是向老系统提的,新系统的开发追着老系统的需求在不断的更新和按照新系统框架要求的开发模式实现功能。
这个阶段新旧系统并行开发,主要流量在老系统上进行承载,新系统只留1%的流量进行测试和验证,同时给老系统的开发人员培训新系统的架构,以及新的开发模式和运营模式,差不多到十月底新系统可以和老系统并行完成任意功能的开发,且开发效率高于老系统,运营成本低于老系统。
同时老系统的开发人也初步理解了新系统的开发模式,十一月初,正式开始加载线上的流量,广告行业需要对接多个不同的广告网络的流量,为了减小对业务的影响,先从流量比较小的渠道进行切换,基本上采取两周切换一个渠道的速度,碰上流量比较大的渠道则加长切换时间,按比例逐步增加新系统上的流量,差不多到十二月中旬主要的几个渠道已经流量切换到新系统。
四、YES!新系统上位
此时进入主要需求由新系统跟进,老系统开始追随新系统进行开发,运行到2014年一月份老系统基本上已经被切走流量,作为备用系统,当时的考虑是如果新系统出现问题,还可以切回老系统对业务进行支撑。
到切换完毕,彻底废弃老系统是在2014年春节结束后一个半月,新系统已经稳定运行了差不多3个多月,在这个过程中由于新系统开发包括我只有两个人,老系统开发有五个人。
为了能够最大程度运用人力,在新老系统并行开发的阶段对老系统的人员也做了新系统的开发培训,避免新系统起来,老系统的人闲置,新系统的人开发地越多自己的包袱越大的问题。
在此期间也是有分阶段、分层次地对新老系统开发人员的逐步介入和切换:
-
一开始将新系统的框架编译好交给老系统的人员进行上线维护,新系统的人实现算法模块; -
随后新系统的人指导老系统的人开发,最后对老系统人员在新系统开发的代码进行代码走读; -
最后彻底将算法开发提交给老系统开发人员进行开发,新系统的开发人员负责框架层面的开发和编译,两侧的业务边界是,框架由新系统开发人员维护,算法动态链接库和线上运维由老系统开发人员维护。
五、老系统很糟糕,怎么办?
针对这种老系统架构不合理或者代码脏乱差的系统基本上有几点需要注意:
-
老系统短期内不能废,更不能影响业务,一定要找合适的人把系统继续运行维护下去,让你有相对充分的时间和精力去做新的。老板不会容忍你没有做出新的就想干掉老的,因为这会断了老板的财路,老板就会断了你的生路。 -
新系统的开发资源一定要足够的精简,但一定人员素质要非常高。否则资源要太多,老板会肉疼,长期不产出,兄弟部门看到你们吃空饷也会有抱怨,你的死期就到了。而人员素质如果不高,即便给了你是时间和空间,在限定的时间里做不出东西,老板也不会容忍你很久,要照顾老板的预期。 -
要拆分需求,让手下的兄弟能够看到希望,而不是扔一个大的目标放羊让他们做,这样做一半人要看不到希望,中途离场,你就自己僵在现场了,一定要保证你为数不多的几个开发人员高效,稳定的跟你善始善终做完这个项目。 -
你需要找到合适的人能够帮你理清老系统哪里不好,问题的症结在哪里,老系统的需求如何平行切换到新系统,而新系统可以以更高的效率开发,更低的运营成本。需要有非常明白业务的人员是跟你一条心的,愿意和你一起把新的系统做好。
六、赠送:如何管理老板的预期
管理老板的预期,以及员工的预期是开发经理或者是总监的关键任务。
管理好老板的预期,老板到底要什么?老板对什么不爽,老板能给你多少资源,老板愿意等你多久,适时给老板一些甜头或者是希望,定时骚扰老板,让老板知道你在资源非常有限的情况下努力往前,而且分阶段还能出成果,成果看得到,可以检验。可以与老系统直接做对比。
七、Q&A
Q1: 核心系统与外围系统的接口关联比较多,在新老系统并行的如何处理这个问题的?
解耦。
Q2: 关键的数据模型新老系统有保持一致或者延续性吗?有时核心为了迁就周边系统要做一些折中么
核心系统一定是最精简、最高效的,不要把系统做成只有核心系统,并且以其为中心不断摊大饼的模式来做系统,系统做到一定规模一定要拆解和细分,当然粒度要合理。把相关的系统作为外围的插件来配合核心系统,当然数据模型一定要照顾新老系统,否则你新系统做出来没法平行从老系统切换到新系统。
Q3:你们这个升级周边的系统都配合修改了吧?
恩,对的,周边系统在你做新系统的架构设计的时候就要考虑好新系统需要什么,需要周边系统做什么配合,不管是业务流的,数据流的,都先考虑好,在做新系统之初就讲周边系统和老系统一起做一定的升级,当然这种升级一定要控制规模,否则会搞残老系统的。
Q4:新系统构建过程中,老系统有新开发的业务吗?数据库结构变了吗?缓存的数据结构变了吗?还有个问题,系统的体量有多大?可能这个会直接影响切换的方案和步骤,所以想详细了解下,谢谢!
老系统一直都有新的业务需求进来,数据库结构,缓存结构都在随着业务需求再做变化,一开头需求是以老系统为需求主要接收方,新系统追老系统。新系统要照顾到老系统在数据库库、表结构,缓存系统,数据格式上面做让步,在新系统做到差不多追齐老系统的大多数需求之后逐步切换流量,新老并行开发,随后才是新系统为主,老系统为辅,最终干掉老系统。
Q5:你们在做新系统设计的时候关键的优化点主要基于哪些方面的考虑?在系统架构设计上最主要要注意哪方面的问题?有过哪方面的考虑不周的经验教训?
其实作为DSP系统还是一个蛮复杂的系统,功能模块非常多,而当时我主要瞄准的是竞价引擎RTB部分的,周边的系统尽量兼容,由于是要写一个新系统,老系统的问题就在于代码质量不高,可维护性太差,架构不合理,做不到高并发和低延时,这才是我要动这个老系统的目的。
所以架构和代码我基本上是尽量不再使用老系统的代码,除非是业务逻辑相关的代码,也要按照新系统架构的需要做调整后用到新系统中,架构是重新涉及的,基本上推翻了老系统的架构,继承了大部分数据结构,做了小的更新。新系统当然不能比老系统缺少任何功能和模块,否则业务部门的VP,绝不会允许我换掉老系统的。我们的业务模式是快速迭代的,我们的维护人员是要写代码的。竞价引擎RTB部分的,周边的系统尽量兼容,由于是要写一个新系统,老系统的问题就在于代码质量不高,可维护性太差,架构不合理,做不到高并发和低延时,这是我要动这个老系统的目的。
系统架构设计的时候主要注意的地方是:解耦,解耦,再解耦;保持系统模块间的独立性;对业务一定要不断的check和review,一定要拉一个对业务非常熟悉的人做你的参谋。
经验和教训举个例子吧,广告系统中有一个比较关键的环节是做点击率的预测,也就是特定的广告创意投放在特定媒体的特定广告位上持续的点击率要先做统计,同时要对后续的可能的点击率进行预测。在对接谷歌adx的流量的时候我们发现一个问题,我们买回来的流量点击率非常的低,比盲投都低,盲投的点击率是万分之四。我们新系统当时对接完谷歌的流量发现,我们的点击率只有万分之二,也就会说我们的系统做选择性的投放之后,比海量闭着眼睛瞎投还差,这个问题折磨了我一周左右的时间,愣是没找到原因,后来我找了业务运营部门的一个哥们,才问出问题,这个问题老系统当年也碰上过,但是没有形成文档。
最后把问题找到了,就是谷歌流量里面有匿名流量,也就是说,你出价前,媒体告诉谷歌不想让买家知道媒体和广告位的信息,出完价,展现了才知道这个媒体和广告位是哪个。这部分流量其实质量通常是比较好的,而谷歌限定的条件是流量中,广告位ID和匿名ID有且只能有一个。
而我们解包的时候发现匿名流量没有广告位ID,我们以为是错误流量,就丢弃了,剩下的流量里即便买再多,质量也不会比匿名流量高太多,最后我们新系统里做上这个逻辑之后,点击率立马就回升了,能跟老系统的万分之六持平,后续能到万分之八,最高的时候能到千分之一。
Q6:在系统上线之初,肯定会对系统实现的业务逻辑是否与老系统一致存在担心,你们是如何从开发测试的流程上以及技术手段上来确保新系统逻辑的准确性。是不是用生产上实际的流量并行模拟一段时间,并进行新老系统数据比对?
新系统的逻辑有效性有几种办法,有的以黑盒从输入输出上来确定,这样做的好处是简单,快速,但问题在于测试的样本集会非常大,而且也容易遗漏,这个就需要开发人员和测试人员一起来梳理测试用例,让测试尽可能地掌握系统开发的层面上到底有多少坑是测试不知道的。
另外就是代码走读了,由于开始和中间新老系统是由两个团队在维护,做新系统的架构和开发模式培训的时候,对于系统代码做了代码的走读,在先期架构设计的时候也对老代码读了很多遍,算我在内的新系统设计和实现的三个人对于老代码基本上是烂熟于心了。
还有就是线上运营来复制流量进行模拟测试,但是这种方法有个问题,对于事务性质的业务你可以用复制流量来看所做的事务是不是有效通过了,对比新老系统的结构就知道新老系统是不是一致,只要样本集足够的大基本上能够让新系统和老系统一致。
但是这个用法在广告系统中是有问题的,广告系统中同一个人的两个流量进来两次,可能投放的广告主,或者是创意的形式,甚至是广告位的尺寸,都有可能影响点击率,而每次进来的流量最后投放的广告都有可能不一样,你要用这种办法来测试广告系统基本上是不可能的。
但是广告系统有一个好处就是,没有作弊流量的情况下,广告投放基本上就是在买概率,通常盲投也会有万分之四的点击率,那我们就盯着点击率不就行了么?新系统和老系统分别加载流量,各自跑,算法打上不同的算法标签,谁产生的点击都是可以标记出来的,最后算哪个的点击率高就是那个系统有效,如果新系统的点击率比老系统要高,那新系统不就没有问题了嘛。
Q7:信息类系统,如果新老系统的数据库结构不一致,又如何进行新老系统数据比对?
库表接口不一致是很常见的,我觉得主要还是要抓住主要的数据流,看关键的业务流程。