我们需要学习不单单是node, 而是整个后端的海洋。

后端服务的架构模式

我们在和后端同学打交道的过程中,经常会听到各种各样高大上的术语,这就需要我们对后端的架构有一个大概的了解。

后端技术在发展的过程中,很多网站提出了自己的解决方案,这些解决方案被不同的网站反复使用,从而就形成了大型网站架构模式。

分层

分层是横向的划分。大型网站,后端系统分为 应用层,服务层,数据层。

应用层: 处理具体的业务逻辑

服务层: 提供一些服务化的接口,比如说发券,发红包

数据层: 比如说数据库,缓存,文件等。

分层结构的挑战 分层结构必须要划分合理 禁止跨层次调用(比如说,应用层直接调用数据层) 禁止逆向调用(比如说,数据层调用服务层) 三层结构可以部署在同一台机器上,也可以部署在不同的服务器上。

分割

分割是对纵向的划分。大型网站有很多功能,比如说,搜索,购物车,推荐。这些小应用可以分割为不同的模块,交给不同的团队来维护。

分割可以把不同的业务放在不同的机器上,比如说,交易等对性能要求比较高的模块可以放在更高性能的机器上,而评论等模块则可以视情况降级。

分布式

分布式意味着,把不同的后端服务部署在不同的服务器上。 分布式遇到的挑战 分布式不同的机器之间,通过网络调用,性能会有影响 服务器越多,宕机的可能性越高 保持数据一致性比较困难

集群

集群是,把不同的服务器部署相同的设备。不同的服务器之间会负载均衡。 因为服务器集群有更多的服务器提供相同的服务,所以并发性更高,当访问量飙升时,只需要加机器就可以了。 当某台机器发生故障时,只需要负载均衡,或者失效转移都会把流量打到其他服务器上,使得用户仍可以正常访问。

缓存

缓存是改善性能的第一手段。在后端的世界中,缓存几乎无处不在。 缓存主要包括下面: 1、CDN CDN, 内容分发网络(content delivery network), 由遍布全国的高性能加速节点构成。当您的用户向您的某一业务内容发起请求时,请求会被调度至最接近用户的服务节点. CDN 出现的原因

用户与业务服务器地域间物理距离较远,传输延时较高且不稳定;

请求需要运营商之间进行互联转发。

业务服务器网络带宽、处理能力有限,当接收到海量用户请求时,会导致响应速度降低、可用性降低。

CDN 请求的全流程

假设发起一个请求为http://www.test.com/1.jpg,需要会先向 Local DNS 发起域名解析请求。

当local DNS 解析 www.test.com 时,发现该域名已经配置了CNAME 指向 www.test.com.cdn.dnsv1.com, 解析请求会发送至 腾讯云,会为请求分配最佳节点 IP

Local DNS 获取 Tencent DNS 返回的解析 IP

用户获取解析 IP

用户向获取的 IP 发起对资源 1.jpg 的访问请求

若该 IP 对应的节点缓存有 1.jpg,则会将数据直接返回给用户(10),此时请求结束。若该节点未缓存 1.jpg,则节点会向业务源站发起对 1.jpg 的请求(6、7、8),获取资源后,结合用户自定义配置的缓存策略,将资源缓存至节点(9),并返回给用户(10),此时请求结束。

2、 反向代理 反向代理部署在服务器之前,如果发现有缓存的静态资源,则直接返回静态资源,无需访问服务器。 3、分布式缓存 现在大型网站中,缓存往往非常巨大,一个机器承受不住,所以除了本地缓存,还有分布式缓存,将缓存存放在一个专门的集群中,应用程序通过网络访问缓存数据。 异步 作为一个前端,我们肯定对异步不陌生。异步是典型的生产消费模式,两者不直接调用,而是通过消息来交流。 异步带来很多好处: 提高系统可用性 消费方出现了堆积,不影响生产方的逻辑。

