收藏 分享(赏)

CUBIC TCP拥塞算法.doc

上传人:精品资料 文档编号:10624149 上传时间:2019-12-09 格式:DOC 页数:5 大小:33.10KB
下载 相关 举报
CUBIC TCP拥塞算法.doc_第1页
第1页 / 共5页
CUBIC TCP拥塞算法.doc_第2页
第2页 / 共5页
CUBIC TCP拥塞算法.doc_第3页
第3页 / 共5页
CUBIC TCP拥塞算法.doc_第4页
第4页 / 共5页
CUBIC TCP拥塞算法.doc_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

1、TCP 拥塞控制算法及 Linux 内核实现1. 引言由于 Internet 是一种基于 Best-Effort 服务的网络,传输控制协议 TCP 却能够在不可靠的互联网上提供可靠的服务,所以说 TCP 已经得到了大量的部署和使用并且统治着几乎全部的 Internet 数据流量。然而 TCP 协议的性能又在很大程度上由 TCP 拥塞控制算法决定,当今互联网上的算法又实在太多,如果想要专心研究几个算法还真不知道应该研究那些,不过有过研究称现在传统的 AIMD 算法已经不再是用得最多的算法了1。不过在研究中只是对前 5000 的服务器进行了一个并不一定准确的测定,笔者认为现在很多的很多服务器还是基

2、于 Linux 操作系统,很多人并不会对原本的算法进行修改也没有多大的必要,我们通过查看/proc/sys/net/ipv4/tcp_congestion_control 可以发现现在的 Linux 内核默认是 cubic 算法,所以我笔者猜测之前的研究1虽然是基于真正的事实,但是毕竟是最大的服务器集群,那是属于一个很专业的系统,也就是说管理员很有可能在每个地方都尽量给出最好的方案,但是大多数普通的服务器并没有这个必要,也就是说那 5000 个流量最大的服务器集群并不能够真实地反应我们当今 Internet 上的算法部署情况。毫无疑问的是现在的服务器大多都是 Linux 内核,相信 cubic

3、 以及一些别的 Linux 内核内置的算法在整个 Internet 上占有的比率肯定大于之前的研究。本文并不会在具体的占有率上进行研究,只是谈及一下 Linux 内核 2.6.36 版本的 TCP 拥塞控制算法实现,同时会介绍一下Linux 的 TCP 拥塞控制。2. TCP 拥塞控制简介我们知道现在的整个互联网体系结构是以 IP 协议为基础的,是一种基于无连接的端到端的报文传输服务,端到端传输的有点很多,但是有一个基本的问题就是需要自己来保证数据的可靠性。所以说 TCP 的拥塞控制对于整个 Internet 来说都是非常重要的,本文就将对 Linux 操作系统的拥塞控制算法进行一定的源码分析

4、,更为深层次的分析笔者可能会在以后做一定的阐述。先来看一下 TCP 是如何保证数据的可靠传输的2,TCP 的设计其实非常容易理解的,TCP 对所传输的数据都做了序号标记,序号按着字节数来增长,TCP 的接收方在接到数据后发出一个确认(ACK )给对端,ACK 里面包含一个序列号,这个序列号 n 表示序号在 n 之前的数据已经全部收到了,现在期待序号为 n 的数据到来。我们必须要知道的一个事实就是,主机发去网络上的任何一个数据包都有可能在网络上被丢弃,由于网络中路由器处理能力限制、链路错误等原因都会导致数据包的丢弃。如果 ACK 被丢弃了的话,那么就要靠重传机制了。TCP 对发出去的数据包都保留

5、有计时器,如果定时器到而确认还没有收到的情况下,TCP 会对刚才发送的数据包进行重传。TCP 使用确认和超时重传机制保障了数据的可靠性传输。当网络中存在过多的报文时,网络的性能就会相应下降,这种现象就被称为拥塞。TCP 的拥塞控制有很多的机制(慢启动、拥塞避免、快速重传、快速恢复等), 具体的一些工作方式在很多书籍论文中都已经有所阐述,本文将不再赘述。3. Linux 源码概述作为黑客们技术和梦想的结晶,Linux 无疑是这个世纪黑客们以及那些开源爱好者们最大的创举,有时候不禁感慨如果这个世界没有 Linux 或是 Unix 将是怎样,应该来说肯定会有别的系统来替代 Linux 的位置,但是现

