为移动应用优化Linux

  来自CDN提供商 ClounFare的Optimizing Your Linux Stack for Maximum Mobile Web Performance

  我们已经试验过在前端网络7层FEO的优化,但是Linux系统不太适合移动应用,我们必须深入到4层。这篇文章是关于移动设备目前所面临的挑战,如何调整默认TCP配置以获得最佳的移动性能。

  移动网络的性能挑战之一是,你需要了解网络堆栈的第4层的TCP拥塞Congestion 控制。 TCP拥塞控制是一个看门人,决定如何控制从您的服务器到客户端的数据包流量。其目的是为了防止网络拥塞,当拥塞发生时检测并减慢数据的传送速度。这有助于确保互联网可用,但可能会导致移动网络上的问题。

  有线网络中,如果一个端口发生丢包,说明交换机负载过重,这时TCP拥塞控制能够后退减慢以保证这个端口网络可用。但是在移动无线网络中,可能会受到干扰而导致丢包,丢包的原因很多,这时了解TCP的拥塞算法就很重要,以便应对无线网络这种情况。

  要了解TCP拥塞控制算法是如何工作的,想象以下情况。你的web服务器作为您当地的水厂,你已经在这个城市建立了大型网络管道,你需要保证每个管道的水压越大越好,但又不想爆管。

  当地正好有一个瓶装水工厂,其基础设施是建立在漏而脆的旧管道上。你需要大水量推送,但是怕爆管,你只能做测试 - 你送的水有一个量数,然后测量其压力,如果压力突然失去了,那么你可以推断出一个管道爆破了。如果没有,那么这个水平很可能安全的,你可以添加更多的水压力和重复测试,直到爆管。不断遍历测试,看看压力,记下最大水量,并确保你永远不会超过它。

  但是外部因素也会影响,比如这个水厂加了一个水泵,结果水管压力降低,你没有办法确定爆管还是其他原因,只能将水压降低到一个低水平,导致所有客户只能有一个低水压。

   TCP有一个初始数据包量称为初始拥塞窗口(initcwnd),它是数据包在网络中传输的初始值。而拥塞窗口(cwnd的)要么收缩,要么增长,这取决于初始数据发出后,它们返回有多快以及量有多少。从本质上讲,TCP拥塞控制是类似自来水管道控制 - 测量网络可以承受的压力,然后调整数据量,试图最大限度地传输数据但是不能有爆裂。

  当TCP第一次建立连接是,它会尝试将迅速扩大的拥塞窗口,被称为慢启动。这是一个有点用词不当,因为它通常是一个指数增长函数,它是相当快的。就像供水企业在上面的例子中检测到压力下降,它检测到的TCP数据包丢失时,它减少了拥塞窗口的大小,加大了下一阵包的交付延迟。两组组脉冲包之间的timeout被称为重传超时(RTO) 。控制这些流程中的TCP算法被称为拥塞控制算法。基于在他们的网络的特性不同的策略有许多的拥塞控制算法。大多数的拥塞控制算法侧重于优化的一种类型的网络:充血性损失(有线网络)或随机损失(移动网络中) 。

为移动应用优化Linux[转]_第1张图片

  在很多操作系统中默认的拥塞控制算法对于有线网络是良好的,却在移动网络有问题。一些拥塞控制算法尝试通过“压力增加”与“预期容量”的差值找出损失的原因,以缩小差距。这些被称为带宽估计算法,例子包括Vegas, Veno 和 Westwood。

升级Linux

  如果你的Web服务器上运行旧的Linux内核,并希望提高网络性能,特别适用于移动设备,你应该升级。首先,Linux的2.6.38默认initcwnd和initrwnd是3和10。它允许14.2KB初始值发送,等接收的返回后才开始缓慢增长。这是HTTP和SSL重要,因为它可以让你在头部初始设置更多空间的数据包。

  如果您运行的是较旧的内核,你或许可以在bash shell中(谨慎使用)来设置'initcwnd和initrwnd至10。平均而言,这个小小的改变,是最大限度地提高网络性能的最大助力之一。

ip route | while read p; do ip route change $p initcwnd 10 initrwnd 10; done

  Linux kernel 3.2 实现了 Proportional Rate Reduction (PRR). 提高http响应 3-10%.

tcp_no_metrics_save

  许多拥塞控制算法检测到丢失时会减少拥塞窗口。当多个损耗发生后,这可能导致cwnd降低小于慢速启动的阈值。不幸的是,这个连接不会再进行一次慢启动。其结果是,一些网络中断,可能会导致TCP放缓这个会话中的所有连接。

  3.2版本之前的未打补丁的内核tcp_no_metrics_save = 0 的sysctl设置会更致命。此设置将保存数据在所有连接上,并试图用它来优化网络。不幸的是,这实际上使性能更差,因为TCP会将一个丢包的例外情况下采取的策略适用于这个客户端中几分钟的窗口内的每一个新连接。换句话说,在某些情况下,一个人从手机浏览您的网站如果一些随机数据包丢失,能够降低你的服务器的性能,尽管他。如果你希望你的访问者从移动,有损连接来了,你不能升级或修补的内核,我建议设置tcp_no_metrics_save = 1 ,Linux的3.2 的PRR能降低影响TCP性能的有损连接的数量。

vi /etc/sysctl.conf

加入:

net.ipv4.tcp_no_metrics_save=1

重启:/sbin/sysctl -p

  

Linux 3.x版本

   Linux3.2在RFC2099bis一个重要的改进。最初的重传超时(initRTO)已更改为从1秒3秒。如果发送的initcwnd的2秒等待时间内有包丢失,这个时间规定试图重新发送数据时的等待时间。当TCP数据流很短时,这可以有一个非常明显的改善。老版本补丁:here's the patch

  Linux3.3在CODEL(控制延迟)有字节队列限制,在3.5内核中通过智能管理数据包队列解决了Bufferbloat长期存在的问题。 Bufferbloat当基于TCP缓存过载时变得没有效率,因为它充满了过时的数据。 Linux的3.3具有自动QoS重要的数据包(SYN/ DNS/ ARP/等),保留存下缓冲队列,从而减少bufferbloat大小,改善服务器延迟。

  Linux3.5实现的TCP早期重传,对于具有少量的数据包重新排序的连接提供了保障。这使得连接可以绕过昂贵的重传超时计时(RTO)快速触发新连接。默认情况下,它启用故障安全模式tcp_early_retrans=2。如果由于某种原因,你确定你的客户端连接已经丢失,但没有重新排序reordering,那么你可以设置tcp_early_retrans=1,以节省RTT的四分之一时间。

  linux 3.6的去除IPv4的路由缓存,IPv4的路由缓存的目的是要消除FIB(Forward Information Base)查表并提高性能。可惜在3.2.x中它提供了不到10%非常小的性能提升。在3.5.x的内核中是非常容易受到某些DDoS***。

  最后,你应该检查Linux内核中的一个重要的设置:tcp_slow_start_after_idle,默认情况下,此参数设置为1,将大幅削减空闲连接时的CWnd,对长连接如SSL产生负面影响。下面的命令将其设置为0,可以显著提高性能。

sysctl -w tcp_slow_start_after_idle=0

  Linux 2.6.19 有一个缺省拥塞算法是CUBIC,基于实时优化的高性能高吞吐量算法,它的杀手锏是一个被称为Hybrid Slow Start (HyStart),通过衡量ACK 冲击而避免过载cwnd,安全地推出慢启动。吞吐量能提高200-300%。

  其他算法如TCP Westwood,经过测试没有CUBIC 表现优异。