理解了实现再谈网络性能-总结

文章目录

        • TCP 连接的 CPU 开销
          • LINUX 是如何接收⼀个⽹络包的
            • **收包过程**
            • IO 多路复⽤ EPOLL 内部实现
            • ⽹络包处理之 CPU 开销汇总
        • TCP 连接的 内存 开销
        • TCP 连接的时间开销
          • **TCP 连接建⽴时的异常情况**
            • **客户端connect系统调⽤耗时失控**
            • **半/全连接队列满**
        • LINUX ⽹络性能优化建议
          • **耗时优化建议**
            • 建议1:尽量减少不必要的⽹络 IO
            • 建议2:内⽹调⽤不要⽤外⽹域名
            • 建议3:调⽤者与被调⽤机器尽可能部署的近⼀些
            • 建议4: 如果请求频繁,请弃⽤短连接改⽤⻓连接
            • 建议5:如果可能尽量合并⽹络请求
            • 建议6:注意你的半连接、全连接队列的⻓度
          • **内存优化建议**
            • 建议1:设置合适的收发缓存区⼤⼩
            • 建议2:使⽤ mmap 减少拷⻉
            • 建议3: sendfile
          • **CPU 优化建议**
            • 建议1:监控 ringbuffer与调优
            • 建议2:硬中断监控与调优
            • 建议3:硬中断合并
            • 建议4:软中断 budget 调整
            • 建议5:软中断 Gro 合并
            • 建议6:减少拷⻉
            • 建议7:减少进程上下⽂切换
            • 建议8:配置充⾜的端⼝范围
        • 项⽬实际问题分析
          • 我的机器上出现了 3 万多个TIME_WAIT,开销有 哪些?
          • 我的 REDIS SERVER 上 6000 多个⻓连接,会不 会把我搞垮?
          • 服务器负载很正常,但是 CPU 被打到底了怎么 回事?
          • 我要做⼀个⻓连接推送模块,1亿⽤户需要多少 台机器?

TCP 连接的 CPU 开销

LINUX 是如何接收⼀个⽹络包的

CPU 在向内存要数据的时候是以 Cache Line 为单位进⾏的,⼀个 Cache Line 是 64 字节

inet_protos 记录着 udptcp 的处理函数地址,ptype_base 存储着 ip_rcv() 函数的处理地址

ethtool 命令之所以能查看⽹卡收发包统计、能修改⽹卡⾃适应模式、能调整 RX 队列的数量和⼤⼩,是因为 ethtool 命令最终调⽤到了⽹卡驱动的相应⽅法,⽽不是 ethtool 本身有这个超能⼒。

Linux 在硬中断⾥只完成简单必要的⼯作,剩下的⼤部分的处理都是转交给软中断的,硬中断处理过程真的是⾮常短。只是记录了⼀个寄存器,修改了⼀下下 CPU 的poll_list,然后发出个软中断

只要硬中断在哪个 CPU 上被响应,那么软中断也是在这个 CPU 上处理的

收包过程

当⽤户执⾏完 recvfrom 调⽤后,⽤户进程就通过系统调⽤进⾏到内核态⼯作了。如果接收队列没有数据,进程就进⼊睡眠状态被操作系统挂起。这块相对⽐较简单,剩下⼤部分的戏份都是由 Linux 内核其它模块来表演了。

⾸先在开始收包之前,Linux 要做许多的准备⼯作:

  • 创建ksoftirqd线程,为它设置好它⾃⼰的线程函数,后⾯就指望着它来处理软中断呢。
  • 协议栈注册,linux要实现许多协议,⽐如arp,icmp,ip,udp,tcp,每⼀个协议都会将⾃⼰的处理函数注册⼀下,⽅便包来了迅速找到对应的处理函数
  • ⽹卡驱动初始化,每个驱动都有⼀个初始化函数,内核会让驱动也初始化⼀下。在这个初始化过程中,把⾃⼰的DMA准备好,把NAPI的poll函数地址告诉内核
  • 启动⽹卡,分配RX,TX队列,注册中断对应的处理函数

以上是内核准备收包之前的重要⼯作,当上⾯都 ready 之后,就可以打开硬中断,等待数据包的到来了。