6、在, Linux 在这么多年的发展,在世界的各个地方都布满了 Linux 的身影,尤其是这几十年随着 Internet 的迅速发展,Linux 这样一个开源的操作系统更是大发神威,因为其在 Internet 上的出色表现(稳定、可定制、免费等),现在的 Linux 操作系统已经成为Internet 上最重要的操作系统,为世界的交流和互通提供了最基本的服务。既然 Linux 在现代社会和 Internet 占有这么重要的地位,那么毫无疑问的是这个系统上的任何一个设计,尤其是关于网络的设计对整个互联网而言都是非常重要的,笔者也是考虑到这个问题所以说选择 Linux 的源码来分析我们所探讨的主题。但

7、是因为笔者时间并不宽裕,很多地方也没有深入去研究,所以说肯定还有很多需要提升的地方,待日后再返工。4. Linux 源码分析一:基本数据结构和函数Linux 内核支持相当多种的 TCP 拥塞控制算法,不过在内核 2.6.19 版本之后默认的算法调成了CUBIC 算法。首先说说 Linux 内核拥塞控制算法实现的框架, Linux下面介绍一下 Linux 内核实现拥塞控制的几个共同的数据结构或函数:1) inet_connection_sock 是 Linux 内核拥塞控制实现相当重要的一个数据结构。由于这个数据结构实在太大,具体的定义可以参考 include/inet/inet_connect

8、ion_sock.h 里面的定义,这里笔者就大概拿出几个比较重要的来说一下吧。首先是 const struct tcp_congestion_ops *icsk_ca_ops, 这个结构体指向的是一个包含大量的处理拥塞控制算法的指针,结构体中还有一个是 u32 icsk_ca_priv16, 这里的作用是放置拥塞控制模块需要的变量控制,也就是算法运行过程中需要的那些常量都是保存在这里的,具体的赋值运行过程由于在代码里面也没有太多的注释所以很难理解深刻,需要注意的一点是 Linux 内核设定了一套算法注册和删除的体系。其实就是一个链表,把新注册的数据结构插在链表的第一位,连接建立的时候会把最新注

9、册的算法数据结构赋给连接;当然我们也是可以调整算法顺序的,/proc/sys/net/ipv4/tcp_congestion_contril 就是干这个事的。2) Tcp_sock 这个结构体是一个很重要的结构体,里面定义了相当多的和 TCP 拥塞控制有关的,这个结构体非常大,具体的定义在 include/linux/Tcp.h 里面,下面大概介绍一下比较重要的几个参数:struct tcp_sock . u32 window_clamp ; /* 最大窗口值 */ u32 rcv_ssthresh ; /* 当前窗口阈值 */ u32 rcv_wnd ; /* 当前接收窗口大小 */ . /

