写点什么

【Spring Cloud 12】分布式架构下的高可用设计与可伸缩设计

  • 2021 年 11 月 11 日
  • 本文字数:3475 字

    阅读完需:约 11 分钟



CDN 全称是 Content Delivery Network,中文释义是内容分发网络。


CDN 的作用是把用户需要的内容分发到离用户最近的地方进行响应,这样用户能够快速


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


获取所需要的内容。


CDN 本质上就是一种网络缓存技术,能够把一些相对稳定的资源放到距离最终用户较近的地方,一方面可以节省整个广域网的带宽消耗,另外一方面也可以提升用户的访问速度、改善用户体验。



五、如何实现高可用



1、入口层

入口层,通常指 Nginx 和 Apache 等层面的东西,负责应用(不管是 Web 应用还是移动应用)的服务入口。我们通常会将服务定位在一个 IP,如果这个 IP 对应的服务器当机了,那么用户的访问肯定会中断。此时,可以用 keepalived 来实现入口层的高可用。例如,机器 A 的 IP 是 1.2.3.4,机器 B 的 IP 是 1.2.3.5, 那么再申请一个 IP 1.2.3.6(称为?跳 IP), 平时绑定在机器 A 上,如果 A 当机,IP 会自动绑定在机器 B 上;如果 B 当机,IP 会自动绑定在机器 A 上。对于这种形式,我们将 DNS 绑定到心跳 IP 上,即可实现入口层的高可用。


但这个方案有一点小问题。


第一,它的切换可能有一到两秒的中断,也就是说,如果不是要求到非常严格的毫秒级就不会有问题。


第二,对入口的机器会有些浪费,因为买了两台机器的入口,可能就只有一台机器用上。对一些长连接的应用可能会导致服务中断,这时候就需要客户端做配合做一些重新创建连接的工作。简单的说,对于比较普通的业务来说,这个方案就能解决一部分问题。


这里要注意,keepalived 在使用上会有一些限制。


  1. 两台机器必须在同一个网段,不再同一个网段,没有办法实现互相抢 IP。

  2. 内网服务也可以做心跳,但需要注意的是,以前为了安全我们会把内网服务绑定在内网 IP 上,避免出现安全问题。但为了使用 keepalived,必须监听在所有 IP 上(如果监听在心跳 IP 上,那么机器没有持有该 IP 时,服务无法启动),简单的方案是启用 iptables, 避免内网服务被外网访问。

  3. 服务器利用率下降,这时可以考虑做混合部署来改善这一点。


比较常见的一个错误是,如果有两台机器,两个公网 IP,DNS 上把域名同时定位到两个 IP,就觉得已经做了高可用了。这完全不是高可用,因为如果一台机器当机,那么就有一半左右的用户无法访问。


除了 keepalive,lvs 也能用来解决入口层的高可用问题。不过,与 keepalived 相比,lvs 会更复杂一些,门槛也会高一些。

2、业务层

业务层通常是由 PHP、Java、Python、Go 等写的逻辑代码构成的,需要依赖于后台数据库及一些缓存层面的东西。如何实现业务层的高可用呢?最核心的就是,业务层不要有状态,将状态分散到缓存层和数据库。目前大家通常喜欢将以下几种数据放入业务层。


第一,session,即用户登录相关的数据,但好的做法是将 session 放在数据库里,或者一个比较稳定的缓存系统中。


第二,缓存,在访问数据库时,如果一个查询很慢,就希望将这些结果暂时放到进程里,下次再做查询时就不用访问数据库了。这种做法带来的问题是,当业务层服务器不只是一台时,数据很难做到一致,从缓存拿到的数据就可能是错误的。


一个简单的原则就是业务层不用有状态。


在业务层没有状态时,一台业务层服务器宕机了,Nginx/Apache 会自动将所有的请求打到另外一台业务层的服务器上。由于没有状态,两台服务器没有任何差别,所以用户完全感受不到。如果把 session 放在业务层里面的话,那么面临的问题是,这个用户以前是登录在一台机器上的,这个进程死掉之后,用户就会被登出了。


友情提示:有一段时间比较流行 cookie session,就是将 session 中的数据加密之后放在客户的 cookie 里,然后下发到客户端,这样也能做到与服务端完全无状态。但这里面有很多坑,如果能绕过这些坑就可以这样使用。


第一个坑是怎么保证加密的秘钥不泄露,一旦泄露就意味着攻击者可以伪造任何人的身份。


第二个坑是重放攻击,如何避免别人通过保存 cookie 去不停地尝试验证码,当然也还有一些其他的攻击手段。


如果没有好办法解决这两个问题,那么 cookie session 尽量别用,那么将 session 放在缓存中比放在 cookie 中要好一点。

3、缓存层

非常简单的架构里是没有缓存这个概念的。但在访问量上来之后,MySQL 之类的数据库扛不住了,比如在 SATA 盘里跑 MySQL,QPS 到达 200、300 甚至 500 时,MySQL 的性能会大幅下降,这时就可以考虑用缓存层来挡住绝大部分服务请求,提升系统整体的容量。


