• Linux TCP 单机优化


    TCP 的 send 函数 tcp_sendmsg/tcp_sendpage,要调用 lock_sock(sk)。

    TCP 的 recv 函数 tcp_recvmsg,也要调用 lock_sock(sk):

    void lock_sock_nested(struct sock *sk, int subclass)
    {
            might_sleep();
            spin_lock_bh(&sk->sk_lock.slock);
            if (sk->sk_lock.owned)
                    __lock_sock(sk);
            sk->sk_lock.owned = 1;
            spin_unlock(&sk->sk_lock.slock);
            /*
             * The sk_lock has mutex_lock() semantics here:
             */
            mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_);
            local_bh_enable();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    __lock_sock 的核心即睡眠等锁。

    这意味着 TCP socket 的 send 和 recv 互斥。睡眠等锁期间,CPU 时间不属于该 socket。

    不光如此,软中断上下文 tcp_v4_rcv 处理 TCP 接收间,无论 send 还是 recv 均会在一个 spinlock 自旋,这意味着软中断 TCP 接收间,send 无法进行,recv 亦无法读取已按序齐整排入 receive queue 的数据。

    这就是我常说的,TCP 称全双工传输,但 Linux TCP 实现却是半双工。我并不认为这是高尚的:
    Linux TCP并不是全双工的

    很多人怼我,说我根本不懂双工的概念,涉及到物理层,信道。我想他们并没有理解我在说什么。再解释也苍白,引用 iperf-2.0.14a 的 manual 来解释 socket 双工:

    –full-duplex
    run a full duplex test, i.e. traffic in both transmit and receive directions using the same socket

    在我看来,高尚的做法是只保护读写共享的数据,细化锁粒度:

    • sk_write_queue:发送队列,socket 进程上下文写入,tcp_write_xmit 进程上下文或软中断上下文摘除。
    • tcp_rtx_queue:重传队列,socket 进程上下文或软中间上下文写入,tcp_clean_rtx_queue 软中断上下文摘除。
    • sk_receive_queue:接收队列,socket 进程上下文 release_sock 或软中断上下文写入,socket 进程上下文摘除。

    保护好这些数据结构,再小心翼翼处理一下其它共享元数据,send/recv/tcp_v4_rcv 即可并行。事情会高尚很多。

    迄今为止,我想因为 Linux TCP 单机性能尚未触及瓶颈,拆锁重构工作量成本不小,却没有眼见的收益,社区没人闲着做这事。如今 100 Gbps 网卡越来越多,这些细节早晚会被盯上。

    但还有一条路,若 DPDK 可实现好用的 TCP,内核协议栈可能就这么放着永远不动了:

    • DPDK 提供高性能版本 TCP。
    • Kernel 提供通用完备 TCP。

    外说一句,曾经 UDP 也是类似 lock_sock,可能也是因为一把梭哈实现简单,后面随着 UDP 应用逐步推广,可能是 QUIC 加持也可能不是,UDP 的 lock_sock 消失了,锁粒度细化到保护特定的共享 queue,最终,连 queue 都拆成了两个,便于批量处理:

    • Linux内核UDP收包为什么效率低?能做什么优化?
    • Linux内核UDP收包为什么效率低?能做什么优化?

    这也是历史发展的轨迹。

    弄蟹!80块钱弄蟹,两大四小。

    浙江温州皮鞋湿,下雨进水不会胖。

  • 相关阅读:
    Centos切换yum源
    【WebService笔记02】使用CXF框架实现WebService接口的发布和调用
    从零开始Blazor Server(6)--基于策略的权限验证
    img图片丢失后默认图
    利用向日葵和微信/腾讯会议实现LabVIEW远程开发
    kubernetes helm
    CSS中calc(80vw - 100px)为什么不加空格会不生效?
    SQL使用技巧
    Jmeter使用
    2.4 自定义msg Python
  • 原文地址:https://blog.csdn.net/dog250/article/details/126438507