活动主持人

个人签名

169篇博客

360°透视:云原生架构演进

活动主持人2020-03-24 17:25

目前,互联网企业随着业务的发展不断前进。因此,不同的阶段有不同的需求,所以需要使用不同的方法来聚焦不同的目的。比如初创型的企业需要抓住合适的机遇快速进行原型验证,证明大的方向没问题才有可能进一步发展。因此技术一般是为了满足业务的发展和验证而设计,只要保证共用的组件能够复用就可以。只有随着业务的进一步发展,组织架构及人员的规模越来越大,企业才有机会发展成中型或独角兽公司。然而协作人员数量的增长也意味着新的问题,一般而言,只要企业的人员规模超过150人,就会带来极大的管理成本提升。在这一阶段,技术不仅需要和产品进行更充分的结合,还需要规范化和工程化操作。当规模再次扩大的时候,如果只是简单的人力堆积,协调性问题是无法解决的,企业需要更高效的架构才能支撑和反哺业务的发展,工具和流程需要更加自动化才有可能保证业务的持续发展,边际效应非常明显,同时挑战也更大。
总之,在任何阶段,技术的演进都是一个非常重要的过程,这一点在以技术为导向的公司尤为凸显。技术超前就有可能成为先行者,技术落后就有可能导致企业发展缓慢,机会丢失。
无论是个人开发者还是技术公司,如果目的是持续运行和发展,就需要一套良好并固定的制度,同样,在技术上,团队的持续前进离不开项目的工程化思维。开发、测试、发布的软件生命周期的高效管理必须依赖工程化,它是研发协作与云端运维的基础。这里面包括许多问题,需要技术人员去解决,比如:追求技术的先进或业务需求的合理性评估,可能是很多公司技术管理需要根据组织架构权衡的问题。一般来讲,任何从零起步的公司都会经过不同的技术发展阶段,包括简单的初创期、快速增长期及分布式的服务化架构阶段。每个阶段对应不同的产品和业务需求,技术承担不同职责,需要技术人员来决策,特别是需要架构师首要思考的问题。
初创期架构
通常来说,创业公司在开始新业务的时期,基本处在试错或原型验证阶段,这个阶段更多是关注业务的本身是否有前景或商业模式,而不会把非常多的精力放在技术的系统架构上,尤其是对于非技术型或不确定型的项目立项阶段。尽管很多技术人员也预料到前期需要很多时间去好好设计系统,才能保证支撑后续可能的业务快速发展,但往往由于时间成本或人力等原因而无法很好地执行。
一般来讲,创业型的项目对时间的要求非常苛刻,基本需要在3到6个月时间内完成系统的上线,否则有可能由于业务无法快速上线验证,导致无法获取相关的原始数据进行下一个目标验证,更严重的有可能造成资金链的断裂。罗马不是一天建成的,因此这个阶段会使用相对简单的架构方式来进行设计,本节先从最主要的几点进行说明,更详细内容请参考第3章。
单体架构
对于创业型公司来说,由于人才、技术、资金等重要因素的影响,同时,技术人员为了配合产品的需求,会采用最简单的架构来完成最原始阶段开发。根据我们接触的不少用户,有些企业甚至考虑成本因素,只使用一台服务器或者容器服务。另外,传统官网、论坛等应用,由于早期的设计采用了单体架构来实现,只需要一台服务器或容器来服务即可。对于其他的应用服务器、数据库、静态文件等资源,也是部署到同一台服务器或容器上来服务。最简单的架构模型如图1-11所示。

图1-11 最简单的架构模型

