是什么?
架构的本质
架构的本质就是打造对业务和技术变化友好的有序系统。
系统由要素和连接关系组成,通过合理的“分”与“合”,把原先铁板一块的系统变成一个富有弹性的结构化系统。这样,系统的复杂性有效地分解了,系统的有序度大幅度地提升了。
架构的分类
一般来说,主要分为业务架构和技术架构。
开发的痛点主要由业务架构来解决,机器的痛点主要由技术架构来解决。
业务架构
就是讲清楚核心业务场景的处理过程,给出业务模块的划分(应用)和依赖关系(应用调用)。
技术架构
就是保障应用的稳定运行。
好的架构师
为什么?
使系统配置和功能完整一致正交、高性能、高可用、高扩展、高安全、可监控、能耗低
怎么样?
配置和功能完整一致正交
划分服务边界时,要保证服务配置和功能完整,这样才能支撑一个完整的业务领域;服务的配置和功能要一致,谁拥有配置,谁就负责提供相应的功能;如果是基础服务,它们处于调用链的底层,服务之间不会有任何的调用关系,它们之间是正交的。
高性能
常用性能数据
降低响应时间(处理一个信息的时间)
优化处理单个请求路径上每个节点的处理速度
短事务;使用更好的算法和数据结构;通过缓存来代替数据库访问;通过索引,优化数据库查询。
并行处理单个请求
计算可并行,把一个请求分解为多个子请求,内部使用多个节点同时处理子请求,然后对结果进行合并。这个在很多情况下并不可行,例如MapReduce 也有使用场景的限制。
提高吞吐率(单位时间内处理信息的总量)
同时处理多个请求
同一个节点内部,利用多进程、多线程技术;水平扩展多个实例(无状态和有状态(往往需要很大改造))。
请求处理异步化
通过消息系统对流量进行削峰,系统先把请求存起来,然后再在后台慢慢处理;在处理核心业务时,把相对不核心的逻辑做异步化处理。
会导致处理结果不能实时返回,有时候会影响到用户体验,而且对程序的改造也会比较大。
高可用
业务架构
此处高可用更多地指可复用。
复用的分类
技术复用
代码级复用。这里包括自己打包的类库,第三方提供的 SDK,还有各种算法封装等。我们的代码可以直接调用它们,物理上也和我们的应用打包在一起,运行在同一个进程里。代码级复用是最低层次的复用,可以把它当作你自己源代码的一部分。
技术组件复用。这些组件有自己封装的,更多的是大量开源的中间件,比如 Redis、MQ、Dubbo 等;组件也包括各种开发框架,比如 Spring Cloud。这些基础组件技术复杂度很高,它们的存在,极大地简化了我们的开发工作。
业务复用
业务实体复用。针对细分的业务领域,比如订单、商品、用户等领域。它对各个业务领域的数据和业务规则进行封装,将它变成上层应用系统可以直接使用的业务组件。
业务流程的复用。针对的是业务线,它可以把多个业务实体串起来,完成一个端到端的任务。比如说,下单流程需要访问会员、商品、订单、库存等多个业务领域,如果我们把这些调用逻辑封装为一个下单流程服务,那下单页面就可以调用这个流程服务来完成下单,而不需要去深入了解下单的具体过程。相比单个的业务实体复用,业务流程的复用程度更高,业务价值也更大。
整个系统的复用。比如说一个 SaaS 系统(Software-as-a-Service),它在内部做了各种通用化设计,允许我们通过各种参数配置,得到我们想要的功能;或者说一个 PaaS(Platform-as-a-Service)平台,它会提供可编程的插件化支持,允许我们“嵌入”外部代码,实现想要的功能。
从技术复用到业务复用,越往上,复用程度越高,复用产生的价值也越大,但实现起来也越复杂,它能复用的场景就越有限。
技术架构
衡量标准
系统正常工作的时间除以总体时间。通常用几个 9 来表示,比如 3 个 9 表示系统在 99.9% 的时间内可用,4 个 9 表示 99.99% 的时间内可用,这里的正常工作表示系统可以在相对合理的时间内返回预计的结果。
故障点
故障点可以归纳为三类:
资源不可用。包括网络和服务器出故障,网络出故障表明节点连接不上,服务器出故障表明该节点本身不能正常工作。
资源不足。常规的流量进来,节点能正常工作,但在高并发的情况下,节点无法正常工作,对外表现为响应超时。
节点的功能有问题。这个主要体现在我们开发的代码上,比如它的内部业务逻辑有问题,或者是接口不兼容导致客户端调用出了问题;另外有些不够成熟的中间件,有时也会有功能性问题。
架构原则
处理线上事故的首要原则是先尽快恢复业务。
正面保障
第一个设计原则是冗余无单点(主备)。
很多成熟的 HA 方案,比如可以选择 Nginx、HAProxy、LVS 等负载均衡软件,能很好地支持双节点 +Keepalived 部署;提供多条通信线路;机房层面的冗余;数据库有成熟的 MHA 方案,支持主库故障时,能够自动实现主从切换,应用可以通过 VIP 访问数据库,因此这个切换过程对应用也是透明的;Redis 本身就支持集群方式,通过数据的多副本来支持故障转移; Kafka通过数据的多分区,实现故障的自动切换,保证系统的可用性。
第二个设计原则是水平扩展(主主)。
很多时候,系统的不可用都是因为流量引起的:在高并发的情况下,系统往往会整体瘫痪,完全不可用。
对于无状态的计算节点,比如应用层和服务层来说,水平扩展相对容易,直接增加机器,进行健康检测,及时剔除失效节点,如Eureka;对于有状态的节点,比如数据库,我们可以通过水平分库做水平扩展,不过这个需要应用一起配合,做比较大的改造。
Redis 本身就支持集群方式,它可以通过多节点支持处理能力的水平扩展; Kafka通过多节点部署来支持处理能力的水平扩展。
减少损失
第三个原则是柔性事务。
在 CAP 理论中,系统的可用性、一致性和网络容错性,三个最多只能保证两个,在分布式系统的情况下,我们只能在 C 和 A 中选一个。
在很多业务场景中,系统的可用性比数据的实时一致性更重要,所以在实践中,我们更多地使用 BASE 理论来指导系统设计。在这里,我们努力实现系统的基本可用和数据的最终一致。
柔性事务具体的实现方式有很多,比如说,通过异步消息在节点间同步数据。当然,不同的方式,对 C 和 A 的支持程度是不一样的,我们在设计系统时,要根据业务的特点来决定具体的方式。
第四个原则是系统可降级。
限流:让部分用户流量进入系统处理,其它流量直接抛弃。
在 Nginx 中设置每秒多少个并发的限制,超过这个并发数,Nginx 就直接返回错误。
降级:系统抛弃部分不重要的功能,比如不发送短信通知,以此确保核心功能不受影响。或者针对具体的功能,我们设置好功能开关,让代码根据开关设置,灵活决定是否执行这部分逻辑。比如商品搜索,在系统繁忙时,我们可以选择不进行复杂的深度搜索。
熔断:我们不去调用出问题的服务,让系统绕开故障点,就像电路的保险丝一样,自己熔断,切断通路,避免系统资源大量被占用。比如,用户下单时,如果积分服务出现问题,我们就先不送积分,后续再补偿。
Spring Cloud 的 Hystrix 组件(开源熔断框架)
高扩展
业务架构
对业务变化友好。
面向业务线和业务流程,通过拆分,实现模块划分;通过整合,优化模块连接关系。如果系统拆分整合得合理,模块就具有良好的封装性,模块定位明确,连接关系清晰,当业务变化了,只要调整相应模块的内部,而它的功能接口基本不变,做到对业务变化友好。
拆分
先考虑垂直拆分,从大方向上,把不同业务线区分清楚,再针对具体业务线,将业务处理流程在业务域的维度进行水平拆分。
整合
通过整合,对多个模块进行包装,形成更大粒度的抽象,相当于减少了模块的数量;模块的定位更明确,连接关系也更清晰;新的业务线进来,它可以基于业务平台快速落地。
技术架构
对资源需求变化友好。
借助虚拟化和容器化技术,可以方便实现节点和系统级别的伸缩。
节点级别的伸缩
对于无状态的节点,直接手动/自动增减节点就可以;对于有状态的服务,需要能够支持状态数据的重新分布。
系统级别的伸缩
系统是一个整体,可以把多个处理节点打包在一起(可以是整个系统),形成一个资源处理能力分配合理的处理单元。这样可伸缩能力就更高了。
高安全
可监控
对系统状态变化友好。
无论采取了多么强大的高可用措施,还是不能充分相信系统,还需要借助额外的监控来及时发现系统的问题并加以解决。监控是第二条保命措施。
Metrics监控
健康检查
某个应用是否存活。
调用链监控
日志监控
结构化:k-v形式或json形式,直观,方便查询
非结构化:就是一个字符串
能耗低
当业务低谷时,可以快速地减少系统资源,保证系统的低能量消耗。
每台机器提供合理的性能,以便减少机器,从而降低能耗。
实现了系统的高性能和可伸缩,就表明已经最大限度地利用了机器资源,那么能耗低就是自然的结果。
特别鸣谢:
1、得到平台刘润老师
2、极客时间平台杨波老师
3、极客时间平台王庆友老师