缓存层做高可用一个简单的方法就是,将缓存层分得细一点儿。比如说,缓存层就一台机器的话,那么这台机器当了以后,所有应用层的压力就会往数据库里压,数据库扛不住的话,整个网站(或应用)就会随之当掉。而如果缓存层分在四台机器上的话,每台只有四分之一,这台机器当掉了以后,也只有总访问量的四分之一会压在数据库上面,数据库能扛住的话,网站就能很稳定地等到缓存层重新起来。在实践中,四分之一显然是不够的,我们会将它分得更细,以保证单台缓存当机后数据库还能撑得住即可。在中小规模下,缓存层和业务层可以混合部署,这样可以节省机器。

4、数据库层

在数据库层面实现高可用,通常是在软件层面来做。例如,MySQL 有主从模式(Master-Slave),还有主主模式(Master-Master)都能满足需求。MongoDB 也有 ReplicaSet 的概念,基本都能满足大家的需求。


总之,要想实现高可用,需要做到这几点:入口层做心跳,业务层服务器无状态,缓存层减小粒度,数据库做一个主从模式。对于这种模式来讲,我们做的高可用不需要太多服务器,这些东西都可以同时部署在两台服务器上。这时,两台服务器就能满足早期的高可用需求了。任何一台服务器当机用户完全无感知。


第二章?分布式架构下的可伸缩设计


================


一、可伸缩性/可扩展性(Scalable/scalability)




可伸缩性(可扩展性)是一种对软件系统计算处理能力的设计指标,高可伸缩性代表一种弹性,在系统扩展成长过程中,软件能够保证旺盛的生命力,通过很少的改动甚至只是硬件设备的添置,就能实现整个系统处理能力的线性增长,实现高吞吐量和低延迟高性能。


可伸缩性和纯粹性能调优有本质区别, 可伸缩性是高性能、低成本和可维护性等诸多因素的综合考量和平衡,可伸缩性讲究平滑线性的性能提升,更侧重于系统的水平伸缩,通过廉价的服务器实现分布式计算;而普通性能优化只是单台机器的性能指标优化。他们共同点都是根据应用系统特点在吞吐量和延迟之间进行一个侧重选择,当然水平伸缩分区后会带来 CAP 定理约束。


软件的可扩展性设计非常重要,但又比较难以掌握,业界试图通过云计算或高并发语言等方式节省开发者精力,但是,无论采取什么技术,如果应用系统内部是铁板一块,例如严重依赖数据库,系统达到一定访问规模,负载都集中到一两台数据库服务器上,这时进行分区扩展伸缩就比较困难,正如 Hibernate 框架创建人 Gavin King 所说:关系数据库是最不可扩展的。


二、性能和扩展性




  • 什么是性能问题? 如果你的系统对于一个用户访问还很慢,那就是性能问题;

  • 什么是扩展性问题? 如果你的系统对一个用户来说是快的,但是在用户不断增长的高访问量下就慢了。


三、延迟和吞吐量




延迟和吞吐量是衡量可扩展性的一对指标,我们希望获得低延迟和高吞吐量的系统架构。所谓低延迟,也就是用户能感受到的系统响应时间,比如一个网页在几秒内打开,越短表示延迟越低,而吞吐量表示同时有多少用户能够享受到这种低延迟,如果并发用户量很大时,用户感觉网页的打开速度很慢,这意味着系统架构的吞吐量有待提高。


扩展性的目标是用可接受的延迟获得最大的吞吐量。可靠性(可用性)目标:用可接受的延迟获得数据更新的一致性。


四、如何实现可伸缩




1、入口层


在入口层实现伸缩性,可以通过直接水平扩机器,然后 DNS 加 IP 来实现。但需要注意,尽管一个域名解析到几十个 IP 没有问题,但是很多浏览器客户端只会使用前几个 IP,部分域名供应商对此有优化(如每次返回的 IP 顺序随机),但这个优化效果不稳定。


推荐的做法是使用少量的 Nginx 机器作为入口,业务服务器隐藏在内网(HTTP 类型的业务这种方式居多)。另外,也可以把所有 IP 下发到客户端,然后在客户端做一些调度(特别是非 HTTP 型的业务,如游戏、直播)。


2、业务层


业务层的伸缩性如何实现?与做高可用时的解决方案一样,要实现业务层的伸缩性,保证无状态是很好的手段。此外,加机器继续水平部署即可。


3、缓存层


比较麻烦的是缓存层的伸缩性,最简单粗暴的方式是什么呢?趁着半夜量比较低的时候,把整个缓存层全部下线,然后上线新的缓存层。新的缓存层启动起来之后,再等这些缓存慢慢预热。当然这里一个要求,你的数据库能抗住低估期的请求量。如果扛不住呢?取决于缓存类型,下面我们先可以将缓存的类型区分一下。

评论

发布
暂无评论
【Spring Cloud 12】分布式架构下的高可用设计与可伸缩设计