从认识web应用开始(一)TCP通信延迟

    最近,整理过一篇电商和电信技术应用差异的ppt,简单梳理了一下技术应用存在的差异,个人觉得还不够完善和严谨,只是一些粗略的认识。那么作为曾经的一名侧重后台应用和技术组件的开发者,不妨再深入一点,从web应用的基础网络通信相关的基础知识入手,也希望能从底层基础梳理出一个对电商,对web应用认识的体系结构出来。虽然应用场景不同,导致的技术使用和体系有别。但是大家共同追求构建“低延迟,高吞吐”应用的目标是一致的。
    对于电商来讲,技术人员在各个网站或者周围经常听到一个词“访问速度”,因为电商领域直接面向终端用户,所有业务都通过web方式提供。因此电商系统访问速度对用户的忠诚度、转化率和粘性都有很大的关系。那么,我们就着关于电商系统访问速度这个核心关键点来看看一些技术应用背后的思考。

    我们来看一个最基本的访问网站模型,来分析一下可能影响用户访问速度的主要因素有哪些。如下图。

    访问流程如下:
        1.用户打开浏览器,输入访问web网站URL,回车访问。   
        2.浏览器会先查找本地hosts文件,查询本地系统有没有域名和IP地址的映射关系。
            1)假如找到,则直接根据解析的IP地址访问。
            2)如果没找到,则需要到DNS服务器上去查询并且解析具体访问的IP地址。
        3.查找并解析出访问Web服务的IP地址之后,网络上首先先建立一个TCP连接(暂且认为就是本地到web服务器之间直连)。
        4.通过该TCP连接,Web网站访问通过Http协议请求,请求相应访问的文档内容,可能也会包括访问的资源(图片等),这些资源的请求可能会是多次请求的组合,甚至会在多个TCP连接上。
        5.服务器接收到Http请求之后,根据提供服务逻辑返回相应的信息,包括访问的网页文档,要查询数据库展示的动态数据、图片等信息。
        6.浏览器通过Http应答,将传输回来的文档、图片等一一展示给访问者。
     这是一个最简单结构的Web网站的访问模型,简要的描述了下交互的流程,在理解这个简单的Web网站交互过程中个人认为有几个网络通信的知识点是必须要了解的。只有理解这些基本概念,才能认识到其实要想达到用户极速访问Web网站的体验,留给应用系统的时间真的不多!何况真实的电商Web网站面临的网络结构,以及为了支撑大规模用户访问导致系统分层结构、资源分布等更复杂的局面。还有更为挑战的是用户在无线网络下移动客户端的访问速度的挑战。
     从上面一个Web网站的基本结构来看,影响访问性能可能会有较多的因素,个人认为要形成一些体系的认识,就要从底层网络通信原理认识开始。可能不需要太多深入各种细节,但是需要了解其实现的原理,对于技术在电商这种Web系统中的应用会有一些根本的认识。

1.理解web应用访问底层通信基本原理
    现在几乎所有电商网站访问都是基于HTTP协议,这是应用层的标准协议,规约了客户端通过浏览器的URL以某种协议约束方式来请求和访问网络资源。在底层网络协议栈上,最常用的两种传输层协议TCP和UDP,网络协议栈的基本认识看看相关资料就能理解了,这里暂不多说。
    HTTP作为应用层协议,底层并没有规约一定要基于TCP或者UDP的传输协议实现,但是实际的应用场景中,因为TCP的可靠传输连接的保障机制,决定了大多数的HTTP协议的网络应用都基于TCP传输协议。

    TCP负责在不可靠的传输信道上提供可靠层的抽象层,向上应用层屏蔽了很多网络通信的复杂细节,但是也带来了网络通信传输的开销,并且这个开销会因为网络的复杂性、不同的组网环境、客户端、服务器端的实际情况带来不一样的延迟。同时整个电商在技术运用上面也就面临这种延迟带来的挑战,演进出了我们现如今看到的很多技术应用。

    决定网络通信的性能一般有两个方面,通信延迟和通信的带宽。在带宽这种传输吞吐量恒定的情况下,对于非流媒体这种应用场景的访问,会发现通信的延迟对应用系统性能带来的影响最大。所以下面来重点认识下网络通信延迟和影响通信延迟的几个关键因素。

延迟的定义:
        如上图中描述了一个端到端的基本简单网络访问结构,其中网络延迟就是指通信分组从源到目的地需要的时间。
        所以通俗点说,延迟就是一个消息或者分组信息从用户访问起点(一般为浏览器)到终点之间的时间,这个时间一般是毫秒级的,这也就是为什么要重视网络通信延迟的重要因素。
