如何提高网络的吞吐量
Posted on Wed, 25 Dec 2024 10:31:00 +0800 by LiangMingJian
服务器(进程)级别
服务器级别增加网站吞吐量是诸多措施中最容易并且是效果最好的,如果一个网站能通过增加少量的服务器来提高吞吐量,应该优先采用。毕竟一台服务器的费用相比较一个程序员费用来说要低的多。但是有一个前提,就是你的服务器是系统的瓶颈,网站系统之后的其他系统并非瓶颈。如果你的系统的瓶颈在接口或者其他服务,盲目的增加服务器并不能解决你的问题。
通过增加服务器来解决你的网站瓶颈,意味着你的网站需要做负载均衡。负载均衡(Load Balance),其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。负载均衡的方案,比如 LVS、Nginx、F5 等。
线程级别
当一个请求到达服务器并且正确的被服务器接收之后,最终执行这个请求的载体是一个线程。当一个线程被CPU载入执行其指令的时候,在同步的状态下,当前线程会阻塞在那里等待CPU结果,如果CPU执行的是比较慢的IO操作,线程会一直被阻塞闲置很长时间,这里的很长是对比CPU的速度而言。当一个新的请求到来的时候,如果没有新的线程去领取这个任务并执行,要么会发生异常,要么创建新的线程。
线程是一种很稀缺的资源,不可能无限制的创建。这种情况下我们就要把线程这种资源充分利用起来,不要让线程停下来。这也是程序推荐采用异步的原因。试想,一个线程不停的在工作,遇到比较慢的IO不会去等待结果,而是接着处理下一个请求,当IO的结果返回来得到通知的时候,线程再去取IO结果,岂不是能在相同时间内处理更多的请求。程序异步化(非阻塞)会明显提高系统的吞吐量,但是响应时间可能会稍微变大。
还有一点,尽量减少线程上下文在CPU的切换,因为线程上线文切换的成本也是比较大的,在线程切换的时候,CPU需要把当前线程的上下文信息记录下来用以下次调用的时候使用,然后把新线程的上下文信息载入然后执行。这个过程相对于CPU的执行速度而言,要慢很多。
CPU级别
现代操作系统都采用虚拟寻址的方式,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统将虚拟空间分为两类:内核空间和用户空间。
- 内核空间独立于用户空间,有访问受保护的内存空间、IO设备的权限(所有的用户空间共享)。
- 用户空间就是我们的应用程序运行的空间,其实用户空间并没有操作各种IO设备的权限,像我们平时读取一个文件,本质上是委托内核空间去执行读取指令的,内核空间读取到数据之后再把数据复制到程序运行的空间,最后应用程序再把数据返回调用方。
内核会为每个I/O设备维护一个 buffer(同一个文件描述符读和写的buffer不同),应用程序发出一个IO操作的指令其实通过了内核空间和用户空间两个部分,并且发生了数据的复制操作。这个过程其实主要包含两个步骤:用户进程发出操作指令并等待数据;内核把数据返回给用户进程(buffer的复制操作)。根据这两个操作的不同表现,所以IO模型有了同步阻塞,同步非阻塞,异步阻塞,异步非阻塞的概念。利用CPU提高系统吞吐量主要目标是提高单位时间内CPU运行的指令数,避免CPU做一些无用功。可以通过增加CPU的个数来增加吞吐量
CPU负责把buffer的数据copy到应用程序空间,应用程序再把数据返回给调用方,假如这个过程发生的是一次Socket操作,应用程序在得到 IO 返回数据之后,还需要网卡把数据返回给client端,这个过程又需要把刚刚得到的buffer数据再次通过内核发送至网卡,通过网络传送出去。由此可见CPU把buffer数据copy到应用程序空间这个过程完全没有必要,在内核空间完全可以把buffer数据直接传输至网卡,这也是零拷贝技术要解决的问题。
PS:零复制 (Zero-copy) 技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。
网络传输级别
由于协议大部分是TCP/IP,所以在协议传输方面优化的手段比较少,但是应用程序级别协议可以选择压缩率更好的,比如采用GRPC会比单纯的HTTP协议要好很多,HTTP2 要比HTTP 1要好很多。
另外一方面网卡尽量加大传输速率,比如千兆网卡要比百兆网卡速度更快。由于网络传输比较偏底层,所以人工干预的切入点会少很多。
代码层
- 加大应用的进程数,增加并发数,特别在进程数是瓶颈的情况下;
- 优化线程调用,尽量线程池化;
- 应用的代码异步化,特别是异步非阻塞式编程对于提高吞吐量效果特别明显;
- 充分利用多核CPU优势,实现并行编程;
- 减少每个调用的响应时间,缩短调用链,例如通过加索引的方式来减少访问一次数据库的时间;