比如说,之前,我们的用户支付和发券是写在一起的,很多时候,用户支付成功了,但是发券因为商家配置的券有问题,导致发券失败,从而返回给用户支付失败。后来改成,【发券逻辑】去订阅【支付成功】的消息,【发券逻辑】失败,不会影响用户支付成功。 复制代码 加快了网站的响应速度。 生产方处理完逻辑,只需要发出消息,就直接返回响应。 复制代码 削平峰值 网站有高负载的时候,也有低谷的时候。使用消息队列,将突然增加的访问请求数据放入消息队列中,等待消费者服务器依次处理,压力就会小很多。 复制代码 后端服务的核心要素 高性能 性能是很重要的一个方面,从前端到后端,每一个环节上都可以有优化。 对于前端方面,性能优化可以浏览我的博客《前端性能探究》。 对于后端方面,可以使用本地缓存或者分布式缓存,可以组建集群,可以使用多线程,可以改善内存管理,可以对数据库增加索引、缓存等等。 上述方法,不用着急,下文会深入讲到。 可用性 我们追求服务高可用性,说白了就是后端服务不宕机。 保持运行环境的高可用,主要方法是,把我们的应用部署在多个服务器上,数据库备份在多个服务器上。当某一个机器宕机了,只需要把请求切换到其他服务器上即可。

上述有一点要求,应用服务器上不能存储会话信息。

对于开发环境的高可用,需要引入自动化发布,自动化测试,灰度发布等手段,减少把bug引入到线上的可能性 伸缩性 所谓的伸缩性,就是往集群里面新增加一台机器是否方便。 对于应用服务器集群,只要服务器上不保存数据,所有的服务器都是对等的。 对于缓存服务器集群,新加入的机器会让缓存路由失效,从而导致缓存失效,大量的请求打到数据库上,从而导致网站崩溃。所以要改善路由算法。 对于关系型数据库,虽然可以数据复制,主从热备,但是很难做到大规模集群的可伸缩,因此关系数据库通过路由分区等手段。 对于NoSql数据库,天生就是为伸缩性而生,则支持度比较好。 拓展性 所谓的拓展性,就是,能够快速新增一个新的业务线,而不会对现有的业务有很深的耦合,其他的业务线不会进行牵连或改动。 主要手段有两点: 事件驱动架构和分布式服务 事件驱动架构,主要是通过消息队列来实现的,将消息产生和消息处理解耦开。比如说,我们新增一个618临时营销活动,当用户下单成功后,给用户发放某种卡片。我们不是改动用户下单的代码,而是监听用户下单的消息队列。 分布式服务,是通过将业务代码和可复用的服务抽离开来。比如说,公司里面有A,B,C三个业务线,都需要对用户发放店铺券,就可以提供java的服务化接口,我们node 的业务通过 dubbo 来调用。 安全性 安全性保护网站不受恶意攻击。 小结 恭喜你,看到了这里。上面的性能, 高可用, 伸缩性, 拓展性, 安全性 是对接下来内容的提纲挈领。如果你有任何的疑问,请放心大胆的跳过去,我会在后面的文章细细介绍。

在本章节,我们的关注点主要是在 高性能 和 高可用

img

性能优化 性能优化是软件发展史中亘古不变的追求。 那么,对于后端同学来说,我们追求高性能,究竟什么样才是高性能?高性能我们需要关注哪些指标? 后端架构应该如何设计,才能达到高性能呢? 下面会一一介绍 性能测试指标

响应时间,越少越好

并发数,越多越好

吞吐数量,越多越好

性能计数器(system load),主要包括内存使用,cpu使用,磁盘使用等。

并发数 和 吞吐量的区别?

并发数:就是并发连接数,指网络设备所能处理的最大会话数量。这里的会话数是指请求->响应一次会话。

吞吐量: 用户请求是由一个个数据包组成,网络设备(防火墙/路由器/交换机)对每个数据包的处理要耗费资源。吞吐量是指在不丢包的情况下单位时间内通过网络设备的数据包数量。

并发数x包长度=吞吐量 参考知乎衡量网站性能时,并发数与吞吐量为何要分别考量?

性能优化策略 那么,性能优化的策略有哪些呢? 策略1: 前端性能优化

减少http请求

使用浏览器缓存

启动压缩

css放在最上面,js放在最下面

减少cookie大小

策略2: cdn加速 主要使用cdn缓存静态资源:比如说文件,css, js 等静态文件。

策略3: 反向代理 反向代理位于服务器一侧。

提高安全

可以使用缓存

负载均衡

正向代理、反向代理 正向代理 和 反向代理 正向代理代理客户端,为客户端收发请求,客户端必须要做一定的配置,比如说,翻墙。 用户不能直接访问facebook, 但是可以访问服务器A,服务器A可以访问facebook, 服务器A 就被称为正向代理。 反向代理服务端,隐藏了具体的机器,可以用于负载均衡 策略4:应用服务器的优化 应用服务器是后端业务代码部署的地方,也是最复杂,变化最多的地方,优化的主要手段有缓存,集群,异步等,具体介绍如下:

  1. 分布式缓存

