本文首发于InfoQ垂直公众号:聊聊架构,5年时间服务器从0到200,一个创业公司的架构野蛮生长史,转发于InfoQ公众号:一家创业公司的5年架构变迁史。
贝聊成立于2013年,是中国幼儿园家长工作平台,致力于通过互联网产品及定制化解决方案,帮助幼儿园解决展示、通知、沟通等家长工作中的痛点,促进家园关系和谐。贝聊是威创股份(A股幼教第一股)、清华启迪、网易联手投资的唯一品牌。在短短几年内,用户规模迅速达到千万级别,每年DAU均呈倍数级增长。面对如此快速的发展,原有的技术架构很难支撑越来越复杂的业务场景,在系统可用性以及稳定性方面,都给贝聊技术团队带来了很大的压力。因此,如何针对当前需求,选择合适的技术架构,保证架构平滑演进,值得我们深入思考。
贝聊架构总体经历了三次重大历程,由几台服务器搭建的单体架构到目前的几百台分布式部署架构,在整个变化过程中,我们踩过了很多坑,遇到过很多重大技术挑战。
诞生期—技术架构选型V1.0
创业初期,我们的初始创业团队在进行架构选型时,主要基于以下几点进行考虑:
1.在创业初期,研发资源有限,研发人力有限,技术储备有限,需要选择一个易维护、简单的技术架构;
2.产品需要快速研发上线,并能够满足快速迭代要求,现实情况决定了一开始没有时间和精力来选择一个过于复杂的分布式架构系统,研发速度必须要快;
3.创业初期,业务复杂度比较低,业务量也比较小,如果选择过于复杂的架构,反而会增加研发难度以及运维难度;
4.遵从选择合适的技术而不是最好的技术原则,并权衡研发效率和产品目标,同时创业初期贝聊只有一个PHP研发人员,过于复杂的技术架构必然会带来比较高昂的学习成本。
正是基于以上几点考虑,最终选择了经典的LNMP技术架构,贝聊V1.0架构就这样诞生了,为了加快产品研发速度,尽快上线产品,首期通过外包公司实现了研发以及部署,后续由我们的PHP研发人员接手,并进行后续的迭代开发。
初期部署时,部署了三台ECS服务器,其中接入层nginx与系统部署在同一台机器,RDS数据库一台机器,Memcached缓存一台机器,V1.0架构具有以下特点:
LNMP架构支撑贝聊业务发展了将近一年半左右的时间,简单、易维护的架构为贝聊的快速发展做出了很大的贡献,期间业务发展迅速,用户体量也越来越大,原有架构逐渐暴露出越来越多的问题。
成长期—技术架构重构V2.0
我是在2015年初加入了贝聊,初始研发团队只有三人,有幸在这一时期
主导了贝聊技术架构重构,并经历了贝聊后续的几次架构演进路程,将原有PHP单体架构重构为JAVA分布式架构。
首先谈一谈我们做技术架构重构的契机,重构并非难在怎么做,而是难在何时开始做,所以我们做架构重构的契机主要基于以下几点:
1.原有LNMP架构经历了两个团队研发和维护,外包团队和公司PHP研发人员,由于业务变化比较快,原有的数据库设计逐渐暴露出来很多问题,很多表设计不合理, 很多字段定义不清,比较混乱;
2.2015年,由于业务发展,贝聊app需要拆分为两个客户端:贝聊家长端和贝聊老师端,通过不同的客户端来服务不同的用户群体,达到精准运营的目的,如果在原有架构上继续进行开发,则会导致新旧接口逻辑混在一起,并且早期的很多接口定义不是很规范,维护起来越来越麻烦、越来越吃力;
3.原有API接口系统是单体架构,里面包含了各种接口,混合了各组业务逻辑处理,所有功能都集中在API接口系统中,代码非常臃肿,业务非常繁杂,迭代开发的速度也逐渐减慢,各种性能问题经常爆出,BUG也比较多,并且部署困难,任何修改每次都需整体部署。由于业务逻辑混杂在一起,新入职研发人员需要很长时间才能够完全熟悉系统,很难快速通过以点及面的方式切入系统;
4.所有数据存储在一个RDS数据库中,只使用了一个主库,没有从库,同时很多系统共用一个数据库,一方面数据库没有做到物理上的隔离,另一方面很多表都放在了同一个数据库中,经常会碰到一个慢查询或者其他性能问题,导致整个RDS各项指标飙升,造成雪崩效应,所有系统连锁出现故障,最终都不能访问;
5.公共服务耦合比较严重,很多第三方服务都散落在各个系统里面,不便于统一维护,当需要修改公共服务参数或者做其他调整时,需要深入到每个系统里进行修改或者排查,非常麻烦,还非常容易出现遗漏,最终产生BUG,急需独立拆分出公共服务,将公共服务从业务系统中解耦出来,由专人进行独立维护、独立部署;
6.我们新的研发团队都拥有丰富的JAVA分布式架构设计经验,拥有高并发、高可用经验,因此将原有的单体架构重构为JAVA分布式架构也是顺势而为。
由于公司业务高速发展,如果停下来专门做技术架构重构是不可能的,我们选择了在维护现有系统的基础上,同时进行新的技术架构重构工作。重构期间,在原有PHP研发团队的大力支援下,我们的重构工作还算非常顺利,既保障了业务的快速迭代需求,又成功完成了新的技术架构重构,新的V2.0架构如下:
在V2.0架构时期,初步实现了分布式部署架构,根据不同的功能以及业务逻辑,完成系统级别的拆分,同时对第三方服务进行解耦,拆分出了独立的服务模块,针对DB,我们实现了系统级拆分以及物理独立部署,并实现了数据库主从分离,同时引入了MQ消息队列,并使用SLB实现了负载均衡和带宽流量入口统一。
V2.0时期的架构具有以下特点:
系统拆分和DB拆分
针对系统拆分以及DB拆分,我们通过两个阶段来完成该项工作。
第一阶段
首先在系统层面进行拆分,将原有的大系统拆分出多个业务逻辑独立的子系统,而DB暂时不进行拆分,多套系统还继续共用一个DB,只是根据业务逻辑划分各个系统所依赖的表,不同业务逻辑系统之间不能互相访问表,这样新系统只访问自己所归属的表,通过此种方案,可以保证原有系统业务不受影响,同时新拆分的业务系统研发工作也可以顺利进行,此阶段大概花费了我们几个月的时间,最终顺利完成系统层面的拆分。
第二阶段
在完成系统层面拆分之后,我们紧接着实施DB层面的拆分,将各个子系统所依赖的表独立拆分出来,分别放置到不同的RDS数据库,实现物理的隔离,同时实现了数据库主从分离。最终实现效果如下图:
初步服务化
本阶段,我们采用了比较简单易用的Hessian实现初期的RPC服务化。针对第三方公共服务,从原有系统中解耦出来,独立拆分出服务化组件,并做独立部署,供其余业务系统统一调用。而系统间调用也通过Hessian来实现RPC远程调用。
SLB负载均衡
在V1.0架构期间,我们的Nginx都是单点部署,一旦一台Nginx服务器出现故障,则会波及到大量业务系统,风险非常大,如下图:
在V2.0架构期间,我们引入了SLB实现负载均衡,SLB配置了多台Nginx,同时在业务系统层面也实现了负载均衡,避免了单点故障,达到高可用的目的。
爆发期—微服务架构V3.0
进入2016年以来,贝聊业务高速发展,用户规模在短时间内增长数百万,同时各个业务线逐渐铺开,业务场景更加复杂,代码规模膨胀得也非常快,研发团队迅速达到了几十人规模,一个系统多人开发,研发人员层次不一,规范难以统一,同时业务逻辑耦合严重,每次上线都需要将整个大系统整体打包上线,风险非常大,并且新人入职之后学习成本非常高。因此我们引入了微服务架构,将业务逻辑拆分为独立的微服务组件,每个微服务都围绕着具体业务进行构建,由专人研发和维护,并由专人做性能优化和架构优化,各个微服务组件的研发与上线互不影响。
结合V2.0架构,在实施微服务架构时,基于多方面考虑,我们选择了Dubbo作为分布式微服务框架。
在做微服务时,我们考虑了以下几个关键点:
在实施微服务架构时,主要考虑从以下几个方面进行实施:
微服务拆分案例
1 班级动态微服务
贝聊的班级动态是一个高频率使用功能,园长、老师、家长都可以在班级进行发布动态,通过点赞、回复进行互动。随着贝聊业务飞速发展,用户规模爆发,每天都产生数十万的班级动态量,同时日回复量和点赞量均达到了数百万级别。面对如此大规模的数据量,我们一方面要应对高并发的性能压力,另一方面又要应对数据压力,原有的班级动态功能散落在API接口系统以及后台管理系统中,相关的表也与原有系统共享一个DB,迫切需要我们拆分出独立的班级动态微服务组件,同时还需要做分库分表减少单数据库压力。因此我们专门抽调精干研发人力,拆分出了班级动态微服务组件。
旧班级动态调用方式如下
班级动态微服务组件调用方式如下:
拆分出班级动态微服务之后,我们解决了以下问题:
2 用户通行证微服务
很多创业公司,在一开始发展时,为了追求速度,同时由于人力不足,都是将用户数据表与业务数据表暂时放在了一个DB里面,贝聊早期也是这样,这就造成了各个业务系统都是自己分别写DAO来获取用户数据,产生了大量重复的用户逻辑拷贝代码。随着业务发展的越来越快,越来越多的业务系统都需要访问用户数据,用户逻辑代码散落在各个业务系统,用户数据越来越难维护,复杂度越来越高,同时用户量越来越大,经常会遇到高并发性能问题,不容易做独立性能优化,因此拆分出独立的用户通行证微服务迫在眉睫。
旧用户数据获取方式
用户通行证微服务
拆分出用户通行证微服务之后,我们解决了以下问题:
微服务治理
微服务架构开发、测试、部署复杂度远远大于单体架构,因此需要构建能够支撑微服务架构的交付和运维能力。
1 版本发布系统
微服务架构的应用开发、部署的复杂度都是远大于单体架构应用的,大量的微服务组件如果依然靠运维人员手工的配置管理显然是难于应付了,因此我们研发了自动化部署和发布的版本发布系统,我们的版本发布系统具有以下特性:
通过版本发布系统,实现代码版本管理、一键部署上线、一键快速回滚、上线单申请、上线审核以及上线日志等。
2 开发测试发布部署
针对微服务复杂的架构,为了保证每个微服务交付的质量,我们部署了四个环境:
通过以上四个环境,确保微服务组件的研发、测试、发布的质量。
3 分布式配置中心以及分布式任务调度平台
随着微服务架构的实施,我们拆分出了很多的微服务以及子系统,各种配置信息都以明文形式配置在配置文件中,同时各种定时任务也散落在各个微服务以及子系统中,非常难管理。因此我们选择了合适的分布式配置中心以及分布式任务调度平台
4 全链路跟踪
微服务架构拆分了大量的子系统以及微服务组件,面对如此复杂大规模分布式集群,一次链路调用可能会发生在多个微服务组件之间,如何进行链路调用追踪,如何快速发现一次接口调用过程中哪些地方需要优化、哪个微服务接口导致了整体调用比较慢。针对上述问题,我们引入了美团点评的APM工具Cat实时监控系统,与Dubbo服务化框架进行整合,通过全局链路ID,实现链路追踪功能。
5 微服务授权
默认Dubbo没有实现服务授权功能,系统调用微服务、微服务之间调用均没有实现授权验证,都是直接访问微服务组件接口,因此我们针对Dubbo进行了个性化定制研发,研发了微服务授权认证中心,通过授权认证保证核心微服务接口的调用安全性。
6 微服务监控
拆分出大量的微服务组件,我们面对的是如何监控这么多的微服务运行状态,我们采用了Dubbo自带的简易监控中心,监控微服务组件的成功率、失败率、平均耗时、最大耗时、并发量等指标,通过这些指标发现微服务性能瓶颈,进而优化微服务性能。同时我们进行个性化定制扩展与研发,针对Dubbo接口调用,统计接口耗时排行、接口失败排行、接口访问异动排行等等,通过定制化研发的统计报表,更直观的监控Dubbo接口性能。
7 微服务管理
我们使用Dubbo的管理控制台,实现对微服务的路由规则配置、访问控制、权重调节、服务降级、服务禁用、容错等功能,可以非常方便的管理运行中的微服务组件。
经过一年多的微服务化历程,V3.0架构如下:
V3.0微服务架构具有以下特点:
V3.0架构虽然实现了微服务架构,但该架构还存在以下可以继续演进的点:
架构演进一直在路上,架构要围绕业务进行,不能脱离于业务,不同的业务时期需要不同的架构。
单体应用架构,更适合创业初期,公司需要快速试错以及验证市场反应,需要更快的研发速度,同时研发人员比较少,而单体应用架构比较简单,可以快速切入,对研发人员的技术栈要求不是特别高,可以快速上手快速研发,但在设计单体应用架构时最好可以提前规划好未来的扩展性,可以在业务层面先规划好,便于日后业务发展到一定规模,可以快速进行解耦,实施微服务化架构。
当企业发展到一定规模,业务线变的越来越多、越来越复杂,同时研发人员的数目也快速增长,单体应用架构就会慢慢暴露出来弊端,大量的研发人员在一个系统上进行开发,缺少并行研发能力,大量的业务代码耦合在一起,同时研发效率非常低。微服务架构可以更好的进行业务解耦,具备更好的扩展性以及独立性,可以提高研发团队间的并行化研发速度,提升效率、提高模块复用性,具备高可用、高并发特性。但微服务架构对服务治理的能力要求比较高,维护成本也会比单体应用高,需要强大的服务治理支持,对研发人员的技术能力要求也比较更高。
目前我们依然在架构演进的路上,经历了以上几次架构历程,虽然取得了一定的进步,但依然有很多挑战等待我们去迎战。规划技术架构需要综合考虑业务的规模、业务的时效性、研发团队的规模、研发的技术能力、基础环境配置等。架构来源于业务,架构演进的生命周期只有完美匹配好业务的生命周期,才能最终发挥出最好的效果。