对于早期的单体应用模型,应用服务+数据库服务基本上就组成了最原始的架构模型,技术人更多会考虑技术的选型,包括编程语言、版本管理、数据库的类型等。比如PHP的开发者选择PHP+MySQL,Java的开发者采用Tomcat+MySQL等开发方式。
服务器分离
根据线上运行经验,一般的业务的类型,如果每日的用户访问量在百万之内PV级别,只要进行简单的Web应用性能参数调优、数据库索引优化等,基本上就能保证服务的稳定运行。当然,如果随着访问量的不断增加,部署在同一台服务器上的应用及数据库等服务应用,会和服务器的CPU/内存/磁盘/带宽等系统资源竞争,从而相互影响。显然很容易出现性能瓶颈,如果这台服务器出现了宕机或无法恢复的情况,就有可能会导致全站不可访问或者数据丢失等情况,造成的后果非常严重,因此大部分产品会将Web应用服务器和数据库服务器进行物理分离,独立部署,相互热备提供服务,只需要增加很少的成本,就能解决对应性能和数据的可靠性等问题。
初期由于各种条件存在,不能很好地进行新项目前景的预见,技术人员如果能在最小成本的情况下保证架构的合理性,还能很好地服务产品功能需求,甚至只要在部署架构上稍做调整,就可以防止出现灾难性的问题,这其中也包括很多技术架构上的考虑。
业务模型
一般而言,现阶段的业务比较简单,产品也比较单一,业务会随时根据其运营数据进行调整,因此,这时需要技术人能够较好地把不同的模块分离出来,对于偏业务相关的功能,需要有较好的心态接收随时变化的不确定性,对于后续可能复用或大量依赖的工程,需要进行较好的设计,否则可能在业务爆发时导致业务开发的进度越来越慢,甚至阻碍业务的发展,造成业务时常中断。即使有人力或时间来对系统进行重新设计,也会令技术人员产生抵触心理,同时也会引入较高的风险。因此,基于云原生应用的设计模式在最基础的阶段对架构也有很大的作用,包括考虑如何使用云的弹性,将不可变优势融合到系统的设计中。合理的业务模型分界也是确保后续能发展的重要步骤之一。
总而言之,在早期项目原型验证或者快速试错阶段,采用单体架构具有很大的技术优势,产品的想法也在项目的初始阶段就能进行比较好的迭代开发,发布和部署也比较灵活。然而,随着业务的增长,如果架构还是一成不变的话,带来的技术风险就越来越高,比如,代码行数的增加影响技术人员的学习成本、业务的变更速度、业务的可靠性、安全性及工程变大后的发布效率等,每次修改都必须反复测试,否则全站随时可能不可用,导致业务中断或者丢失市场的机会。因此,这部分的技术债务必须在业务快速发展的同时,进行技术架构的改造,使其能保证后期业务的支撑。所以,除了业务的发展判断外,对开发人员的技术能力储备和架构远见判断也将成为考虑的事情之一。
快速成长期架构
接下来,初创公司随着业务的进一步发展,比如当访问人数到达十万日活(UV)的时候,通常也是最关键的时刻,既要保证业务的稳定运行,又要进行产品的快速迭代。到了这个阶段,由于业务模式得到了一定的验证和反馈,有可能会出现很多竞品或友商。一方面,随着风险资本的注入,会依赖更有质量的数据进行发展运营,另一方面,竞品的出现又导致了市场的加速前进。因此,如何在调整期保证业务与技术的和谐发展是考验架构是否足够灵活的指标之一,同样,本节主要说明几点,更详细内容请参考第4章。
前端加速优化
首先基于浏览器端应用或者移动端应用,随着请求的不断增加,偶尔会看到Web服务出现性能瓶颈导致请求变慢或者失败。除去服务器本身的配置低外,更有可能由于架构设计或分离的原因,大量的Web并发请求被堵塞或者变慢,原因无非是服务器的CPU、磁盘I/O、带宽竞争激烈,导致相互影响。这时候我们就需要对架构进行前后端分解,合理配置或转发请求,如果是前端的服务请求来不及处理或者有瓶颈,可以将图片、JS、CSS、HTML及应用服务相关的静态资源文件存储通过Nginx本地代理或者对象存储服务来进行物理加速,使用不同的域名来转发请求,并通过CDN将静态资源分布式缓存在各个节点实现“就近访问”,主动或被动刷新CDN的缓存来加速前端服务。如果是后端的动态请求压力过大或者有热点服务,可以把无状态的后端的服务再进一步水平扩展满足业务分担,有状态需要判断是否能通过垂直扩容来服务,否则只能进行代码、架构设计或者业务规划的调整来优化。一般而言,通过将动态请求、静态请求的访问分离(“动静分离”),能有效解决服务器在CPU、磁盘I/O、带宽方面的访问压力,当然,这需要在架构设计时采用一些方法来进行调整。
水平扩展
在上节中提到垂直扩容能解决部分的问题,但由于业务和流量的快速增长及垂直资源有限,不同的应用场景需要依赖不同的策略分流,比如长连接的应用会依赖于4层的网络连接,互联网应用通常采用7层的模式来完成,甚至在游戏场景中,依赖UDP进行通信。为了更多地分担服务器的压力和保证业务的高可用,负载均衡技术通常是这个阶段解决问题的一个方法,通过增加多台后端服务器就可以实现分流的功能,分流设计也面临很多原则与技巧,比如分流的路径、权重等,负载均衡承担的角色也决定了后端的应用架构,比如无状态化设计才能实现水平扩展,另外还要考虑业务是否有亲缘性,同时在后端服务出现异常的情况下,自动进行健康检查,异常的服务能及时进行下线操作,快速失败。
数据库及缓存优化
数据库和缓存配合使用是解决后端结构化数据与非结构化问题的有效手段,根据不同的场景,要明白哪种数据使用结构化数据合适,哪种数据使用非结构化数据更合适,以及哪种方式在保证性能较好的情况下成本又可以接受。同时,如何在数据库和缓存之间进行过渡也是需要考虑的,比如数据在更新的时候,如何保证缓存的一致性,如何保证热点数据一直被访问,提高缓存的命中率等。另外,当大量用户访问不存在的数据时,也有可能导致后端的压力非常大,甚至有可能造成雪崩效应。
每种服务独立承担对应的功能,各司其职,并且根据应用的特性区别提供不同的服务能力,比如应用服务器提供用户的接入服务,数据库服务专门承担结构化数据的存储,缓存承担或非结构化数据(KV值对)的存储等,如果要提供搜索的功能,还需将数据进行分词、索引、检索等,不同服务器根据业务的功用需求来提供对应的服务,如图 1-12所示。
在这个阶段,除了必须保证满足业务的功能型需求,还要更多考虑非功能性需求,比如,通过前端负载均衡提供业务分流的能力,根据用户的特征进行不同的流量转发;数据库提供主备的能力,两者之间通过数据同步进行数据备份,当主数据库发生故障后,应用可以自动切换到备份的服务器来为用户提供服务;在用户体验方面,可能会引入缓存、CDN等基础服务来提供性能加速。

