您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 商务礼仪 > 从为什么要重构到微服务架构
从为什么要重构到微服务架构公司决定将支付业务从原来所在部门剥离出来,成为一个独立的团队,以应付迅速发展的业务需求。原团队负责支付系统开发的几位同学转到现团队,形成开发班底。此后开始招聘,三个月团队扩充到10多个人。与此同时,公司业务也在快速发展,6月份宣布会员突破2千万。一些热片上映往往也会引发会员注册缴费的小高峰。其他业务,包括直播,阅读,动漫等,也都进入了发展的快车道。每天订单量早已经超过百万,比去年某片上映时把系统打垮时还早高。移动端每个月发布一个版本,桌面则是半个月。产品经理们夜以继日地规划各种功能,待开发功能都排到好几个月之后。而随着项目团队的日益扩大,却出现一些奇怪的事情:开发效率和以前没有太大区别,尽管队伍扩大了4倍多,人员素质则有所提升。大部分开发工作还是几位老员工在忙,新员工还比较难介入核心开发工作。除了管理因素,作为工程师,我们还是期待从技术上找到根源所在,解决问题,提高效率。最终的决策,是使用微服务架构来重构现有系统。这一系列博文,描述在这过程中我们做的选择、取得的成果、走过的弯路,以及经验教训。一、原有架构从技术角度看,原有系统是一个基于SSH架构的传统实现,软件架构整体上是大家所熟知的多层Java软件架构:代码让人看的非常怀旧,虽然开发人员和我说是4年前开发的,但这熟悉的SSH架构,可是妥妥10年前的东西。使用ApacheStruts做展示层,对数据访问层做个简单封装实现业务逻辑层,基于Spring的AOP以及Hibernate实现数据访问。数据保存在MySQL中,单库多表的结构。二、架构问题1.DAO层使用Hibernate来封装数据库访问操作。其优势是在面向对象领域,通过系统自动生成数据库访问语句的方式,使得开发者无需考虑数据库的实现细节,专注于对象的设计和使用,简化了开发工作。另外,使用Hibernate还支持系统可以在不同类型的对象数据库间无缝迁移。在业务对象关系复杂的管理系统开发中广泛使用。存在的问题是,它隐藏了数据库的实现细节,这导致在大数据场景下开发人员很难对数据库访问进行优化,而这却是互联网应用开发的重点。2.Service层业务逻辑层为Controller层提供具体业务的实现。但在实现上,问题还不少。如果是严格按照分层架构来实现,对业务逻辑层进行拆分,将本地调用变成远程调用,即可比较容易实现拆分。但实际中往往会碰到如下问题:这个层往往并未实现单向依赖,部分业务逻辑层实现被注入了接口层的参数(request,response),使其耦合到接口层。为了应对不断变更的需求,不少接口会使用map作为输入输出参数,此类接口在维护时无法约束其参数。Service层绝大部分实现是使用工厂模式来管理数据对象。仅对工厂类建模,未对业务实体建模。这个层的实现是不完整的。这使得对业务实体的操作需要推迟到Controller层来实现,导致Controller臃肿。当服务之间存在大量依赖关系时,开发人员往往会直接将SpringBeanFactory注入到各个服务中,或者简单封装一个FacadeService,通过这个Service可以访问到所有的业务逻辑对象。这个类的使用导致无法评估Controller层对Service业务对象的具体依赖。3.Controller层基于ApacheStruts来实现,ApacheStruts漏洞频繁爆发,修复慢。当前已经很少在对外的应用中使用了。由于Service层实现上的问题,Controller层承担了部分业务逻辑实现,使其臃肿,难以测试。三、功能问题从功能模块上来看,并没有区分对端的服务以及对运营管理系统的服务,仅实现了支付系统的基本功能:四、实施问题1.可扩展性差,性能提升困难web应用性能瓶颈基本都在数据库上。这个系统使用mysql作为数据库。三个应用对应三个数据库。没有读写分离。读写都在一个库上操作。数据量最大的表当时在5000万条数据。高峰期数据库操作的QPS在1000左右,压测结果是可以支撑2000的QPS。这个指标令我诧异。为什么能有这么好的性能?首先是,没有复杂的查询逻辑,所有查询都在一个表里操作,没有跨表事务处理,复杂的处理,分解为多个语句来执行。最复杂的一个action中,执行了将近20次数据查询。其次,也是最重要的因素,这里用的是SSD磁盘。从目前情况看,撑到年底应该是可以的,这也为我们技改争取了足够的时间。尽管这样,对mysql还是没有把握。每次运营部门搞活动,我们都玩胆战心惊地盯着,祈祷活动不要太有效果。从应用层来看,目前读写比在10:1,接口日访问量10亿。高峰期访问量在300QPS。公司业务增长迅猛,数据量半年翻一番,访问量预估10倍增长。还有一个严峻的挑战,产品同学扬言要搞秒杀,秒杀…每秒十万的量必须支持到。这就超过MYSQL能承受的压力范围,需要把读操作切到内存数据库上,但是在SSH架构下,读写分离实现就得伤筋动骨了。另外由于Hibernate封装了对数据库的操作,不用写SQL了,精细优化也搞不定了。每次系统变慢,就得求DBA,帮看看有那些SQL被卡住了。每隔一段时间,还得请DBA导出SQL语句,研究怎么建索引。2.系统臃肿,学习周期长100多个接口,分为三个大项目。最大项目有1300多个类,其次是600多个和300多个类。SSH架构,SVN版本控制,resin作为容器,Nginx前置路由。路由这个让人欣慰,它是整个重构工作的有力支撑。纯后端的项目,为移动端app,PCWEB应用提供接口。这也使得重构工作难度大大降低。如果把前端也耦合进来,那就更酸爽了。庞大的系统规模为团队成员接手带来困难。支付业务独立出来后,开发人员从原来的5人,在2个月内扩充到10人。与此同时,兴奋的产品同学也都跟打鸡血一样,各种想法纷纷变为产品,开发压力骤增。但是新增的同学,看着几百个类,往往一片茫然,无法下手。不知道哪些功能实现了,哪些功能是待改进的。一直到3个月后,新员工才逐步进入角色。尽管如此,还是有不少恐龙级代码,无人敢挑战。最大的一个类的规模是2000多行,核心方法超过500行,大量重复代码,每次调整都以失败告终。3.合作成本高随着项目组人员增加,每次新版本开发都需要多人一起合作,修改同一个项目代码。虽然使用版本控制工具来对分支进行管理,但是不可避免的,大量的时间花费在代码冲突处理上。新增功能,增强功能,bug修复,支持各种客户端,都在一个项目上进行,需要建立不同的分支,高峰期五六个分支同时进行都是常见的。这种情况下,代码冲突的频率非常高。一个周的小版本开发,1天时间在解决冲突都是很正常的。4.测试难度大测试工作也逐步的恶化了。测试环境构建难度高。随着分支的增加,每个进入测试的分支,都需要准备独立的测试环境。环境构建成本高。刚测试完的功能,由于分支合并冲突处理,又得重新跑一遍。严重影响项目进度。5.上线风险高随着系统复杂度的增加,上线风险也越来也大。一个小功能的修改,打印一个日志,修复一个bug,都需要整体上线。一旦有一个地方修改错了,这个系统就崩溃了。上线时间长,一次上线,半个小时是必须的。6.引入新技术困难互联网公司对新技术的追求和使用显得特别饥渴,SSH框架降低开发难度和成本同时,也屏蔽了其他技术的导入。缓存机制,数据库优化,读写分离等,SSH有自己的一套逻辑体系,要调整姿势,成本相对高,技术难度也大,需要对实现底层有深入了解。CONWAY’SLAW很长一段时间,这个系统是2-3位开发人员在维护,对外接口、运营系统,都混杂在一起实现,访问量也不算大。3个独立系统,对应3个版本库,每个人负责1-2个系统。当有新功能添加到系统中的时候,大家优先考虑的是如何对现有系统进行改进,而不会考虑是否需要建立新系统。而当公司做业务调整,人员迅速增加后,原有的合作方式,就需要变更了。这就应了所谓的康威定律:Anyorganizationthatdesignsasystem(definedbroadly)willproduceadesignwhosestructureisacopyoftheorganization’scommunicationstructure.我们需要一套新的机制来应对新形式下的系统演化的需求。五、分层与共享库避免对原有系统作大规模调整,我们首先考虑的是利用原系统分层实现的特点,实现基于层的分工。在实践方面,以前负责的管理系统的开发项目,使用SSH架构的,大部分是采用基于分层的分工:将业务逻辑层、数据访问层、数据表示层封装为可以独立维护的库;将接口层按照业务来拆分,将代码依赖调整为库依赖。为各个独立的库和项目建立各自的代码库。层之间通过接口来交互,基础层通过单元测试来保证质量,这种分层的优势在于能够很好地解决学习周期的问题。每个层的技术相对独立,开发人员可以快速上手。DAO层相对简单,因而对于团队中的新手,可以从这个层入手,熟悉系统架构和软件过程;业务逻辑层是整个系统的核心,由老员工来负责,对上可以协助显示层的开发,对下可以指导DAO层的新同学。显示层需要对HTML,CSS等技术要有所了解。这种分工,适合10人以内的、一同办公的团队。团队之间是紧耦合的合作关系。对于大型项目,首先需要对项目按照业务进行切分,每个子项目分配到10人以内的团队来完成,之后对每个团队,采用分层的分工。但采用这种合作方式,存在的问题是:要求有很好的系统架构设计。需要在编码启动前,将各层的接口、数据库结构确定下来。而这对轻架构的互联网应用开发来说几乎是不现实的。不少互联网公司甚至都没有架构师的角色,有架构师的公司,还有不少是形同虚设的。团队内部沟通成本高。层与层之间是紧耦合的关系,对接口的修改必须通知到所有使用方。这要求开发人员之间建立稳定的合作关系,通过约定俗成的规则,降低沟通成本。上述各种问题仍然存在。基础库的变更,都需要对线上的系统更新库之后重新上线。六、微服务在开始支付项目改造之前,我们刚刚完成了公司数据仓库项目的微服务架构改进。这个项目实施详细过程,在dockone社区做了分享,详情参见这里。我们认为调整为微服务架构可以解决上述问题。1.性能问题对于性能要求高的接口,可以通过建立数据缓存的方式进行优化。2.学习周期一个项目仅包含少数紧耦合的接口,接口的业务逻辑单一,开发人员1-2小时通读代码,即可快速上手。3.合作成本每个项目相对独立,项目之间仅通过接口来交互。确定完接口后,开发、测试、上线,都是独立进行的,从而降低了沟通成本。4.版本控制由于项目之间是接口依赖而不是代码依赖,每个项目都可以建立独立的代码库。同时项目切分的比较细,每个项目开发时,仅会有一个开发人员对其做修改。这基本就不存在代码合并工作,也避免了代码合并过程中的各种问题。实际上,基于微服务架构的开发,我们并没有采用分支策略,而是直接用主干开发。5.测试难度每个项目独立部署、独立测试。由于消除了代码分支,没有代码合并的隐患,重复测试的工作量减少了。6.上线风险每个项目独立上线,就算出现问题了,也仅影响到少数接口。7.新技术在微服务改造进行一个季度后,各种新技术被引入到系统中,开发不再局限于SSH架构。Spark,Hadoop,Hbase等大数据处理相关的技术,Couchbase,Redis等缓存系统,都开始在项目中使用,并有效地解决的业务上存在的问题。当然,有利必有弊,微服务带来的问题,也不少,包括项目多、出问题时排查难等,在实施过程中,也积累了不少的经验。这些问题,将在后续的分享中逐步做介绍。
本文标题:从为什么要重构到微服务架构
链接地址:https://www.777doc.com/doc-4756092 .html