当数据到到来了以后,第⼀个迎接它的是⽹卡:

  • ⽹卡将数据帧 DMA 到内存的 RingBuffer 中,然后向 CPU 发起中断通知
  • CPU 响应中断请求,调⽤⽹卡启动时注册的中断处理函数
  • 中断处理函数⼏乎没⼲啥,就发起了软中断请求
  • 内核线程 ksoftirqd 线程发现有软中断请求到来,先关闭硬中断
  • ksoftirqd 线程开始调⽤驱动的 poll 函数收包
  • poll 函数将受到的包送到协议栈注册的 ip_rcv 函数中
  • ip_rcv 函数再讲包送到 udp_rcv 函数中(对于 tcp 包就送到 tcp_rcv )

内核在通知⽹络包的运⾏环境分两部分:

  • 第⼀部分是我们⾃⼰代码所在的进程,我们调⽤的 socket() 函数会进⼊内核态创建必要内核对象。 recv() 函数在进⼊内核态以后负责查看接收队列,以及在没有数据可处理的时候把当前进程阻塞掉,让出 CPU。
  • 第⼆部分是硬中断、软中断上下⽂(系统进程 ksoftirqd)。在这些组件中,将包处理完后会放到 socket 的接收队列中。然后再根据 socket 内核对象找到其等待队列中正在因为等待⽽被阻塞掉的进程,然后把它唤醒。

每次⼀个进程专⻔为了等⼀个 socket 上的数据就得被从 CPU 上拿下来。然后再换上另⼀个进程。等到 数据 ready 了,睡眠的进程⼜会被唤醒。总共两次进程上下⽂切换开销,根据之前的测试来看,每⼀ 次切换⼤约是 3-5 us(微秒)左右

IO 多路复⽤ EPOLL 内部实现

epoll 相关的函数是如下三个:

  • epoll_create:创建⼀个 epoll 对象
  • epoll_ctl:向 epoll 对象中添加要管理的连接
  • epoll_wait:等待其管理的连接上的 IO 事件

eventpoll 这个结构体中的⼏个成员的含义如下:

  • wq: 等待队列链表。软中断数据就绪的时候会通过 wq 来找到阻塞在 epoll 对象上的⽤户进 程。
  • rbr: ⼀棵红⿊树。为了⽀持对海量连接的⾼效查找、插⼊和删除,eventpoll 内部使⽤了⼀棵 红⿊树。通过这棵树来管理⽤户进程下添加进来的所有 socket 连接。
  • rdllist: 就绪的描述符的链表。当有的连接就绪的时候,内核会把就绪的连接放到 rdllist 链表 ⾥。这样应⽤进程只需要判断链表就能找出就绪进程,⽽不⽤去遍历整棵树

epoll 相关的函数⾥内核运⾏环境分两部分:

  • ⽤户进程内核态。进⾏调⽤ epoll_wait 等函数时会将进程陷⼊内核态来执⾏。这部分代码负责 查看接收队列,以及负责把当前进程阻塞掉,让出 CPU。
  • 硬软中断上下⽂。在这些组件中,将包从⽹卡接收过来进⾏处理,然后放到 socket 的接收队 列。对于 epoll 来说,再找到 socket 关联的 epitem,并把它添加到 epoll 对象的就绪链表 中。 这个时候再捎带检查⼀下 epoll 上是否有被阻塞的进程,如果有唤醒之。

⽹络包处理之 CPU 开销汇总

了解完了整个 TCP 协议下⽹络包的处理过程,现在我们总结⼀下其 CPU 开销都有哪些

  1. 系统态 CPU 开销:当⽤户进程调⽤ socket、connect、recvfrom 等等函数的时候,都会将⽤ 户进程陷⼊到内核态。在内核态⾥的 CPU 开销就是进程⾥的 sy 列。如果你的应⽤程序是⽹络 IO 密集型的,你的 sy 中可能⼤部分都是因为⽹络造成成。
  2. 硬中断、软中断开销:内核收到包以后会在硬中断、软中断上下⽂中进⾏内核相关⼯作的处理。 硬中断由于逻辑简单,⼀般不会成为系统的瓶颈。这也就是你查看 cpu 开销是,hi 这⼀列⼤部 分时候都是 0.0 的原因。但软中断中确确实实要执⾏好多好多的操作,包括协议栈的处理。在⽹ 络 IO 密集型应⽤中,si 会吃掉不少 CPU。
  3. 进程上下⽂切换:⽤户进程和内核在配合的时候有可能会引起进程的阻塞与唤醒。尤其是对于使 ⽤ recvfrom 系统调⽤的,每⼀次的等待都会造成进程被阻塞。当数据来临的时候,⼜会被唤 醒。在⽹络请求量⼤的时候,会消耗⾮常多 CPU 周期来执⾏进程的上下⽂切换。在 epoll 中改 善了很多,但当没有 IO 事件可做的时候,进程同样要被阻塞掉

