首先需要明白的是,架构设计是一种平衡,所有的架构方案一旦脱离了它所适应的场景,一切都将是空谈。所以说到架构设计我们只说指导方向,你应该尽量往这些方向上去参考,但也要结合实际业务情况考平衡其他因素。
所有的高性能架构设计其实无非主要解决的考虑以下三个问题:
并发读:并发读的核心优化理念是尽量减少用户到服务端来读数据,或者让他们读更少的数据 并发写:并发写也是同理,尽量减少写的次数和写的数量量 兜底方案:另外,我们还要设计一些兜底保护方案,防止意料之外的情况发生
一般而言,在整个用户请求路径上从浏览器到服务端我们有以下几个原则,注意以下我们只说原则不说具体方案:
1)减少数据量:首先是指用户请求的数据能少就少,因为首先这些数据在网络上传输需要时间,其次不管是请求数据还是返回数据都需要服务器做处理,而服务器在写网络时通常都要做压缩和字符编码,这些都非常消耗 CPU,所以减少传输的数据量可以显著减少 CPU 的使用。常见的思路就是减少页面上不必要的展示信息
其次,还要求系统依赖的数据能少就少,业务数据一般是和后台服务以及数据库打交道的,调用其他服务会涉及数据的序列化和反序列化,而且数据库本身也容易成为一个瓶颈。
2)减少请求量:这里的请求可以指 API 请求,也可以指浏览器渲染锁需要的额外请求比如 CSS/JavaScript、图片等。这些请求都应该尽量少,因为浏览器每发出一个请求都多少会有一些消耗,例如建立连接要做三次握手,有的时候有页面依赖或者连接数限制,一些请求(例如 JavaScript)还需要串行加载等。另外,如果不同请求的域名不一样的话,还涉及这些域名的 DNS 解析,可能会耗时更久。总之,减少请求数可以显著减少以上这些因素导致的资源消耗。
3)缩短请求路径:所谓“路径”,就是用户发出请求到返回数据这个过程中,需求经过的中间的节点数。通常,这些节点可以表示为一个系统或者一个新的 Socket 连接(比如代理服务器只是创建一个新的 Socket 连接来转发请求)。每经过一个节点,一般都会产生一个新的 Socket 连接。然而,每增加一个连接都会增加新的不确定性。从概率统计上来说,假如一次请求经过 5 个节点,每个节点的可用性是 99.9% 的话,那么整个请求的可用性是:99.9% 的 5 次方,约等于 99.5%。
所以缩短请求路径不仅可以增加可用性,同样可以有效提升性能(减少中间节点可以减少数据的序列化与反序列化),并减少网络传输耗时。缩短访问路径有一种有效的方法,就是将多个相互强依赖的应用合并部署在一起,把远程过程调用(RPC)变成 JVM 内部之间的方法调用。
4)减少依赖:所谓依赖,指的是要完成一次用户请求依赖的系统或者服务,这里的依赖可以分为强依赖和弱依赖。举个例子,比如说你要展示秒杀页面,而这个页面必须强依赖商品信息、用户信息,还有其他如优惠券、成交列表等这些对秒杀不是非要不可的信息,这些不影响整个秒杀逻辑的依赖就称之为弱依赖,这些弱依赖在紧急情况下就可以去掉。
要减少依赖,我们可以给系统进行分级,比如 0 级系统、1 级系统、2 级系统,0 级系统如果是最重要的系统,那么 0 级系统强依赖的系统也同样是最重要的系统,以此类推。注意,0 级系统要尽量减少对 1 级系统的强依赖,防止重要的系统被不重要的系统拖垮。例如支付系统是 0 级系统,而优惠券是 1 级系统的话,在极端情况下可以把优惠券给降级,防止支付系统被优惠券这个 1 级系统给拖垮。
5)避免单点故障:系统中的单点可以说是系统架构上的一个大忌,因为单点意味着没有备份,风险不可控,我们设计分布式系统最重要的原则就是“消除单点”。
那如何避免单点呢?关键点是避免将服务的状态和机器绑定,即把服务无状态化,这样服务就可以在机器中随意移动。服务无状态化的典型实现方式就是把和机器相关的配置动态化,这些参数可以通过配置中心来动态推送,在服务启动时动态拉取下来,我们通过修改配置规则来方便地改变这些映射关系。
服务无状态化是有效避免单点的一种方式,但是像存储服务本身很难无状态化,因为数据要存储在磁盘上,本身就要和机器绑定,那么这种场景可以通过冗余多个备份的方式来解决单点问题,每个数据分片都有多个副本存储在不同的物理节点上,通过负载均衡器将请求分发到可用的副本上,这样即使某个节点或副本发生故障,系统依然能够继续提供服务而不影响整体的可用性。
还没有评论,来说两句吧...