延迟的因素:
        这要从TCP的几个基本实现机制理解开始。TCP是一个点对点的通信协议,在两点之间为了达到安全、可靠、按序的传输,设计了一些复杂的算法来保障。但是这些复杂的机制也带来了网络延迟的开销。先来看一下经典的三次握手。
    1)TCP三次握手的开销

            1)每个TCP连接创建时候,客户端先发起SYN分组,其中会随机生成一个序列号,假设为x,里面还会包含协议的一些其它标志和选项。
            2)服务器接收到SYN分组请求后,会应答一个SYN ACK分组,该分组里面会将请求的序列号x+1,然后自己会随机生成一个确认序列号,假设为y,追加部分自己的标志和选项,然后返回响应。
            3)客户端接收到服务端的SYN ACK分组之后,各自给x,y序列加1完成最后的确认,发送握手期间最后一个ACK分组。
    可以通过Winshark这要的抓包工具简单跟踪下TCP连接建立三次握手的过程。这里就不详细描述协议交互内容了。

    为什么把TCP连接创建拿出来说明下呢,主要也是为了观察TCP连接建立的延迟开销。也就是没有特殊的优化之前,TCP创建一个新的连接会涉及三次分组数据来回交互。假如建立一次访问短连接,连接之间的距离可能会达到KM以上,分组数据一次来回开销延迟可能就在几十毫秒以上。
    对于短连接请求访问的场景,TCP连接创建的过程是一个延迟的重要因素。在这方面就有了后来重用TCP连接、TFO(快速打开)的优化思路。重用TCP连接在整个电商Web应用中配套的浏览器、HTTP协议,应用层基于Socket通信的私有协议上都有比较多的应用,后面可以详细分析一下。
    2)流量传输控制带来开销

   TCP连接通过三次握手机制建立之后,会遇到我们通信上面最常见面临的一种情况,就是两个山头的兄弟先对对方进行了通知,但是后续说的话都担心对方可能没听到。TCP连接为了解决这个问题,在三次握手分组交换之后,每次数据传输都会附带ACK确认分组信息,来确认在连接上的数据通信是否已经收到。
    另外,TCP连接创建过程完成之后,会涉及在该虚拟连接上传输数据/消息。因为TCP连接是点对点模式的,因此在数据传输上面会存在一个很明显的问题,那就是数据传输链路上面传输数据,两端能接收和发送的数据双方都不知情,可能因为通信双方发送、接收处理能力信息不对等,导致网络大量拥塞问题,因此需要有一些协议层面约束定义。
    TCP机制为了解决这类问题,提供了一系列的分组协商机制来解决这些问题。
       I.流量控制

         TCP的流量控制机制,本质上就是预防任何一个发送端向接收端过多的发送数据的一种机制。假如发送端过多的发送数据给接收端,那么接收端就会因为处理不过来、负载重导致无法处理传输过来的数据。因此,TCP协议中在ACK确认分组里面定义了一个称为接收窗口rwnd,用于标注发送端和接收端能够接收数据的大小。
         上述图是TCP机制下,在握手交互之间,通过ACK分组首部的互相通知对端接收窗口rwnd值,包含了各自接收缓冲区的大小信息。
         第一次TCP连接建立的时候,客户端、服务端都会使用各自系统默认的设置来发送rwnd信息。这个值一般情况下为64KB,在最新的规定中可以支持调整到1GB,但是这里面可能存在的问题如下。
               a.假如是浏览网页的场景,主要是从服务端下载数据到客户端,客户端的接收窗口可能会成为瓶颈。
               b.假如是上传类业务,比如上传图片、视频,客户端向服务端传输大量数据,服务端的接收窗口又可能会成为瓶颈。
          为了应对这种情况,TCP引入了流量控制机制,也就是在TCP整个连接生命周期之内,每次数据收到后确认的ACK分组都会携带最新的动态调整的接收窗口rwnd值,便于两端动态调整数据流速,这样来适应两端的接收容量和处理能力。要简要说明清楚,可以通过一个场景来描述。假设通信双方为AA和BB。
                  AA:连接三次握手最后ACK确认分组,携带rwnd值,告知BB,我的接收窗口是系统默认值64KB。
                  BB:接收到三次握手ACK确认分组之后,开始接收AA发起请求数据信息。缓存在本地缓冲区,待处理。
                  BB:在接收到请求数据之后的确认ACK分组里面,告知一下BB当前可接收窗口大小,应该去除掉缓存本地没来得及处理的请求数据大小,同时给AA发送应答数据。
                  AA:接收BB传递的数据,缓存在本地,将缓存剩余的大小,通过确认ACK分组里面rwnd字段告知BB端。
          从上述场景交互来看,rwnd这个分组里面的信息就是个动态变化的值了。当然他会有最大值的限制,在最新的Linux内核中,通过如下查看窗口缩放选项的命令查看该值限制。默认都是启用,也就是该窗口rwnd大小可以提升到1G字节。
                [root@ecs-c0be ~]# sysctl net.ipv4.tcp_window_scaling
                       net.ipv4.tcp_window_scaling = 1
     II.慢启动
        流量控制解决了点对点通信里面,避免发送端向接收端发送过多数据的问题。但是这是建立在单连接,点对点理想的情况下的控制机制。在实际应用中,在同一个通信的链路中可能会创建很多的TCP连接,你会发现带宽不会只是给一个连接使用的。这时候带来了新的问题。
        一开始这样:

         实际情况是这样:

            服务端可能不只接收一个客户端TCP连接请求,可能会多个,甚至还在不断的增加。虽然客户端和服务端之间数据交换rwnd值是一个根据双方实际处理能力动态调整的。
            但是,客户端和服务端看是透明的两端,中间会存在各种交换机、路由器设备。加上一个通信链路上面多个TCP连接存在,假如还是按照客户端、服务端处理能力来决定数据传输率的话,就可能导致中间环节处理不过来。举个容易理解的例子:
                    “你在家看视频,一个人使用接入家庭的宽带,访问流畅,视频的服务器正在根据流量控制机制,卖力的给你客户端传输数据。你家老婆这时候可能要更新一个软件,打开一个新的连接,可用的带宽就可能会降低。在这种情况下,如果视频服务器还是按照原来动态调整的速度发送视频数据的话,就可能导致数据在中间交互的某个网关点上产生积压,最终导致本地缓冲处理不及时,需要删除分组数据,降低网络利用率。”
            为了解决这个问题,TCP里面定义了一个“拥塞窗口cwnd”(发送端从客户端接收ACK分组之前可以发送数据量的限制)变量,另外通过“慢启动”算法来估算整个网络通信过程中变化的可用带宽。因为根据传输的数据来估算客户端和服务端可用的带宽是唯一的办法。
            服务器维护一个拥塞窗口变量cwnd,这个值和rwnd都是一个限制值,也就是最大不能超过,实际发送数据是根据消息定义结合这个最大限制来的。这个cwnd初始值会在Linux里面通过initcwnd来定义。
    慢启动就是通过在ACK分组交互确认过程中,不断的调整cwnd的大小,从默认值慢慢放大,达到最大限制。但是接收窗口可能会因为这个值处理不过来,因此算法中是取cwnd和rwnd最小值来进行传输数据的。
    慢启动最大的特点就是带宽会在TCP连接建立后,慢慢达到最大可拥带宽。
        1)假如是视频流服务,慢启动机制对其影响不大,因为会在整个访问过程中达到最大带宽,可以将传输分摊到整个周期内消化掉。
        2)假如是应用访问,大量突发的连接,甚至以前使用web访问的短连接机制,那就意味着应用很难短时间内达到最大的带宽利用率。端到端实现这种慢启动来回确认机制带来的延迟成为瓶颈。
     III.拥塞预防
    慢启动解决了发送端和接收端可能处理不及时和带宽利用率的问题,就是慢启动在不断的增大发送数据窗口同时,通过rwnd和cwnd的动态变化比较来检测网络带宽情况,决定连接上面发送数据量的大小,以此来改善TCP连接上面带宽利用率。
    但是没有解决一旦拥塞出现了,怎么去避免和预防的问题。举个例子。还是AA和BB通信,中间可能存在一个路由节点CC。
                AA:通过三次握手,以及后续的ACK确认分组,我们已经交换了rwnd和cwnd的值,而且经过多次交互已经达到比较优的带宽利用率了,这是在按照最新的窗口计算值来发送数据。
                CC:因为某个时间点,经过本人路由节点的数据暴增,导致本节点处理缓慢。慢到什么程度?可能慢到超过了发送数据包超时时间,也就是数据包从AA没有按时到达BB端,这时候就会出现该数据包被丢弃的处理。因为不丢弃就没办法改善处理能力,保持网络通信效率。
                AA:在该连接上面发现了延迟丢包现象,为了确保数据包必须准确的到达对端,那我们继续发相同的数据包。
                CC:尼玛,越积越多,AA你能发慢一点吗?让我先及时处理积压,等通道畅通了你再发。
    上述场景,在TCP连接机制里面提供一个拥塞预防的机制。就是说,通过TCP连接建立,慢启动等达到了发送端发送数据量最佳速率(可能是变化的),但是中间传输路由节点可能会发生处理拥塞的问题。
     拥塞预防的主要思路:就是以网络丢包为标记的,也就是一旦出现网络丢包的情况,就启动响应的调度算法,按照比例的降低TCP的传输速率。这个时候就要求各自双方调整窗口了,一旦窗口调整降低之后,网络恢复正常,则又开始重新动态调整回来。
     为了达到这样的效果,动态调整都要等每次确认ACK来回才可以进行下一步的操作,因此一次来回的增加的延迟就看之间传输的距离了。
    V.其他因素
    TCP是不可靠信道上面实现可靠传输。分组的错误检测、纠正啊、按序交付啊,丢包重发等这些都是TCP底层机制,面向应用程序是屏蔽的,应用对TCP重发和缓冲区种排队分组是不清楚的,只能靠访问接口上面来感知数据分组到达的延迟。这是使用TCP连接应用层面需要付出的代价。
    因为可靠传输各自排队、检验、纠正的机制,让一个消息从发送端到接收端到达的时间不可预测,这个时间经常是变化的,通信术语上面称为“抖动”,这个也是影响应用性能的一个因素。

