高性能网络编程系列

本系列转自陶辉大牛的博客。

高性能网络编程(一)----accept建立连接

高性能网络编程2----TCP消息的发送

  1. SO_SNDTIMEO
    发送超时时间,可以简单的认为是把用户态数据copy到TCP发送缓冲区的超时时间。
    JVM中该参数就是0。

3. 高性能网络编程3----TCP消息的接收

3.1 四种队列

为了功能区分和减小并发加锁竞争,所以组织了多种队列
1.1 receive(数据是已去除TCP协议之后的可以直接被copy到用户态的数据)
1.2 out-of-order
1.3 prequeue
1.4 backlog(socket被加锁时放入)

3.2 prequeue与tcp_low_latency

当有socket正在睡眠以等待更多的数据时,新到的包根据tcp_low_latency的配置可能到prequeue队列,也可能到receive或者out-of-order队列。
tcp_low_latency默认为0,即关闭,此时新到的包进入tcp_low_latency

3.2.1 prequeue

  1. tcp_low_latency打开时
    在TCP中断时需要处理ACK响应等TCP协议,去除TCP头等信息(放入receive队列的需要去除),甚至还可能把数据直接copy到用户态buffer。
    所以,这种模式下用户进程能快速的得到数据,但是软中断的时间长,造成TCP吞吐量下降。
  2. tcp_low_latency关闭时
    与普通机制的主要区别在于,在进程没有收取到足够的数据而睡眠等待时,prequeue机制会将skb放入prequeue队列中再唤醒进程,再由进程对skb进行TCP协议处理,再copy数据;而普通模式下skb会在软中断上下文处理,在放入sk->sk_receive_queue队列中后再唤醒进程,进程被唤醒后只是copy数据。对比普通模式,prequeue机制下使得skb的TCP协议处理延迟,延迟的时间为从skb被放入prequeue队列并唤醒进程开始,到进程被调度到时调用tcp_prequeue_process函数处理skb时截止。对于收数据的进程而言在一次数据接收过程中其实并没有延迟,因为普通模式下进程也会经历睡眠-唤醒的过程。但由于TCP协议处理被延迟,导致ACK的发送延迟,从而使数据发送端的数据发送延迟,最终会使得整个通信过程延迟增大。现在我们知道prequeue机制延迟大的原因了:skb的TCP协议处理不是在软中断中进行,而是推迟到应用进程调用收包系统调用时。

3.2.2 为什么有用户进程因等待数据睡眠时才有tcp_low_latency机制

因为有进程在等待,所以可以让新到的包的TCP协议完成由等待的进程完成。

3.3 一些参数

  1. SO_RCVTIMEO
    JAVA不不支持设置该参数,该参数JVM设的为0
  2. SO_RCVLOWAT
    《UNIX网络编程中》描述该参数用于select/epoll,和本位描述不符。
  3. TP_LOW_LATENCY

4. 网络编程4--TCP连接的关闭

4.1 监听句柄的关闭

半连接直接发RST

4.2 关闭ESTABLISH状态的连接

  1. 如果还有数据未读取
    发RST
  2. 如果还有待发送的数据
    发送,在最后一个报文加上FIN
  3. so_linger
    so_linger是close(无论socket是否工作在阻塞模式,都是阻塞的)的超时时间,用来尽量保证对方收到了close时发出的消息,即,至少需要对方通过发送ACK且到达本机。

5. 高性能网络编程5--IO复用与并发编程

  1. select和epoll
    select每次调用都需要把所有欲监控的socket传入内核态
  2. epoll提供的2种玩法ET和LT
    LT是每次满足期待状态的连接,都得在epoll_wait中返回,所以它一视同仁,都在一条水平线上。ET则不然,它倾向更精确的返回连接。在上面的例子中,连接第一次变为可写后,若是程序未向连接上写入任何数据,那么下一次epoll_wait是不会返回这个连接的。ET叫做 边缘触发,就是指,只有连接从一个状态转到另一个状态时,才会触发epoll_wait返回它。可见,ET的编程要复杂不少,至少应用程序要小心的防止epoll_wait的返回的连接出现:可写时未写数据后却期待下一次“可写”、可读时未读尽数据却期待下一次“可读”。