网站性能优化第一定律 : 优先考虑使用缓存

使用缓存的注意点:

不要存放频繁修改的数据,数据的读写比要在2:1以上

没有热点的访问。缓存珍贵

数据不一致和脏读。要容忍一定时间的数据不一致

缓存雪崩。就是大部分情况下,都会走缓存,万一缓存有一天不能用了,流量就会全部打到数据库上,从而造成数据库的崩溃

建议缓存预热, 缓存里面存放的是热点数据。如何判断是热点数据呢?是根据LRU(最近最久未使用算法)对不断访问的数据筛选出来的,这个过程需要花费一定的时间。新启动缓存,没有任何数据,因此刚开始的性能会比较差,最好在刚启动的时候就把热点数据加载好,这就叫 缓存预热

注意缓存穿透, 如果是不恰当的代码,或者是恶意攻击,会频繁的请求一个不存在的值,缓存中没有,就会去数据库中找,从而拖慢数据库。建议给不存在的数据也缓存起来。

分布式缓存的两个代表:

jboss ( 同步更新 )

memcached ( 互不通讯,高效的网络TCP, UDP, 高效的内存管理 )

  1. 异步操作 使用消息队列将调用异步化,不仅仅可以增强拓展性,也可以提高性能。 不使用消息队列,直接操作数据库,延迟高,高并发压力大。 使用消息队列,将峰值的事务存放在消息队列中,从而削平了高峰的并发事务。 但是后续操作可能会失败,因此会要业务上,通过邮件等方式避免纠纷。 3.使用集群 高并发时,使用负载均衡,把一组机器组成一个集群,把并发请求发到多台机器上处理。 负载均衡

http重定向 主服务器的吞吐量限制

DNS解析

反向代理

ip负载均衡

高可用 网站为了实现高可用,一般会分为三层:应用层,服务层,数据层 应用层是通过负载均衡来把一组机器来组成集群。负载均衡的设备通过心跳检测检测(或者是服务器放一个check_live.html, 或者是通过header请求)到某一个服务器不可用时,就把流量分发到其他的服务器上。 服务层是通过分布式服务调用框架来来实现负载均衡。 数据层比较特殊。为了保证服务器宕机的时候,数据不丢失,需要在数据写入的时候,就对数据进行同步复制,将数据写入多台机器中,实现冗余备份。 高可用的应用层 通过负载均衡进行无状态服务的失效转移 应用层通过负载均衡来保证高可用。实现的前提是,任意一个服务器都不保持请求的上下文,也就是,对于同一个请求,所有的服务器都对等。 集群的session管理 单独部署一个session服务器,用来同一管理session。 高可用的服务层 分级管理 性能更好的机器分配给更核心的业务 超时设置 一旦服务层超时,应用层换一个机器重新尝试 异步调用 应用层对服务层的调用可以通过异步的形式,避免一个服务层方法的失败,导致整个链路的异常。比如说用户注册的流程是:写入数据库,发送确认邮件,开通权限。如果是同步的,【发送邮件】这一步有可能会阻塞掉,从而导致用户注册失败。 服务降级 网站高峰期,为了保证核心功能是没有问题的,通常会采用下面的方法:

拒绝服务。一部分不可用,总比全部人都无法用好。

关闭功能。比如说淘宝双十一关闭了评价的非核心功能

幂等性设计 应用层调用了服务层的转账接口,但是没有拿到成功的结果,于是重复调用接口,很容易就悲剧了。 服务重复调用是不可避免的,因此需要服务层做好幂等性设计,调用一次和调用一百次的结果是一样的。 高可用的数据层 数据层的高可用的指标是:

数据持久性。通过在不同的设备上进行备份

数据可访问性。出现了服务器宕机,可以快速备份

数据一致性。不一致的情况:一部分服务器更新了,另一部分服务器没有更新。

cap 原理: 我们永远没有办法实现,数据一致性(consisitency), 数据可用性(availibility)和伸缩性 这三个目标。 一般我们会优先保证 伸缩性和数据可用性,而牺牲数据一致性。 数据备份 冷备和热备的区别 冷备份:数据库是关闭,直接拷贝到另外一个地方。 热备份:数据库是运行状态。 热备份分为两种: 异步热备 和 同步热备 失效转移 如果数据服务器某一个机器宕机,那么针对这台服务器的读写必须重新路由到其他服务器。 失效转移有三部分构成:失效确认、访问转移、数据恢复

参考 · 转载 · 鸣谢