TCP 连接的 内存 开销

linux 提供了⼀个特别⽅便的命令 slabtop 来按照占⽤内存从⼤往⼩进⾏排列。这个命令⽤来分析 slab 内存开销⾮常的⽅便。

通过下⾯描述的⼏个步骤,内核⾼效地把内存⽤了起来

  • 第⼀步:把所有的内存条和 CPU 划分成 node
  • 第⼆步:把每⼀个 node 划分成 zone
  • 第三步:每个 zone 下都⽤伙伴系统管理空闲⻚⾯
  • 第四步:内核提供 slab 分配器为⾃⼰专⽤
    在这里插入图片描述

上图可⻅,内核在 socket 内存开销优化上采取了不少⽅法

  1. 内核会尽量及时回收发送缓存区、接收缓存区,但⾼版本做的更好
  2. 发送接收缓存区最⼩并不⼀定是 rmem 内核参数⾥的最⼩值,实际可能会更⼩
  3. 其它状态下,例如对于TIME_WAIT还会回收⾮必要的 socket_alloc 等对象 另外注意,我们测试时发送的数据量很⼩。如果发送数据量⼤了的话,发送缓存区和接收缓存区会消耗 的更⼤。其对应的内核参数分别是 tcp_rmem 和 tcp_wmem。但是⼀旦发送或接收完毕,内核还是会 尽量回收这块内存

⼀台服务器最⼤可以⽀撑多少条TCP连接

一条空TCP连接共得3.3KB左右。 Linux 3.10.0 版本中,创建⼀个socket 需要消耗 densty、flip、sock_inode_cache、TCP 四个内核对象。这些对象加起来总共需要消耗⼤约 3 KB 多⼀点的内存。 如果连接上有数据收发的话,还需要消耗发送、接收缓存区。这两个缓存区占⽤内存影响因素⽐较 多,既受收发数据的⼤⼩,也受 tcp_rmem、tcp_wmem 等内核参数,还取决于服务器进程能否 及时接收(及时接收的话缓存区就能回收)

4个G内存情况下是可以维持100万条长连接(空连接)

Linux对最⼤⽂件对象数量有限制,所以要想完成服务器端百万连接这个实验,得在⽤户 级、系统级、进程级等位置把这个上限加⼤

接收缓存区⼤⼩是可以配置的,通过sysctl命令就可以查看。

sysctl -a | grep rmem

在tcp_rmem中的第⼀个值是为你们的TCP连接所需分配的最少字节数。该值默认是4K,最 ⼤的话8MB之多。也就是说你们有数据发送的时候我需要⾄少为对应的socket再分配4K内存,甚⾄可能更⼤。net.ipv4.tcp_wmem中的第⼀个值是发送缓存区的最⼩值,默认也是4K。当然了如果数据很⼤的话,该缓存区实际分配的也会⽐默认值⼤。

活动连接数量查询:ss -n | grep ESTAB | wc -l

内存大小查询:cat /proc/meminfo

ip_local_host_range host范围

TCP 连接的时间开销

在正常的TCP连接的建⽴过程中,⼀般可以考虑⽹络延时即可。⼀个RTT指的是包从⼀台服务 器到另外⼀台服务器的⼀个来回的延迟时间。所以从全局来看,TCP连接建⽴的⽹络耗时⼤约需要三次 传输,再加上少许的双⽅CPU开销,总共⼤约⽐1.5倍RTT⼤⼀点点。不过从客户端视⻆来看,只要ACK 包发出了,内核就认为连接是建⽴成功了。所以如果在客户端打点统计TCP连接建⽴耗时的话,只需要 两次传输耗时-既1个RTT多⼀点的时间。

TCP 连接建⽴时的异常情况

客户端connect系统调⽤耗时失控

后来经过排查以后发现当TCP客户端TIME_WAIT有30000左右,导致可⽤端⼝不是特别充⾜的时 候,connect系统调⽤的CPU开销直接上涨了100多倍,每次耗时达到了2500us(微秒),达到了毫秒 级别

