You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
15 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 04丨网络编程原理一个字符的互联网之旅
我们开发的面向普通用户的应用程序目前看来几乎都是互联网应用程序也就是说用户操作的应用程序不管是浏览器还是移动App核心请求都会通过互联网发送到后端的数据中心进行处理。这个数据中心可能是像微信这样的自己建设的、在多个地区部署的大规模机房也可能是阿里云这样的云服务商提供的一个虚拟主机。
但是不管这个数据中心的大小应用程序都需要在运行期和数据中心交互。比如我们在淘宝的搜索框随便输入一个字符“a”就会在屏幕上看到一大堆商品。那么我们的手机是如何通过互联网完成这一操作的这个字符如何穿越遥远的空间从手机发送到淘宝的数据中心在淘宝计算得到相关的结果然后将结果再返回到我们的手机上从而完成自己的互联网之旅呢
虽然我们在编程的时候很少要自己直接开发网络通信代码服务器由Tomcat这样的WEB容器管理网络通信服务间网络通信通过Dubbo这样的分布式服务框架完成网络通信。但是由于我们现在开发的应用主要是互联网应用它们构建在网络通信基础上网络通信的问题可能会出现在系统运行的任何时刻。了解网络通信原理了解互联网应用如何跨越庞大的网络构建起来对我们开发一个互联网应用系统很有帮助对我们解决系统运行过程中各种因为网络通信而出现的各种问题更有帮助。
## DNS
我们先从DNS说起。
构成互联网Internet的最基本的网络协议就是互联网协议Internet Protocol简称IP协议。IP协议里面最重要的部分是IP地址各种计算机设备之间能够互相通信首先要能够找到彼此IP地址就是互联网的地址标识。手机上的淘宝App能够访问淘宝的数据中心就是知道了淘宝数据中心负责请求接入的服务器的IP地址然后建立网络连接进而处理请求数据。
那么手机上的淘宝App如何知道数据中心服务器的IP地址呢当然淘宝的工程师可以在App里写死这个IP地址但是这样做会带来很多问题比如影响编程的灵活性以及程序的可用性等。
事实上这个IP地址是通过DNS域名解析服务器得到的。当我们打开淘宝App的时候淘宝要把App首页加载进来这时候就需要连接域名服务器进行域名解析将xxx.taobao.com这样的域名解析为一个IP地址然后连接目标服务器。
![](https://static001.geekbang.org/resource/image/b6/9a/b66ab4aad74e047b671f59d9172c9f9a.png)
## CDN
事实上DNS解析出来的IP地址并不一定是淘宝数据中心的IP地址也可能是淘宝CDN服务器的IP地址。
CDN是内容分发网络Content Delivery Network的缩写。我们能够用手机或者电脑上网是因为运营服务商为我们提供了互联网接入服务将我们的手机和电脑连接到互联网上。App请求的数据最先到达的是运营服务商的机房然后运营商通过自己建设的骨干网络和交换节点将我们请求数据的目的地址发往互联网的任何地方。
为了提高用户请求访问的速度也为了降低数据中心的负载压力淘宝会在全国各地各个主要的运营服务商的接入机房中部署一些缓存服务器缓存那些静态的图片、资源文件等这些缓存服务器构成了淘宝的CDN。
如果用户请求的数据数据是静态的资源这些资源的URL通常以image.taobao.com之类的二级域名进行标识域名解析的时候就会解析为淘宝CDN的IP地址请求先被CDN处理如果CDN中有需要的静态文件就直接返回如果没有CDN会将请求发送到淘宝的数据中心CDN从淘宝数据中心获得静态文件后一方面缓存在自己的服务器上一方面将数据返回给用户的App。
![](https://static001.geekbang.org/resource/image/2d/a4/2da7c834bfadb8aee3325cea78fbd7a4.png)
而如果请求的数据是动态的比如要搜索关键词为“a”的商品列表请求的域名可能会是search.taobao.com这样的二级域名就会直接被DNS解析为淘宝的数据中心的服务器IP地址App请求发送到数据中心处理。
## HTTP
不管发送到CDN还是数据中心App请求都会以HTTP协议发送。
HTTP是一个应用层协议当我们进行网络通信编程的时候通常需要关注两方面的内容一方面是应用层的通信协议主要是我们通信的数据如何编码既能使网络传输过去的数据携带必要的信息又使通信的两方都能正确识别这些数据即通信双方应用程序需要约定一个数据编码协议。另一方面就是网络底层通信协议即如何为网络上需要通信的两个节点建立连接完成数据传输目前互联网应用中最主要的就是TCP协议。
在TCP传输层协议层面就是保证建立通信两方的稳定通信连接将一方的数据以bit流的方式源源不断地发送到另一方至于这些数据代表什么意思哪里是两次请求的分界点TCP协议统统不管需要应用层面自己解决。如果我们基于TCP协议自己开发应用程序就必须解决这些问题。而互联网应用需要在全球范围为用户提供服务将全球的应用和全球的用户联系在一起需要一个统一的应用层协议这个协议就是HTTP协议。
![](https://static001.geekbang.org/resource/image/79/50/79d09c6e3cd898f29b7432af5de81a50.png)
这张图是HTTP的请求头的例子包括请求方法和请求头参数。请求方法主要有GET、POST这是我们最常用的两种此外还有DELETE、PUT、HEAD、TRACE等几种方法请求头参数包括缓存控制Cache-Control、响应过期时间Expires、Cookie等等。
HTTP请求如果是GET方法那么就只有请求头如果是POST方法在请求头之后还有一个body部分包含请求提交的内容HTTP会在请求头的Content-Length参数声明body的长度。
![](https://static001.geekbang.org/resource/image/4e/92/4e396c4b95f22000b5cdd4d6ddc38192.png)
这是HTTP响应头的例子响应头和请求头一样包含各种参数而status状态码声明响应状态状态码是200表示响应正常。
响应状态码是3XX表示请求被重定向常用的302表示请求被临时重定向到新的URL响应头中包含新的临时URL客户端收到响应后重新请求这个新的URL状态码是4XX表示客户端错误常见的403表示请求未授权被禁止访问404表示请求的页面不存在状态码是5XX表示服务器异常常见的500请求未完成502请求处理超时503服务器过载。
如果响应正常那么在响应头之后就是响应body浏览器的响应body通常是一个HTML页面App的响应body通常是个JSON字符串。
## TCP
应用程序使用操作系统的socket接口进行网络编程socket里封装了TCP协议。应用程序通过socket接口使用TCP协议完成网络编程socket或者TCP在应用程序看就是一个底层通信协议事实上TCP仅仅是一个传输层协议在传输层协议之下还有网络层协议网络层协议之下还有数据链路层协议数据链路层协议之下还有物理层协议。
![](https://static001.geekbang.org/resource/image/ab/9a/ab0f73a9e8aef340dffa7fd64f299d9a.png)
传输层协议TCP和网络层协议IP共同构成TCP/IP协议栈成为互联网应用开发最主要的通信协议。OSI开放系统互联模型将网络协议定义了7层TCP/IP协议栈将OSI顶部三层协议应用层、表示层、会话层合并为一个应用层HTTP协议就是TCP/IP协议栈中的应用层协议。
**物理层**负责数据的物理传输计算机输入输出的只能是0 1这样的二进制数据但是在真正的通信线路里有光纤、电缆、无线各种设备。光信号和电信号以及无线电磁信号在物理上是完全不同的如何让这些不同的设备能够理解、处理相同的二进制数据这就是物理层要解决的问题。
**数据链路层**就是将数据进行封装后交给物理层进行传输,主要就是将数据封装成数据帧,以帧为单位通过物理层进行通信,有了帧,就可以在帧上进行数据校验,进行流量控制。数据链路层会定义帧的大小,这个大小也被称为最大传输单元。
像HTTP要在传输的数据上添加一个HTTP头一样数据链路层也会将封装好的帧添加一个帧头帧头里记录的一个重要信息就是发送者和接受者的mac地址。mac地址是网卡的设备标识符是唯一的数据帧通过这个信息确保数据送达到正确的目标机器。
前面已经提到,**网络层IP协议**使得互联网应用根据IP地址就能访问到淘宝的数据中心请求离开App后到达运营服务商的交换机交换机会根据这个IP地址进行路由转发可能中间会经过很多个转发节点最后数据到达淘宝的服务器。
网络层的数据需要交给链路层进行处理而链路层帧的大小定义了最大传输单元网络层的IP数据包必须要小于最大传输单元才能进行网络传输这个数据包也有一个IP头主要包括的就是发送者和接受者的IP地址。
IP协议不是一个可靠的通信协议并不会确保数据一定送达。要保证通信的稳定可靠需要**传输层协议TCP**。TCP协议在传输正式数据前会先建立连接这就是著名的TCP三次握手。
![](https://static001.geekbang.org/resource/image/22/2b/22998c116366030bfce5ef4043579a2b.png)
App和服务器之间发送三次报文才会建立一个TCP连接报文中的SYN表示请求建立连接ACK表示确认。App先发送 SYN=1Seq=X的报文表示请求建立连接X是一个随机数淘宝服务器收到这个报文后应答SYN=1ACK=X+1Seq=Y的报文表示同意建立连接App收到这个报文后检查ACK的值为自己发送的Seq值+1确认建立连接并发送ACK=Y+1的报文给服务器服务器收到这个报文后检查ACK值为自己发送的Seq值+1确认建立连接。至此App和服务器建立起TCP连接就可以进行数据传输了。
TCP也会在数据包上添加TCP头TCP头除了包含一些用于校验数据正确性和控制数据流量的信息外还包含通信端口信息一台机器可能同时有很多进程在进行网络通信。如何使数据到达服务器后能发送给正确的进程去处理就需要靠通信端口进行标识了。HTTP默认端口是80当然我们可以在启动HTTP应用服务器进程的时候随便定义一个数字作为HTTP应用服务器进程的监听端口但是App在请求的时候必须在URL中包含这个端口才能在构建的TCP包中记录这个端口也才能在到达服务器后被正确的HTTP服务器进程处理。
如果我们以POST方法提交一个搜索请求给淘宝服务器那么最终在数据链路层构建出来的数据帧大概是这个样子这里假设IP数据包的大小没有超过链路层的最大传输单元。
![](https://static001.geekbang.org/resource/image/2e/8d/2ef260e20f190fed1d03febdea09378d.png)
App要发送的数据只是key="a"这样一个JSON字符串每一层协议都会在上一层协议基础上添加一个头部信息最后封装成一个链路层的数据帧在网络上传输发送给淘宝的服务器。淘宝的服务器在收到这个数据帧后在通信协议的每一层进行校验检查确保数据准确后将头部信息删除再交给自己的上一层协议处理。HTTP应用服务器在最上层负责HTTP协议的处理最后将key="a"这个JSON字符串交给淘宝工程师开发的应用程序处理。
## LB负载均衡
HTTP请求到达淘宝数据中心的时候事实上也并不是直接发送给搜索服务器处理。因为对于淘宝这样日活用户数亿的互联网应用而言每时每刻都有大量的搜索请求到达数据中心为了使这些海量的搜索请求都能得到及时处理淘宝会部署一个由数千台服务器组成的搜索服务器集群共同为这些高并发的请求提供服务。
因此搜索请求到达数据中心的时候首先到达的是搜索服务器集群的负载均衡服务器也就是说DNS解析出来的是负载均衡服务器的IP地址。然后由负载均衡服务器将请求分发到搜索服务器集群中的某台服务器上。
负载均衡服务器的实现手段有很多种淘宝这样规模的应用通常使用Linux内核支持的链路层负载均衡。
![](https://static001.geekbang.org/resource/image/e0/46/e0cbd3c93b67ed042c786862ede00f46.png)
这种负载均衡模式也叫直接路由模式在负载均衡服务器的Linux操作系统内核拿到数据包后直接修改数据帧中的mac地址将其修改为搜索服务器集群中某个服务器的mac地址然后将数据重新发送回服务器集群所在的局域网这个数据帧就会被某个真实的搜索服务器接收到。
负载均衡服务器和集群内的搜索服务器配置相同的虚拟IP地址也就是说在网络通信的IP层面负载均衡服务器变更mac地址的操作是透明的不影响TCP/IP的通信连接。所以真实的搜索服务器处理完搜索请求发送应答响应的时候就会直接发送回请求的App手机不会再经过负载均衡服务器。
## 小结
事实上这个搜索字符“a”的互联网之旅到这里还没有结束。淘宝搜索服务器程序在收到这个搜索请求的时候首先在本地缓存中查找是否有对应的搜索结果。如果没有会将这个搜索请求也就是这个字符发送给一个分布式缓存集群查找是否有对应的搜索结果。如果还没有才会将这个请求发送给一个更大规模的搜索引擎集群去查找。
这些分布式缓存集群或者搜索引擎集群都需要通过RPC远程过程调用的方式进行调用请求也就是需要通过网络进行服务调用这些网络服务也都是基于TCP协议进行编程的。
对于互联网应用,用户请求数据离开手机通过各种网络通信,最后到达数据中心的应用服务器进行最后的计算、处理,中间会经过许多环节,事实上,这些环节就构成了互联网系统的整体架构,所以通过网络通信,可以将整个互联网应用系统串起来,对理解互联网系统的技术架构很有帮助,在程序开发、运行过程中遇到各种网络相关问题,也可以快速分析问题原因,快速解决问题。
## 思考题
负载均衡就是将不同的网络请求数据分发到多台服务器上,每台服务器承担一部分请求负载压力,多台服务器共同承担外部并发请求的压力,除了文中提到的这种负载均衡实现方案,你还了解哪些方案呢?
欢迎你在评论区写下你的思考,也欢迎把这篇文章分享给你的朋友或者同事,一起交流一下。