一种10s之内的方案

25 Dec 2014


理论上

我们先来看看规则:

  1. 1G文件,双千兆网卡,服务器端单进程。
  2. 每次处理一行。
  3. 客户端需要等一个请求收到之后,才能发另外一个请求。
  4. 服务器每次给出下一行。去掉1/3,逆序加行号。

本文说明如何在不压缩的情况下,做到4秒以内。压缩的话,群里目前说有2.3s的了。

理论上:

1G的文件,10474514行。每行大概200个字符。服务器端去1/3,逆转后加行号,大概700多MB。单位是字节。

双千兆网卡,网络传输2000Mb。单位是位。每秒传输速度是256MB,整个文件内容的传输是可以在4s内完成的。

DEMO

钻风给出的demo中,bloking-io,客户端多线程,服务器端每accept一个连接后,一个线程处理一个链接。 在客户端中:

while (true)
{
    send();
    recv();
}

服务器端中:

while (true)
{
    recv();
    getNextLine();
    send();
}

客户端100个线程的时候(20s ~ 30s):

tsar -l -i 1 --traffic 结果如下:

Time              -------------traffic------------
Time               bytin  bytout   pktin  pktout
06/09/14-23:12:56   0.00    0.00    0.00    0.00
06/09/14-23:12:57  63.4M  155.3M  954.6K  954.6K
06/09/14-23:12:58   0.00    0.00    0.00    0.00
06/09/14-23:12:59  60.1M  147.3M  905.4K  905.4K
06/09/14-23:13:00   0.00    0.00    0.00    0.00
06/09/14-23:13:01  57.5M  140.8M  866.5K  866.4K

sar -n DEV 1 结果:

11:20:46 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s
11:20:47 PM        lo      0.00      0.00      0.00      0.00
11:20:47 PM      eth0 478215.05 478217.20  31756.46  77744.95
11:20:47 PM      eth1 484318.28 484318.28  32162.05  78724.16
11:20:47 PM     bond0 962533.33 962535.48  63918.51 156469.11

网卡的利用率大概在200Mb左右。 TCP的包头: 954.6 * 1000 * 2 * 64 / 1024 / 1024 = 116Mb

每秒90w的tcp包, 网络带宽没全部用上。

在demo中,客户端发一个简单字符,作为消息,客户端收到此字符之后,发回一行。

在每个请求中,TCP包头占了很大比重,如果能合并消息,减少tcp包,每次发送的数据多一些。这样可以可以提高网络带宽的利用率。

合并消息

实际为了解决小包问题,tcp自带了Nagle算法,默认开启,200ms超时,窗口大小和数据达到MSS发送数据。

我们可以自己关闭这个选项,自己做实现。

注意到题目中: 必须要等请求完成,才能发送新的请求,那么就需要

  • 客户端,对于一个连接:

    1. 有独立线程负责写,要发送的消息存放于一个队列,满足要求后发送。
    2. 多个业务线程网队列写数据,然后等待结果返回。
    3. 独立的读线程,读消息,然后通知结果访问。
  • 服务器端,对于一个连接:

    1. 独立线程,读数据。
    2. 多个业务线程处理数据,往发送队列写数据。在无数据时,等待。
    3. 独立线程根据消息合并规则,合并消息,发送数据。

客户端可以建立多个连接到服务器,调整业务线程的数量,达到最好的网络带宽利用。

这个方案,会有一些的线程切换和锁。这个是这个方案的难点。

当然也可以用协程来实现,这个是另外的方案了。

参考: 如何把网卡跑满


欢迎关注我的微信公众号

欢迎关注我的 新浪微博,有问题随时交流。

欢迎关注我的 GitHub,了解我最新关注的项目。

comments powered by Disqus