strace -cp port

当遇到这种问题的时候,虽然TCP连接建⽴耗时只增加了2ms左右,整体TCP连接耗时看起来还可接 受。但是这⾥的问题在于这2ms多都是在消耗CPU的周期,所以问题不⼩。 解决起来也⾮常简单,办法很多:修改内核参数net.ipv4.ip_local_port_range多预留⼀些端⼝号、改⽤⻓连接都可以。

半/全连接队列满

如果连接建⽴的过程中,任意⼀个队列满了,那么客户端发送过来的syn或者ack就会被丢弃。客户端等 待很⻓⼀段时间⽆果后,然后会发出TCP Retransmission重传

在服务端的话,查看起来就更⽅便⼀些了。 netstat -s 可查看到当前系统半连接队列满导致的丢包统 计,但该数字记录的是总丢包数。你需要再借助 watch 命令动态监控。如果下⾯的数字在你监控的过 程中变了,那说明当前服务器有因为半连接队列满⽽产⽣的丢包。你可能需要加⼤你的半连接队列的⻓度了。

  • watch ‘netstat -s | grep LISTEN’

对于全连接队列来说呢,查看⽅法也类似。

  • watch ‘netstat -s | grep overflowed’

如果你的服务因为队列满产⽣丢包,其中⼀个做法就是加⼤半/全连接队列的⻓度。 半连接队列⻓度 Linux内核中,主要受tcp_max_syn_backlog影响 加⼤它到⼀个合适的值就可以。

全连接队列⻓度是应⽤程序调⽤listen时传⼊的backlog以及内核参数net.core.somaxconn⼆者之中 较⼩的那个。你可能需要同时调整你的应⽤程序和该内核参数。

改完之后我们可以通过ss命令输出的 Send-Q 确认最终⽣效⻓度:

  • ss -nlt

Recv-Q 告诉了我们当前该进程的全连接队列使⽤⻓度情况。如果 Recv-Q 已经逼近了 Send-Q , 那么可能不需要等到丢包也应该准备加⼤你的全连接队列了。

如果加⼤队列后仍然有⾮常偶发的队列溢出的话,我们可以暂且容忍。如果仍然有较⻓时间处理不过来 怎么办?另外⼀个做法就是直接报错,不要让客户端超时等待。例如将Redis、Mysql等后端接⼝的内核 参数tcp_abort_on_overflow为1。如果队列满了,直接发reset给client。告诉后端进程/线程不要痴情 地傻等。这时候client会收到错误“connection reset by peer”。牺牲⼀个⽤户的访问请求,要⽐把整 个站都搞崩了还是要强的。

以瞬间连接建⽴请求量很⼤,就会导致 全连接队列或者半连接队列被打满的情况。⼀旦发⽣队列满,当时撞上的那个连接请求就得需要3秒+的 连接建⽴延时

LINUX ⽹络性能优化建议

对于修改内核参数使⽤编辑 /etc/sysctl.conf ⽂件的⽅式来改,编辑完了执⾏⼀下 sysctl -p 就能⽣效。

耗时优化建议

建议1:尽量减少不必要的⽹络 IO

建议2:内⽹调⽤不要⽤外⽹域名

为什么要这么做,原因有以下⼏点

  • 1)调⽤外⽹服务接⼝会更慢。本来内⽹可能过个交换机就能达到兄弟部⻔的机器,你⾮得上外⽹都⼀ 圈再回来,时间上肯定会慢的多。
  • 2)带宽成本⾼。在互联⽹服务⾥,除了机器以外,另外⼀块很⼤的成本就是 IDC 机房的带宽成本。 两 台机器在内⽹不管如何通信都不涉及到带宽的计算。但是⼀旦你去外⽹兜了⼀圈回来,⾏了,⼀进⼀出 全部要缴带宽费,你说亏不亏!!
  • 3)NAT 单点瓶颈。⼀般的服务器都没有外⽹ IP,所以要想请求外⽹的资源,必须要经过 NAT 服务器。 但是⼀个公司的机房⾥⼏千台服务器中,承担 NAT ⻆⾊的可能就那么⼏台。⼀来它很容易成为瓶颈。 我们的业务就遇到过好⼏次 NAT 故障导致外⽹请求事变的情形。 ⼆来是个单点,⼀旦 NAT 机器挂了, 你的服务就挂了,故障率⼤⼤增加