6. 高性能网络编程6--reactor反应堆与定时器管理

7. 高性能网络编程7--tcp连接的内存使用

net.ipv4.tcp_rmem = 8192 87380 16777216  
net.ipv4.tcp_wmem = 8192 65536 16777216  
net.ipv4.tcp_mem = 8388608 12582912 16777216  
net.core.rmem_default = 262144  
net.core.wmem_default = 262144  
net.core.rmem_max = 16777216  
net.core.wmem_max = 16777216  

7.1 net.ipv4.tcp_adv_win_scale = 2

读取缓冲包含两部分:

  1. 于应用程序的延时报文读取
  2. 接收窗口

tcp_adv_win_scale意味着,将要拿出1/(2^tcp_adv_win_scale)缓存出来做应用缓存。即,默认tcp_adv_win_scale配置为2时,就是拿出至少1/4的内存用于应用读缓存,那么,最大的接收滑动窗口的大小只能到达读缓存的3/4。

7.2 初始的拥塞窗口

以广为使用的linux2.6.18内核为例,在以太网里,MSS大小为1460,此时初始窗口大小为4倍的MSS。有些网络中,会在TCP的可选头部里,使用12字节作为时间戳使用,这样,有效数据就是MSS再减去12,初始窗口就是(1460-12)4=5792*,这与窗口想表达的含义是一致的,即:我能够处理的有效数据长度。

在linux3以后的版本中,初始窗口调整到了10个MSS大小,这主要来自于GOOGLE的建议。原因是这样的,接收窗口虽然常以指数方式来快速增加窗口大小(拥塞阀值以下是指数增长的,阀值以上进入拥塞避免阶段则为线性增长,而且,拥塞阀值自身在收到128以上数据报文时也有机会快速增加),若是传输视频这样的大数据,那么随着窗口增加到(接近)最大读缓存后,就会“开足马力”传输数据,但若是通常都是几十KB的网页,那么过小的初始窗口还没有增加到合适的窗口时,连接就结束了。这样相比较大的初始窗口,就使得用户需要更多的时间(RTT)才能传输完数据,体验不好。

7.3 接收窗口应该设置多大?

image.png

所以:接收buffer大小=BDP*4/3

7.4 内存

7.4.1 TCP缓存上限自动调整策略关闭

  1. SO_SNDBUF和SO_RCVBUF
    应用程序可以为某个连接设置的参数,分别代表写缓冲和读缓冲的最大值。
    在内核中会把这个值翻一倍再作为写缓存上限使用。
  2. net.core.wmem_max和net.core.rmem_max
    操作系统级别的定义的参数。当SO_SNDBUF和SO_RCVBUF大于系统级的参数时,以系统级的为准。
    在内核中也会把这个值翻一倍再作为写缓存上限使用。
  3. net.core.rmem_default和net.core.wmem_default
    定义了读写缓冲区大小的默认值

7.4.2 TCP缓存上限自动调整策略

在并发连接比较少时,把缓存限制放大一些,让每一个TCP连接开足马力工作;当并发连接很多时,此时系统内存资源不足,那么就把缓存限制缩小一些,使每一个TCP连接的缓存尽量的小一些,以容纳更多的连接。
net.ipv4.tcp_moderate_rcvbuf = 1
默认tcp_moderate_rcvbuf配置为1,表示打开了TCP内存自动调整功能。若配置为0,这个功能将不会生效(慎用)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 最近在部门内做了个高性能网络编程的培训,近日整理了下PPT,欲写成一系列文章从应用角度谈谈它。 编写服务器时,许多...
    泥孩儿0107阅读 243评论 0 1
  • 最近在看《UNIX网络编程 卷1》和《FREEBSD操作系统设计与实现》这两本书,我重点关注了TCP协议相关的内容...
    腩啵兔子阅读 1,144评论 0 7
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,563评论 18 139
  • 相逢不语,一朵芙蓉著秋雨。 小晕红潮,斜溜鬟心只凤翘。 待将低唤,直为凝情恐人见。 欲诉幽怀,转...
    孤寂的猫生阅读 262评论 0 1