架构本质总结(二)

本来计划写作不是日更的,但是既然能有时间来写,那就坚持日更吧。加油!

上一篇文中,总结了下架构的本质和目的,以及架构演化原则最普适的手段:。今天就字来看,我了解的架构到底是怎么来拆的。

梳理

在我理解中,程序=计算+数据,也就是说我们的系统组成部分要么承担的是数据存储,要么承担的就是程序计算或者是业务逻辑编排。

因此以我的总结来说,引起我们架构演化的核心就是提示业务的处理能力或者提高数据的存储能力

下面,本文就先从处理能力瓶颈来描述,从最原始的单体单机部署的应用来一步步梳理引起系统需要拆分的原因以及如何实现。原始设计如下:

单体单机设计.png

第一步、冗余应用服务

在这个架构下,最容易出现能力瓶颈的是Process的处理能力,次时,我们需要做的就是将Process冗余部署来分担请求。这时,我们实施的就是拆分请求,将原来落到一个Process的请求,拆分到多个Process。

要实现应用可以冗余部署,这时架构要保证的是以下两点:

  • 应用服务是无状态的(对等),这样我们才可以水平的扩容。
  • 扩容后,需要在Process前置一个负载均衡系统来实现请求的分发。
单体冗余设计.png

第二步、数据读写分离

在上一步完成后,我们的Process的处理能力就暂时不是能力瓶颈了,但是系统中的数据库却仍是单点的,若流量进一步提升,数据库的存储能力就成为新的瓶颈。

这时候,个人认为最有效最快速的方式就是读写分离。从二八法则来看,一般一个系统有八成的请求都是读请求,在读请求中,一般有较大一部分的请求是对数据一致性没有强制要求的。这时,我们实施的仍然是拆分请求,将读写请求拆分到主和从库。

读写分离后解决的最大问题就是,主库只要负责写请求以及部分强一致性的读。而读请求就可以使用加从库的方式来横向扩容。


主从设计.png

第三步、数据缓存

系统做了读写分离后,大部分的系统都能支撑比较长的时间了。下一步,我们更多可以考虑的是能否进一步的减小数据库请求。这时,就可以根据具体的业务来将实时性要求不高数据提炼到离用户更近的地方。

而内存相比数据库的文件来说,是更加靠近用户的,性能也是更高的。因此就可以将数据缓存到Reids等第三方缓存系统,或者将数据缓存到Process的内存中(要解决一致性问题),甚至将数据缓存到机器外部缓存(CDN)。此时,我们实施的其实还是拆分请求,将请求分别拆分到缓存和数据库。

缓存设计.png

第四步、MQ异步化

上述两步解决的跟多的是读请求的拆分,而写请求,仍然是单机的数据库。当数据库出现写压力后,我们除了拆库之外,还有什么手段能提升数据库的处理能力呢?

这时候,我们可以引入消息中间件(MQ)来进行流量的削峰。简单来说MQ能实现写性能提升是因为将对数据库的随机访问变为串行化访问,我们就可以将没有强一致性要求的写请求都先发送到MQ,有订阅线程持续消费处理。此时,我们实施的依旧是拆分请求,只不过拆分的是写请求。

MQ设计.png

第五步、数据库拆分

假设我们经过上述四步后,服务的性能仍旧无法解决,我们需要考虑的就是要进行数据的拆分了。当服务量和写请求量上来后,数据库单机的瓶颈就是一个必须解决的问题了。

通过拆分数据,从而最终达到的还是拆分请求的目的。

数据库拆分的好处和问题就不多说了,顺便说下个人了解到的比较常用的两种分库路由策略:

  1. id取模,扩容时双倍扩容,可以避免数据迁移和停机。
  2. 基因法,比如将用户和用户的商品路由到同一个数据库,从而避免跨库关联。

第六步、限流降级和熔断

有时,系统需要应对突发的流量激增场景,这时候,无限的扩容服务或数据就不是合适的解决方案了。这时候,我们要做的更多的时保护我们的系统仍然能服务部分用户。

为了保护我们的系统服务,我们要做的就是入口做限流,服务内部做降级,以及对下游服务做熔断。

通过上述三种手段,我们做到了拆分请求,将重要的请求留下,不重要的请求延迟或不处理。

梳理的可能条理不是很清楚,后续再来整理一下吧。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。