建议3:调⽤者与被调⽤机器尽可能部署的近⼀些

我们看到在全连接队列、半连接队列不出问题的情况下, TCP 握⼿的时间基本取决与两台机器的 RTT 耗时

建议4: 如果请求频繁,请弃⽤短连接改⽤⻓连接

如果你的服务器频繁请求某个 server,⽐如 redis 缓存。那么⼀个⽐较好的⽅法是使⽤⻓连接。这样的 好处有

  • 1)节约了握⼿的时间开销。短连接中每次请求都需要服务和缓存之间进⾏握⼿,这样每次都得让⽤户 多等⼀个握⼿的时间开销。
  • 2)规避了队列满的问题。前⾯我们看到当全连接或者半连接队列溢出的时候,服务器直接丢包。⽽客户端呢并不知情,所以傻傻地等 3 秒才会重试。要知道 tcp 本身并不是专⻔为互联⽹服务设计的。这个 3 秒的超时对于互联⽹⽤户的体验影响是致命的。
  • 3)端⼝数不容易出问题。端连接中,在释放连接的时候,客户端使⽤的端⼝需要进⼊ TIME_WAIT 状 态,等待 2 MSL的时间才能释放。

建议5:如果可能尽量合并⽹络请求

建议6:注意你的半连接、全连接队列的⻓度

如果你使⽤了短连接,那么⼀定在服务流量⼤的时候要关注服务器上的这两个队列是否存在溢出的情 况。如果有,请加⼤它!因为⼀旦出现因为连接队列导致的握⼿问题,那么耗时都是秒级以上了。

我们如何查看我们⼿头的服务是否有因为半/全连接队列满的情况发⽣ 呢?

在服务器上,netstat -s 可查看到当前系统半连接队列满导致的丢包统计。但该数字记录的是总丢包 数,你需要再借助 watch 命令动态监控。

watch ‘netstat -s’

8 SYNs to LISTEN sockets ignored //半连接队列满导致的丢包
160 times the listen queue of a socket overflowed //全连接队列满导致的丢包

如果你⼿头并没有服务器的权限,只是发现⾃⼰的客户端机连接某个 server 出现耗时⻓,想定位⼀下 是否是因为握⼿队列的问题。那也有间接的办法,可以 tcpdump 抓包查看是否有 SYN 的TCP Retransmission。如果有偶发的TCP Retransmission, 那就说明对应的服务端连接队列可能有问题了。 Linux 内核中半连接队列⻓度主要受内核参数 tcp_max_syn_backlog 影响。如果需要,可以加⼤它。 全连接队列是应⽤程序调⽤ listen时传⼊的 backlog 以及内核参数 net.core.somaxconn ⼆者之中较 ⼩的那个。如果需要加⼤,可能两个参数都需要改

内存优化建议

建议1:设置合适的收发缓存区⼤⼩

建议2:使⽤ mmap 减少拷⻉

建议3: sendfile

CPU 优化建议

建议1:监控 ringbuffer与调优

Linux的整个⽹络栈中,RingBuffer起到⼀个任务的收发中转站的⻆⾊。对于接收过程来讲,⽹卡负责 往RingBuffer中写⼊收到的数据帧,ksoftirqd内核线程负责从中取⾛处理。只要ksoftirqd线程⼯作的⾜ 够快,RingBuffer这个中转站就不会出现问题。

我们使⽤ ethtool 来来查 看⼀下Ringbuffer

ethtool -g eth0

建议2:硬中断监控与调优

硬中断的情况可以通过内核提供的伪⽂件 /proc/interrupts 来进⾏查看。

现在的主流⽹卡基本上都是⽀持多队列的,我们可以通过将不同的队列分给不同的CPU核⼼来处理,从 ⽽加快Linux内核处理⽹络包的速度。这是最为有⽤的⼀个优化⼿段

建议3:硬中断合并

建议4:软中断 budget 调整

net.core.netdev_budget = 300,ksoftirqd⼀次最多处理300个包,处理够了就会把CPU主动让出来,以便Linux上其 它的任务可以得到处理

建议5:软中断 Gro 合并

建议6:减少拷⻉

在⽇常的⽹络使⽤场景中,如果是发送⽂件的场景。则要避免使⽤ read + send 的系统调⽤组合。通过 mmap 或者 sendfile 等系统调⽤不但能减少内存的开销,也还能减少拷⻉时的CPU花费

