背景
由于平时倾向于关注业务层面的架构与技术,对网络基础架构上的知识了解不多,对其中很多知识点都是一知半解,甚至有些都没有听说过,比如AServer是什么?为什么会有AServer?它的原理是什么?等等,带着这些问题来浅析网络基础架构。
看一次网络请求
网络架构是为了服务网络请求的,那一次网络请求都发生了什么?先回顾一下OSI模型,自上向下分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
主要过程
先把主要过程呈现出来,然后再挨个看内部细节。
1.URL解析
一个合法的URL一定包含协议、域名等信息。如果我们经常访问一个网站,那么浏览器会缓存网站的相关信息。试着输入taobao,如果之前有访问过,那么浏览器会自动联想出 https://www.taobao.com。
2.DNS解析
DNS简单来说是将域名转为IP地址的映射服务,可以是1对多,顺序返回通常选择第一个。
MAC查看DNS映射的命令是:cat /etc/resolv.conf
说DNS解析之前得先说下IP地址,它为互联网上的每一个网络、主机分配一个逻辑地址,正如每台电脑都有自己的IP地址一样,服务器也同样如此。
计算机在网络上进行通讯是基于TCP/IP协议的,只能识别如“114.114.114.114”之类的IP地址,并不认识域名,那为什么我们不直接通过IP地址来访问网络服务,减少一层DNS解析仿真速度不是更快吗?自己认为主要是两个原因:
- 域名更具备可读性,试想一下如果访问网站都需要输一串数字,那将是多么痛苦的事情。
- 域名提高了服务可用性,试想如果直接通过固定IP访问,一旦这个IP挂了,那服务将不可用,但是DNS可以根据探活机制动态更新IP列表,保证一定时间后故障IP会被下掉,客户端可以正常访问。
解析顺序
- 浏览器缓存
- 操作系统缓存
- 本地hosts文件缓存
- 路由器缓存
- ISP DNS (DNS服务提供商)
- 13个根域名服务器,.com -> .cn -> .net ...
假设DNS服务器只有一个,那它将面临通信容量大、远距离网络延迟高、维护成本高、可靠性低等问题,所以DNS服务器采用分布式集群方式工作。
服务器层次划分
- 根服务器,根域名服务器是最高层次的域名服务器,所有的根域名服务器都知道所有顶级域名服务器的域名和ip。如果本地域名服务器没有缓存相应记录,首先会向根域名服务器发起请求。
- 顶级域名服务器,顶级域名服务器管理在该顶级域名服务器注册的所有二级域名,但受到DNS查询就会有相应应答。(可能是给出最后的结果或下一步应当找的域名服务器ip)
- 权威域名服务器,权威域名服务器是负责查询域名的解析设置,一般由域名解析服务商提供,权威域名服务器是直接对域名进行解析过程的。
- 本地域名服务器,每一个因特网服务提供ISP(电信联通移动)都可以拥有一个本地域名服务器。这种服务器有时也被称为默认域名服务器。本地域名服务器一般离用户较近,一般不超过几个路由的距离。如果要查询的IP同属一个本地ISP时即可直接返回结果地址ip。
域名的结构由标号序列组成,各标号之间用点隔开。类似于这样:“….三级域名.二级域名.顶级域名”。例如 https://www.taobao.com 中
- 顶级域名:.com
- 二级域名:taobao
- 三级域名:www
3.建立TCP连接
HTTP请求为什么要用TCP协议建立连接?
HTTP协议并没有明确要求必须使用TCP协议作为运输层协议,但是因为HTTP协议对可靠性的的要求,默认HTTP是基于TCP协议的。若是使用UDP这种不可靠的、尽最大努力交付的运输层协议来实现HTTP的话,那么TCP协议的流量控制、可靠性保障机制等等功能就必须全部放到应用层来实现。
TCP 三次握手
seq(序号):TCP连接字节流中每一个字节都会有一个编号,而本字段的值指的是本报文段所发送数据部分第一个字节的序号。
ack(确认号):表示期望收到的下一个报文段数据部分的第一个字节的编号,编号为ack-1及以前的字节已经收到。
SYN:当本字段为1时,表示这是一个连接请求或者连接接受报文。
ACK:仅当本字段为1时,确认号才有效。
连接建立阶段:
第一次握手:客户端的应用进程主动打开,并向服务端发出请求报文段。其首部中:SYN=1,seq=x。
第二次握手:服务器应用进程被动打开。若同意客户端的请求,则发回确认报文,其首部中:SYN=1,ACK=1,ack=x+1,seq=y。
第三次握手:客户端收到确认报文之后,通知上层应用进程连接已建立,并向服务器发出确认报文,其首部:ACK=1,ack=y+1。当服务器收到客户端的确认报文之后,也通知其上层应用进程连接已建立。
CLOSED:关闭状态、LISTEN:收听状态、SYN-SENT:同步已发送、SYN-RCVD:同步收到、ESTAB-LISHED:连接已建立
4.服务器处理请求
服务器处理请求场景比较多,这里只介绍一下常见的处理流程:
- 请求静态资源(html, css, js, png...),服务器可能通过NGINX直接将请求转发到静态资源服务器。
- API请求,请求到达服务器后可能会经历:反序列化,参数校验,用户鉴权,模型转换,信息填充,持久化处理,result构造,返回响应等
5.浏览器接受响应
浏览器接受后端返回的响应,请求的具体响应信息可以通过F12查看,包括但不限于:Response header、Response Body、Timing、Cookies等
6.渲染页面
前端了解不多,这里为了内容完整稍做简述。
前端文件主要分为四类:
- html:为前端页面的主体,由标签、指令与转义字符(实体)等组成,简单来说就是定义条条框框。
- css: 为前端页面的样式,由选择器、作用域与样式块组成,简单来说就是定义条条框框的样式,什么颜色,多少px等。
- js:为前端页面的脚本,由DOM、BOM与ES组成,简单来说就是定义条条框框里面显示的内容,以及如何获取。
- assets:前端资源,比如图片,文本等。
渲染顺序:
- 解析HTML
- 解析CSS
- 渲染doom树
部署架构
总览
结构组成
相关术语
- DS:Director Server,指的是负载均衡器节点,负责接收客户端请求,并转发给RS。
- RS:Real Server,处理实际请求的后端服务器节点。
- CIP:Client IP address,客户端的IP地址。
- VIP:Virtual IP address,DS用于和客户端通信的IP地址,作为客户端请求的目标IP地址。
- DIP:Directors IP address,DS用于和内部RS通信的IP地址。
- RIP:Real IP address,后端服务器的IP地址。
看完部署架构组成,我们来浅析每个组成模块的作用,DNS已经介绍过了,从负载均衡开始吧。
负载均衡(LB/SLB)
服务负载均衡(Load Balance)是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。
SLB(服务器负载均衡):在多个提供相同服务的服务器的情况下,负载均衡设备存在虚拟服务地址,当大量客户端从外部访问虚拟服务IP地址时,负载均衡设备将这些报文请求根据负载均衡算法,将流量均衡的分配给后台服务器以平衡各个服务器的负载压力,避免在还有服务器压力较小情况下其他服务达到性能临界点出现运行缓慢甚至宕机情况,从而提高服务效率和质量,因此对客户端而言,RS(real server 实际服务器)的IP地址即是负载均衡设备VIP(虚拟服务地址IP)地址,真正的RS服务器IP地址对于客户端是不可见的。
为什么有LB
没有LB的时候,用户直接访问服务器,存在两个问题:
- 用户直接访问web 服务器,如果服务器宕机,那么用户将无法访问。
- 用户和服务器是 N:1,如果某个时刻访问服务器的用户很多,超过服务器能处理的极限,就会出现加载速度缓慢或根本无法连接的情况。
可以看到没有LB的情况下网络的可靠性不高。
如果有多个服务器同时提供相同的服务能力,那是不是就可以解决上述问题?答案是是的,但是客户端同一时刻只能连接一台服务器,那么应该选择哪一台服务器呢?通过添加LB来解决这个问题,LB内部有负载均衡算法,可以动态的为客户端选择一台适合的服务器连接,不可用的服务器也将通过定时心跳检测从LB连接池中剔除掉,避免造成客户端错误连接,常用 IP + Port 的方式来实现。
curl -i http://33.x.x.x:7002/appHealth/liveness
如果访问的客户端数量太多LB也顶不住了怎么办?同样的加LB机器,LB集群也通过定时心跳检测来保证连接可用。
LB分类
二层负载均衡(mac)
根据OSI模型分的二层负载,一般是用虚拟mac地址方式,外部对虚拟MAC地址请求,负载均衡接收后分配后端实际的MAC地址响应。
三层负载均衡(ip)
一般采用虚拟IP地址方式,外部对虚拟的ip地址请求,负载均衡接收后分配后端实际的IP地址响应。(即一个ip对一个ip的转发, 端口全放开)
四层负载均衡(tcp)
在三次负载均衡的基础上,即从第四层"传输层"开始, 使用"ip+port"接收请求,再转发到对应的机器。
四层的负载均衡就是基于IP+端口的负载均衡:在三层负载均衡的基础上,通过发布三层的IP地址(VIP),然后加四层的端口号,来决定哪些流量需要做负载均衡,对需要处理的流量进行NAT处理,转发至后台服务器,并记录下这个TCP或者UDP的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
对应的负载均衡器称为四层交换机(L4 switch),主要分析IP层及TCP/UDP层,实现四层负载均衡。此种负载均衡器不理解应用协议(如HTTP/FTP/MySQL等等)。
实现四层负载均衡的软件有:
- F5:硬件负载均衡器,功能很好,但是成本很高。
- lvs:重量级的四层负载软件
- nginx:轻量级的四层负载软件,带缓存功能,正则表达式较灵活
- haproxy:模拟四层转发,较灵活
七层负载均衡(http)
七层的负载均衡就是基于虚拟的URL或主机IP的负载均衡:在四层负载均衡的基础上(没有四层是绝对不可能有七层的),再考虑应用层的特征,比如同一个Web服务器的负载均衡,除了根据VIP加80端口辨别是否需要处理的流量,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。举个例子,如果你的Web服务器分成两组,一组是中文语言的,一组是英文语言的,那么七层负载均衡就可以当用户来访问你的域名时,自动辨别用户语言,然后选择对应的语言服务器组进行负载均衡处理。
对应的负载均衡器称为七层交换机(L7 switch),除了支持四层负载均衡以外,还有分析应用层的信息,如HTTP协议URI或Cookie信息,实现七层负载均衡。此种负载均衡器能理解应用协议。
实现七层负载均衡的软件有:
- haproxy:天生负载均衡技能,全面支持七层代理,会话保持,标记,路径转移;
- nginx:只在http协议和mail协议上功能比较好,性能与haproxy差不多;
- apache:功能较差
LVS(四层LB)
基础概念
一组服务器通过高速的局域网或者地理分布的广域网相互连接,在它们的前端有一个负载调度器(Load Balancer)。负载调度器能无缝地将网络请求调度到真实服务器上,从而使得服务器集群的结构对客户是透明的,客户访问集群系统提供的网络服务就像访问一台高性能、高可用的服务器一样。客户程序不受服务器集群的影响不需作任何修改。系统的伸缩性通过在服务机群中透明地加入和删除一个节点来达到,通过检测节点或服务进程故障和正确地重置系统达到高可用性。由于我们的负载调度技术是在Linux内核中实现的,我们称之为Linux虚拟服务器(Linux Virtual Server)。
LVS集群
当单台LVS无法承载全部的负载均衡任务时,可以通过等价路由让多台LVS形成一个LVS集群,共同完成负载均衡的任务。LVS集群部署后需要前置引入交换机来做LVS集群的健康检查。LVS和交换机间运行OSPF协议,交换机通过ECMP等价路由,将请求分发给LVS集群。1个VIP配置在集群的所有LVS上,当一台LVS宕机后,交换机会自动发现并将其从ECMP等价路由中剔除。
NGINX(七层LB)
LVS只能实现对四层负载均衡,Nginx负载均衡既可以实现对四层的负载又可以实现对七层的负载,可以根据ip端口也可以根据应用名称来转发。
首先用户发送请求首先会被转发到四层负载均衡上,因为访问网站都是基于域名加端口的,四层就满足了访问条件,然后在根据请求的内容转发到七层负载上,七层负载再根据请求的类型转发到不同的后端web集群,四层和七层也可以在一台服务器上,使用Nginx就可以实现这种架构。
Nginx实现负载均衡需要两个模块
- proxy_pass代理模块
- upstream虚拟资源池模块
如何使用可以看:
https://www.nginx.com/resources/wiki/start/
四层与七层的区别
四层负载均衡:传输层
- 优点:性能高,数据包在底层就进行了转发
- 缺点:仅支持ip:prot转发,无法完成复杂的业务逻辑应用
七层负载均衡︰应用层
- 优点:贴近业务,支持URI路径匹配、Header改写、Rewrite等
- 缺点:性能低,数据包需要拆解到顶层才进行转发
负载均衡调度器
在调度器的实现技术中,IP负载均衡技术是效率最高的。在已有的IP负载均衡技术中有通过网络地址转换(Network Address Translation)将一组服务器构成一个高性能的、高可用的虚拟服务器,我们称之为VS/NAT技术(Virtual Server via Network Address Translation),大多数商品化的IP负载均衡调度器产品都是使用此方法,如Cisco的LocalDirector、F5的Big/IP和 Alteon的ACEDirector。在分析VS/NAT的缺点和网络服务的非对称性的基础上,我们提出通过IP隧道实现虚拟服务器的方法VS/TUN (Virtual Server via IP Tunneling),和通过直接路由实现虚拟服务器的方法VS/DR(Virtual Server via Direct Routing),它们可以极大地提高系统的伸缩性。所以,IPVS软件实现了这三种IP负载均衡技术,它们的大致原理如下。
NAT
Virtual Server via Network Address Translation,通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程,过程如下图所示:
发送进行SNAT,接收进行DNAT:
Client -> Server的包: DNAT, 修改desination IP
Server -> Client的包: SNAT, 修改source IP
FNAT
与NAT不同的,Full NAT发送和接收都会进行SNAT和DNAT:
Client -> Server的包: DNAT + SNAT, 修改desination IP和source IP
Server -> Client的包: DNAT + SNAT, 修改desination IP和source IP
TUN
Virtual Server via IP Tunneling,采用NAT技术时,由于请求和响应报文都必须经过调度器地址重写,当客户请求越来越多时,调度器的处理能力将成为瓶颈。为了解决这个问题,调度器把请求报 文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。由于一般网络服务应答比请求报文大许多,采用 TUN技术后,集群系统的最大吞吐量可以提高10倍。
TUN模式中,DS和RS必须支持“IP Tunneling”或者“IP Encapsulation”协议
DR
Virtual Server via Direct Routing,VS/DR通过改写请求报文的MAC地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。同TUN技术一样,DR技术可极大地 提高集群系统的伸缩性。这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,但是要求调度器与真实服务器都有一块网卡连 在同一物理网段上。
LB算法
有了LB后客户端和服务器之前的关系由 N:1 变为 N:N,如何选择一台合适的服务器来承接客户端请求至关重要,如果选择得不好就会造成“旱的旱死,涝的涝死”等现象,流量配比、服务器性能、应用场景等都是影响LB算法的重要因素。
- 轮叫(Round Robin)
调度器通过"轮叫"调度算法将外部请求按顺序轮流分配到集群中的真实服务器上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。 - 加权轮叫(Weighted Round Robin)
调度器通过"加权轮叫"调度算法根据真实服务器的不同处理能力来调度访问请求。这样可以保证处理能力强的服务器处理更多的访问流量。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。 - 最少链接(Least Connections)
调度器通过"最少连接"调度算法动态地将网络请求调度到已建立的链接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用"最小连接"调度算法可以较好地均衡负载。 - 加权最少链接(Weighted Least Connections)
在集群系统中的服务器性能差异较大的情况下,调度器采用"加权最少链接"调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。 - 基于局部性的最少链接(Locality-Based Least Connections)
"基于局部性的最少链接" 调度算法是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器 是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用"最少链接"的原则选出一个可用的服务器,将请求发送到该服务器。 - 带复制的基于局部性最少链接(Locality-Based Least Connections with Replication)
"带复制的基于局部性最少链接"调度算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法的不同之处是它要维护从一个 目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。该算法根据请求的目标IP地址找出该目标IP地址对应的服务 器组,按"最小连接"原则从服务器组中选出一台服务器,若服务器没有超载,将请求发送到该服务器,若服务器超载;则按"最小连接"原则从这个集群中选出一 台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的 程度。 - 目标地址散列(Destination Hashing)
"目标地址散列"调度算法根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。 - 源地址散列(Source Hashing)
"源地址散列"调度算法根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。
统一接入层(AServer)
业务接入AServer之前,外部请求是通过LVS集群转发给业务集群。接入Aserver之后,所有外部请求都先通过LVS集群转发到Aserver,然后Aserver再转发给业务集群,那为什么业务应用需要接入AServer?所有Https应用都涉及到ssl证书,Aserver就是为了解决海量证书维护问题。
外部流量都统一到AServer之后,AServer就必须解决这样一个问题:如何将外部请求正确地转发给对应的业务集群?
VIPServer
VIPServer通过管理应用的VIP table信息,提供软负载的能力,实现应用间直连交互。那有了VIPServer之后有什么好处呢?
没有VIPServer
假设现在有两个,分别是A/B,都是集群部署的,在没有VIPServer的时候,应用A要访问应用B需要经过LVS找到应用B的某个VIP,这时候LVS相当于网关,当请求量过大的时候LVS存在性能瓶颈。
有VIPServer
接入VIPServer后,应用B上线时会将自己的VIP列表注册到VIPServer,当应用A要访问应用B时会从VIPServer中找一个应用B的VIP,然后以直连的方式与应用B交互,可以看到VIPServer只起到服务发现的作用,处于旁路位置,并不作为网关。
Nginx
有了VIPServer就能解决服务发现的问题,Nginx服务流量的代理与转发。
密钥中心
负责密钥的存储、使用、分发、更新等,并提供数据加密解密、签名验签 API。在统一接入时主要负责证书的验证。
附录
缩写
IDC: Internet Data Center 互联网数据中心,简称IDC机房。用来存放服务器的地方,是实体服务器的集群。
AServer:阿里统一接入
参考
DNS相关
IP地址:https://baike.baidu.com/item/IP%E5%9C%B0%E5%9D%80/150859
DNS解析:https://www.zhihu.com/question/23042131
DNS服务器:https://zhuanlan.zhihu.com/p/38282917
TCP
三次握手:https://zhuanlan.zhihu.com/p/24860403
TCP报文缩写:https://www.kvkft.com/info/syn%E6%8A%A5%E6%96%87%E5%85%A8%E7%A7%B0.html
LB
Linux服务器集群系统(一):http://www.linuxvirtualserver.org/zh/lvs1.html
LVS负载均衡原理:https://www.cnblogs.com/zhangxingeng/p/10497279.html
linux负载均衡总结性说明(四层负载/七层负载):https://www.cnblogs.com/kevingrace/p/6137881.html