2.理解底层通信原理上层优化策略
    经过前面描述了web应用底层那么多的核心思路,基本上对基于TCP连接的开销有一个简单的认识。那么来看看站在应用者的角度,都怎么来优化并且提升自己应用达到低延迟、高吞吐的目标。
    1)针对网络的优化
        需要对网络通信机制有深入认识,TCP机制导致了创建一个新连接需要付出一定的延迟开销,同时为了达到连接上带宽的最大利用率,通过慢启动动态实现调整,也带来了延迟开销。
            优化1:TCP连接一旦创建之后,能复用就尽量复用!
        优化场景使用:
                a. web应用层协议HTTP在1.1标注和之后,支持了TCP长连接复用机制,也就是在一个连接上可以多次请求交互。在这之前,都是请求结束,连接断开,然后继续再创建新的连接。
                b.在web域的每一层几乎都能看到TCP长连接的影子,也就是不论你系统怎么切分,垂直、水平,只要涉及之间通信情况的,不管是私有协议还是标注HTTP协议,基本上都是复用连接。比如haproxy、ngnix等开源代理、反向代理服务器,面向后端都支持长连接机制。核心服务域就更多了,J2EE中的远程调用,RPC等。
            优化2:主机层面网络优化设置
                a. 接收窗口rwnd和拥塞窗口cwnd是网络传输带宽利用率提升的重要因素,rwnd决定了接收每次处理数据量限制,可以通过设置本地服务器将其放到最新Linux内核最大的限制,比如1G字节。最新的内核都是默认启动的。可以检查确认下。
                b. 拥塞窗口受慢启动的算法影响,通过TCP连接上面的来回确认ACK分组,逐步的放大。可以将其设置为最大值,减少这种来回慢启动的过程,减少延迟。这两个值在Linux中都有默认设置变量initrwnd和initcwnd,可以手动修改。
                c. 还有一些最新的算法支持比如TCP快速打开,比例降速这些都在最新的Linux内核里面支持,所以尽量考虑使用最新的Linux内核的版本,来达到优化网络通信的效果。
            优化2:距离是一个重要的因素,在带宽稳定的情况下,缩短访问距离最重要!另外就是既然延迟无法避免,那能减少发送传输就减少使用。
        优化场景使用:
                距离的延迟主要是因为传输速率的影响,目前传输最快也无法超越光速。因此如果发送端和接收端的距离超出一定限制,就开始采用一些缩短距离的技术手段,比如部署多个数据中心,CDN等应用,目标都是离用户接入近一点。这一点典型的就是运营商,甚至会在每个省都建立一套完整的系统,来解决地域带来的系统架构挑战的问题。
            优化3:另外就是既然延迟无法避免,那能减少发送传输就减少使用。
        优化场景使用:
                减少发送传输情况,在应用系统里面最多的使用就是缓存cache。既然无法解决实时访问,因为系统分层、分布式导致的数据来回传递的延迟问题,那就尽快的通过缓冲机制,将其推送到最近需要的地方。减少大规模访问下,数据实时传递带来的延迟。这方面还有很多其它的技术运用。
            
总结:
    无论更多环节访问的web应用、还是纯后台的分布式计算应用系统,只要跨越了单机运行场景,就开始与网络通信相关,伴随着网络通信机制带来的延迟一直做斗争。网络通信领域有很多复杂的算法机制,解决和维护整个网络的通信能力,这里只是总结分享一下一些基础认识。一篇分享文章写这么多估计没人有耐心看,就到这里先结束。后面再看看web应用访问应用层HTTP都有哪些需要了解的基本原理,性能优化的手段。
    另外是想说明一个问题,在现在这个时期,计算资源越来越便宜的基础下,cpu、内存终于不需要像以前我们写应用程序节省着用了。那么了解了上述基本情况后,性能和吞吐量两个追求的目标在应用设计的时候就需要去重点平衡

附:
著名的Hibernia Express专线
    据说在金融市场上,很多交易算法最先考虑的因素是延迟,因为几毫秒、几十毫秒延迟就可能导致百万美元收益或者损失。华为和这家公司合作,铺设横跨大西洋的海底光缆,减少了伦敦和纽约之间网络通信距离。节省了5ms,耗资4亿美金,1ms成本是8000万美金



  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值