10、* snd_wll 记录发送窗口更新时,造成窗口更新的那个数据报的第一个序号。 * 它主要用于在下一次判断是否需要更新发送窗口。 */ u32 snd_wll ; /* 用于窗口更新的 seq 值 */ u32 snd_wnd ; /* 发送窗口的大小,直接取值于来自对方的数据报的 TCP 首部 */ u32 max_window ; u32 snd_una ; . u32 snd_ssthresh ; /* 慢启动的阈值 */ u32 snd_cwnd ; /* 发送方拥塞窗口 */ /*表示在当前的拥塞控制窗口中已经发送的数据段的个数*/ u32 snd_cwnd_cnt ; /* 增长因

11、子 */ u32 snd_cwnd_clamp ; /* 增长因子的最大值 */ . u32 mss_cache ; /* 有效 mss 值 */ u32 bytes_acked ; /* ACK 的计数 */ . 3) Tcp_slow_start 这个方法是定义在 net/ipv4/tcp_cong.c 文件中的一种方法。当拥塞窗口小于慢启动阈值的时候就会启动。主要在 RFC2581 中定义。void tcp_slow_start(struct tcp_sock *tp)int cnt; /* 报文数目 */if (sysctl_tcp_abc /* ACK 接收完毕 */if (sysc

12、tl_tcp_max_ssthresh 0 /* 受限慢启动 */elsecnt = tp-snd_cwnd; /* 指数递增 */if (sysctl_tcp_abc 1 tp-snd_cwnd_cnt += cnt;while (tp-snd_cwnd_cnt = tp-snd_cwnd) tp-snd_cwnd_cnt -= tp-snd_cwnd;if (tp-snd_cwnd snd_cwnd_clamp)tp-snd_cwnd+;4) 拥塞避免算法 tcp_cong_avoid_ai 定义于 netipv4Tcp_cong.c,这个算法其实就是判断一下当前发送拥塞窗口和一个传入参数

13、 w 进行比较,如果发送计数器大于 w 且发送窗口没有到达阈值就自增,如果到达阈值了就置为 0;如果发送计数器压根没有大于 w 的话计数器自增。5. Linux 源码分析二:cubic 算法前面的介绍可能不是很清楚,如果想要更全面更清楚弄清楚这个流程可能需要更多的资料和代码研究,本文限于篇幅和笔者的水平只能尽力描述一下这一块的实现及主要的结构流程,那么我们接下来看一看默认算法 cubic 的代码实现。首先和很多别的算法都一样,cubic 算法会调用 tcp_slow_start 这个方法来处理 slow start,内核中的 slow start 的实现机制是接收一个 ack,snd_cwnd

14、 就会加 1,然后当 cwnd 大于设置的拥塞窗口阈值的时候就会进入拥塞避免状态。而在发送数据包的时候回判断这个值,在 in_flight 字段大于它的时候就会停止发包。因为 cubic 算法的设定是一直都通过慢启动来调整窗口大小的,当然,具体的这个算法特性本文不会讲得太多。我们通过分析源码可以知道,在 slow start 的状态时发送拥塞窗口就是简单地每次加一,进入拥塞避免后,拥塞窗口的增大速度就会变慢很多3。算法的核心状态控制代码定义在 net/ipv4/Tcp_bic.c 如下:static void bictcp_cong_avoid(struct sock *sk, u32 ack

15、, u32 in_flight)struct tcp_sock *tp = tcp_sk(sk);struct bictcp *ca = inet_csk_ca(sk);if (!tcp_is_cwnd_limited(sk, in_flight)/判断拥塞窗口是否达到限制return;if (tp-snd_cwnd snd_ssthresh)/决定下一步进入的状态tcp_slow_start(tp);else bictcp_update(ca, tp-snd_cwnd);tcp_cong_avoid_ai(tp, ca-cnt);这段代码主要是控制状态之间的转换,接下来会有一个 tcp_is

16、_cwnd_limited 的函数来实现对拥塞窗口的检测,通过这个函数我们可以知道是否还能继续添加包。int tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)const struct tcp_sock *tp = tcp_sk(sk);u32 left;if (in_flight = tp-snd_cwnd) /in_flight 的计算很纠结,应该是和未确认数据包相关的一个参数return 1;/未发送的报文left = tp-snd_cwnd - in_flight;if (sk_can_gso(sk) return lef

17、t = tcp_max_burst(tp);/所以返回的是 1 就是被限制,需要增加窗口这个算法的主要代码都在 Tcp_cong.c、 Tcp_cubic.c 两个文件里面,有很多的相关的设置没有弄得很清楚,反正最后的拥塞避免处理就是 tcp_cong_avoid_ai, 这里决定是否增加拥塞窗口的值,否则增加snd_cwnd_cnt。大体的流程和主要函数就如上所述。6. 总结内核代码的研究是一件非常富有挑战而艰难的工作,其实笔者最后并没有把这些为数不少的代码完全串起来,应该说就算是现在网上有一些代码分析,但是很多都是有问题的,内核代码的注释也并不足以让一个菜鸟一下子能够理解整个流程,这是一个真正的大工程,可能在一些专门的互联网公司中会有一定的总结和经验,但是并没有真正比较权威的分析报告在网上来让那些对开源感兴趣的大学生或别的入门级的感兴趣的人来做一个参考,本文的分析自然是纰漏无数,逻辑也并不缜密,只是希望更多的人能够感受到开源的魅力,让更多的人加入到开源社区中去真正实现自己技术上的价值。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报