图1-12 数据库及缓存优化


分布式服务架构
一般而言,企业经过前面两个阶段的发展,就基本确定了业务的发展方向,接下来只要面对竞争对手的跟随和大量用户访问请求的问题。这些企业也会提供各种不同的子产品模块功能来满足业务的多样性发展,比如产品会设计不同的产品功能体系,运营人员会设计不同的运营活动,客服人员会接到不同的用户反馈等。这些需求叠加在一起,会导致整个业务越来越复杂,有些系统变得不再具有维护性,无法满足可用性的需求,只要一出现流量高峰,系统必定宕机,所以很多公司面临重构架构设计,甚至推翻重来,比如京东大部分的用户业务从.NET转到Java语言的重构,淘宝从PHP转到Java,升级2.0,再到3.0的架构转变,可以看到,这个时间点的转型或重构可能不会到生死攸关的地步,但其成本是非常高的。因此,如何在一开始就能做好这种转变的预见性,对技术的要求有相当大的挑战,本节先给出几点供读者来参考,更详细内容请参考第5章。
业务需求
通过云服务通常可以解决很多架构层面的问题,比如对象存储系统解决了文件分布式存储的问题,CDN解决了静态资源访问的性能问题,但实际上随着业务的不断发展,系统访问压力增大,还可能有很多的请求变慢或者超时,应用服务器或数据库服务的压力波动较大,只要不停地上线新业务,技术债就会越来越明显,业务的迭代也越来越跟不上产品需求。为了解决这些问题,企业往往需要进行各种业务的拆分,把不同的功能模块拆分到不同的服务器上进行独立部署。比如用户模块、商品模块、购物车模块、订单模块和支付模块等,这些模块拆分并独立部署出来后,可以再进一步根据系统的瓶颈进行细分。但是进行服务拆分之后,各模块之间的依赖又变得明显起来,比如数据库的连接数、数据的分布式事务、数据库的性能开销等都是急切需要解决的问题。
同时,随着业务模块的拆分,除了上述的技术问题要解决外,还面临着工程实践的问题,比如在业务的不同分支中,需要保证开发人员、测试人员、运维人员快速地开发环境、测试环境、预发布环境的搭建和发布。在高速发展的企业中,迭代的频率非常高,以网易考拉平台为例,所有系统的日发布总次数到达数千次,所以技术人员对效率的要求极高。当扩大到一个公司多个产品线,整体的运行就要求像现代化工厂一样来运作,需要自动化的能力平台去解决,纯手工根本无法满足企业的高效运转。
弹性扩容
随着需求和用户的不断增长,系统会出现波峰和波谷,为了更好地利用资源和成本预算,弹性扩容成了必要需求,在峰值的时候能够根据业务的压力自动扩容,分担流量,在压力低的时候自动缩容,减少成本或提高资源的利用率,把缩容的资源做离线业务计算。也许在过去是简单地通过垂直扩大规模能力来处理更多的需求,或者是购买更强的服务器,这在一定程度上是可行的,但过程很慢并且代价庞大,通过提前准备过多的资源,会导致只根据峰值使用量预测来规划能力值,比如根据服务器的最高计算能力购买硬件予以满足,这是不得已的做法。例如国外的黑色星期五、国内的双11等活动,当天请求非常高,需要足够的资源来满足业务请求,而平时这些服务器的使用率很低,所以,只有依赖云的弹性才能满足这种业务场景的需求。
服务化
不管是互联网还是传统行业转型的企业,基本都是在原有基础业务上发展而来的,不可能把业务停止从零开始,因此,直接对原有系统进行微服务改造比较困难,风险也较大。这时基本上处于一种混合架构期,即新的业务会从头开发,逐步接入到老系统中,一步步替换老系统不满足的地方,通过不断地快速迭代来保证业务的可持续性,同时又保证新业务的快速需求。著名的架构大师Martin Fowler从2013年正式提出微服务架构的综述文章至今,都没有提供统一的最佳实践方案。现在微服务的架构实现方式也各种各样,通常根据应用的类型拆分成不同的微服务来实现,每个服务根据业务的特征采用不同的技术栈进行组合,把每个服务划分成可以独立部署的隔离进程来运行。目前,微服务的基本框架都类似,比如包括服务发现、降级、治理等方面。业务实现微服务的技术细节各不相同,没有统一的实现方案,比如服务发现有自建服务基础设施的,也有依赖第三方开源的,技术人员需要根据自己的场景来做选择。简化的架构模型如图1-13所示。

图1-13 服务化架构模型


显然,这个架构模型只是整个业务服务架构的一部分,实际的系统可能要复杂几十倍。如果业务的迭代速度非常快,同时每个业务之间的依赖从设计、开发、测试、上线到运维都是一个非常庞大的复杂工程,因此,如何高效管理所依赖的服务和系统依赖,诊断并及时对业务反馈响应是对服务架构的考验。