建议7:减少进程上下⽂切换

建议8:配置充⾜的端⼝范围

项⽬实际问题分析

我的机器上出现了 3 万多个TIME_WAIT,开销有 哪些?

其实这种情况只能算是 warning,⽽不是 error! 从内存的⻆度来考虑,⼀条 TIME_WAIT 状态的连接仅仅是 0.5 KB 的内存⽽已。 从端⼝的⻆度来考虑,占⽤的端⼝只是针对特定的 server 来说是占⽤了。只要下次连接的 server 不⼀ 样(ip 或者 端⼝不⼀样都算),那么这个端⼝仍然可以⽤来发起 TCP 连接。 ⽆论是从内存的⻆度,还是端⼝的⻆度⼀条 TIME_WAIT 的开销都并不那么可怕。如果你确实连这⼀点 点开销都想省,那你可以考虑打开 tcp_tw_recycle、 tcp_tw_reuse。如果再彻底⼀些,也可以⼲脆 直接⽤⻓连接代替频繁的短连接。

我的 REDIS SERVER 上 6000 多个⻓连接,会不 会把我搞垮?

  • 先看端⼝:每个客户ip只是⽤了1000个端⼝,离linux默认的3W差着远呢。所以客户端的端⼝使⽤率是没有问题 的。(有⼀种情况要注意,就是php连了很多个redis,甚⾄包括mysql等,这时候就要注意端⼝总量 了) 再看服务器端,服务器的端⼝不影响TCP连接数量,所以服务器端也不存在端⼝的问题。
  • 再看内存: 客户机来说,每个客户机仅仅维护1000个连接,占⽤的内存可以忽略了。不到 10 M ⽽已。对于 redis 来说,每个⻓连接⼤约需要 7 k 的内存(假设我们发送的数据都没有超过 4 k )。那么 2 万个连接需要 的内存为 140 M 内存。 再看 CPU和耗时 先说数据传输,短连接和⻓连接这块都是要占⽤的,所以没有讨论的必要。
  • 再说建⽴连接:这个⻓连接是有优势的,省去了频繁的 TCP 握⼿包对服务机的软硬中断开销。⽽且还 减少了客户机的单个服务的响应时间(⼀般情况下通往内⽹机器的 RTT 1ms 以内,so 你的服务也会节 约 1ms),这样服务能⼒也有所提升

结论

如果你的server压⼒不是特别⼤,短连接挺好。多⼀点cpu的开销,但是没有维护连接的成本,也不会 触发server⽂件句柄超默认值的问题。 但是如果你的server请求量较⼤,看起来Redis维护成千上万的⻓连接很可怕,但其实⽤量化的指标对其 计算⼀遍以后发现,⻓连接的开销其实只是多⼀些内存占⽤⽽已,另外就是可能需要适当调节⼀下服务 器的最⼤⽂件句柄限制。Don’t afraid,如果到了该⽤⻓连接的时候就⽤。

服务器负载很正常,但是 CPU 被打到底了怎么 回事?

之前,我⼀直觉得 CPU 和负载是正相关关系。CPU ⾼的话,负载就会⾼。但其实负载是统计就绪状态 进程的排队情况。 但如果进程还没到 Ready 状态的时候, cpu 就被占了许多的话。就会出现CPU占⽤较⾼,但负载却不 ⾼。(因为进程还没有收到数据,都是内核在玩命⼲活)

我要做⼀个⻓连接推送模块,1亿⽤户需要多少 台机器?

100 万条空的 TCP 连接仅仅只消耗掉了 3 GB 多⼀点的内存⽽已。

对于⻓连接的推送模块这种服务来说, 给客户端发送数据只是偶尔的,⼀般⼀天也就顶多发送⼀次两次 的。绝⼤部分情况下 TCP 连接都会空闲的。 假设你的服务器内存是 128 GB 的。 那么⼀台服务器可以考虑⽀持 500 万条的并发。这样会消耗⼤约 不到 20 G 的内存⽤来保存这 500 万条连接对应的 socket。 还剩下 100 G 还多的内存,⽤来应对发送 缓存区的开销⾜够了。

所以,1亿⽤户,仅仅只需要 20 台 机器,够了!

 

(778条消息) 理解了实现再谈网络性能-总结_wu_amber的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值