关于移动互联网TCP协议栈优化的一些材料总结

  1. http://blog.chunshengster.me/2013/12/optimizing_your_linux_stack_for_maximum_mobile_web_performance.html [翻译,原文见:http://blog.cloudflare.com/optimizing-the-linux-stack-for-mobile-web-per
  2. https://docs.google.com/presentation/d/1f2J_HrzMNvVHhsB3f7DKJFPl2N0Q_QR2ZEECWQu6oV8/present#slide=id.p19  google大神关于 high performance browser networking 的简版PPT
  3. http://chimera.labs.oreilly.com/books/1230000000545/index.html   high performance browser networking 的在线电子书
  4. https://developers.google.com/speed/protocols/tcpm-IW10?csw=1  协议栈优化中IW10 的所有关联文档
  5. http://lwn.net/Articles/427104/  LWN中关于TCP initial congestion window 的解释
  6. http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=356f039822b8d802138f7121c80d2a9286976dbd  kernel git中关于 TCP: increase default initial receive window 的文档和代码
  7. https://datatracker.ietf.org/doc/rfc6928/?include_text=1 rfc 6928关于 initial congestion window 的文档
  8. http://research.csc.ncsu.edu/netsrv/?q=content/iw10  Experimental Evaluation of Increasing TCP Initial Congestion Window to 10 Segments
  9. 其他http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36640.pdf
  10. http://lwn.net/Articles/426883/
  11. http://www.ietf.org/proceedings/10mar/slides/iccrg-4.pdf
  12. http://tools.ietf.org/html/rfc3390
  13. http://tools.ietf.org/html/draft-mathis-tcpm-proportional-rate-reduction-01
  14. http://monolight.cc/2010/12/increasing-tcp-initial-congestion-window/
  15. http://www.cdnplanet.com/blog/tune-tcp-initcwnd-for-optimum-performance/
  16. http://blog.habets.pp.se/2011/10/Optimizing-TCP-slow-start
  17. http://idning.github.io/tcp_ip_increasing_init_cwnd.html
  18. http://itindex.net/detail/46633-tcp-%E4%BC%98%E5%8C%96
  19. http://blog.csdn.net/zhangskd/article/details/7608343
  20. http://blog.csdn.net/zhangskd/article/details/7609465
发表在 System, TCP | 留下评论

Optimizing Your Linux Stack for Maximum Mobile Web Performance[优化Linux 协议栈提升移动互联网性能]

Published on December 31, 2012 12:29AM by Matthew Prince.

原文请见:  http://blog.cloudflare.com/optimizing-the-linux-stack-for-mobile-web-per

 

下面是这篇是我们系统工程师团队的lan Applegate (@AppealingTea)写的技术文章,关于如何优化Linux TCP 栈来优化手机访问性能。这篇文章最早发布在  2012 Web Performance Calendar. 在 CloudFlare,我们花了大量的时间来优化网络栈以保证无论什么设备从无论什么网络访问的我们都是最优化的。我们想分享这些技术细节来帮助那些正在寻找移动网络性能优化的公司,即便他们不使用CloudFlare。当然,如果你正在使用CloudFlare,当手机用户访问你的网站的时候你已经获得了最快的TCP效率。

 

We spend a lot of time at CloudFlare thinking about how to make the Internet fast on mobile devices. Currently there are over 1.2 billion active mobile users and that number is growing rapidly. Earlier this year mobile Internet access passed fixed Internet access in India and that’s likely to be repeated the world over. So, mobile network performance will only become more and more important.

我们(CloudFlare)用了很多时间来思考手机设备如何获得最快的网络速度。现在,已经有12亿活跃的手机用户并且还在迅速增长。今年(2012)早些时候,印度的移动互联网接入用户已经超过固网接入用户,这样的情况将在全球蔓延。因此,手机网络的性能优化变得越来越重要。

Most of the focus today on improving mobile performance is on Layer 7 with front end optimizations(最佳化) (FEO). At CloudFlare, we’ve done significant work in this area with front end optimization technologies like Rocket Loader, Mirage, and Polish that dynamically(动态地) modify(修改) web content to make it load quickly whatever device is being used. However, while FEO is important to make mobile fast, the unique(独特的) characteristics(特征) of mobile networks also means we have to pay attention to the underlying(潜在的) performance of the technologies down at Layer 4 of the network stack.

目前大多数移动网络的优化聚焦于7层(前端服务器,FEO)的优化。在CloudFlare,我们在前端服务器上也花了很多的时间来左右话,比如说:Rocket Loader, Mirage, and Polish,无论什么样的设备来访问,我们都能动态的修改页面使得内容能够被快速的展现。然而,尽管在手机访问优化方面FEO很重要,但是移动网络的特征同样意味着我们必须在4层的网络栈优化上,也许会有一些技术方式能够提升性能。

This article is about the challenges mobile devices present, how the default TCP configuration(配置) is ill-suited for optimal(最佳的) mobile performance, and what you can do to improve performance for visitors connecting via mobile networks. Before diving into the details, a quick technical note. At CloudFlare, we’ve build most of our systems on top of a custom version of Linux so, while the underlying technologies can apply to other operating systems, the examples I’ll use are from Linux.

这篇文章针对于现在的移动设备思考,什么样的默认TCP策略,能够适应手机获得最佳的网络性能,并且针对通过移动网络访问的用户我们如何操作来提升性能。在深入细节之前,我们先来快速了解一下这个:在CloudFlare,我们大多数系统都是在定制的Linux上构建的,虽然底层的技术可以适用于其他的操作系统。不过,下面的例子都是来源于Linux环境。

TCP Congestion Control

TCP拥塞控制

To understand the challenges of mobile network performance at Layer 4 of the networking stack you need to understand TCP Congestion(拥挤) Control. TCP Congestion Control is the gatekeeper that determines how to control the flow of packets from your server to your clients. Its goal is to prevent Internet congestion by detecting(察觉) when congestion occurs and slowing down the rate data is transmitted(传输). This helps ensure that the Internet is available to everyone, but can cause problems on mobile network when TCP mistakes mobile network problems for congestion.

为了更好的理解4层网络栈对移动网络性能优化的挑战,我们需要首先理解TCP的拥塞控制机制。TCP的拥塞控制机制是控制数据包如何从你的服务器到客户端流动的看门人。他的目标就是在拥塞发生时发现它并且减慢数据包的传输速率,来达到防止网络拥塞发生的目的。这种机制帮助我们确保网络对于每个节点都是可用的,但这在移动移动网络中,当TCP机制误解了移动网络拥塞问题的时候却会引发一些问题。

 

TCP Congestion Control holds back the floodgates if it detects congestion (i.e. packet loss) on the remote end. A network is, inherently, a shared resource. The purpose of TCP Congestion Control was to ensure that every device on the network cooperates to not overwhelm its resource. On a wired network, if packet loss is detected it is a fairly reliable indicator that a port along the connection is overburdened. What is typically going on in these cases is that a memory buffer in a switch somewhere has filled beyond its capacity because packets are coming in faster than they can be sent out and data is being discarded. TCP Congestion Control on clients and servers is setup to “back off” in these cases in order to ensure that the network remains available for all its users.

TCP拥塞会在察觉与远端通讯产生拥塞的时候控制住数据闸门。而网络,是一个共享的资源。TCP的目标就是确保网络中的每一台设备都是合作状态,而不会压跨它占有的资源。在有线网络中,当丢包发生时,可以非常肯定的认为是这个连接中的某一个端口负载过重了。典型的状况是某台交换设备的流入速率远大于流出速率,导致它的内存缓冲用满了,从而数据被丢弃掉。TCP拥塞控制就是在这种情况下,通过服务器和客户端的控制“回退”,以确保网络对于其他的所有用户仍然可用。

But figuring out what packet loss means on a mobile network is a different matter. Radio networks are inherently susceptible to interference which results in packet loss. If pakcets are being dropped does that mean a switch is overburdened, like we can infer on a wired network? Or did someone travel from an undersubscribed wireless cell to an oversubscribed one? Or did someone just turn on a microwave? Or maybe it was just a random solar flare? Since it’s not as clear what packet loss means on a mobile network, it’s not clear what action a TCP Congestion Control algorithm should take.

但是,必须要指出的是,移动网络中发生的丢包现象却意味着其他的可能性。无线网络天然就很容易因为收到影响、干扰而产生丢包。如果数据包被丢弃确实意味着交换机过载,我们能否在无线网络中也这样推断呢?或者是,一个人从一个不过载的无线基站转移到了一个过载的无线基站?或者是某人刚好这时打开了无线微波?或者可能很随机的?正因为无线网络中的丢包原因不是那样的明确,所以,我们同样不能够明确TCP拥塞控制算法应该如何处理这个问题。

A Series of Leaky Tubes

一系列崩漏的水管

To optimize networks for lossy networks like those on mobile networks, it’s important to understand exactly how TCP Congestion Control algorithms are designed. While the high level concept makes sense, the details of TCP Congestion Control are not widely understood by most people working in the web performance industry. That said, it is an important core part of what makes the Internet reliable and the subject of very active research and development.

为了优化像移动网络这样的容易受到干扰而产生损耗的网络,正确的理解TCP拥塞算法的设计是非常重要的。从一个更高层次的角度来讲,TCP拥塞控制算法的细节并不为广大从事WEB性能优化的人们所广泛知晓。这就是说,这是网络可靠性中是非常重要、核心的部分,也是当前研究和开发的活跃话题。

 

To understand how TCP Congestion Control algorithms work, imagine the following analogy. Think of your web server as your local water utility plant. You’ve built on a large network of pipes in your hometown and you need to guarantee that each pipe is as pressurized as possible for delivery, but you don’t want to burst the pipes. (Note: I recognize the late Senator Ted Stevens got a lot of flack for describing the Internet as a “series of tubes,” but the metaphor is surprisingly accurate.)

为了理解TCP拥塞控制算法的工作方式,想象一下下面的一个可以类比的场景。想像你的WEB服务器就像当地的自来水厂。你已经在你的家乡建立了非常庞大的管线网络,并且你必须确保你的管线尽可能的密封起来,以保证水的传送,但是,你并不愿意水管发生甭裂。(备注:我了解到 Ted Stevens在很多的宣传中都说互联网就像“一系列的水管”,不过,这比喻实在是太恰当了)

Your client, Crazy Arty, runs a local water bottling plant that connects to your pipe network. Crazy Arty’s infrastructure is built on old pipes that are leaky and brittle. For you to get water to them without bursting his pipes, you need to infer the capability of Crazy Arty’s system. If you don’t know in advance then you do a test — you send a known amount of water to the line and then measure the pressure. If the pressure is suddenly lost then you can infer that you broke a pipe. If not, then that level is likely safe and you can add more water pressure and repeat the test. You can iterate this test until you burst a pipe, see the drop in pressure, write down the maximum water volume, and going forward ensure you never exceed it.

你的客户,Crazy Arty,在当地经营一家水灌装厂,连接在你的水管网络中。Crazy Arty的基础设施是用老旧的水管建造的,非常容易崩漏。所有,如果你希望你的水传送到他那里而不崩裂掉他的管道,你就必须能够获知Crazy Arty的水管的能力。如果你事先不知道这些,那么你会做一个测试:你会发送已知流量的水到管线中,并且测试它的压力。如果测试过程中压力突然消失掉,你就能推断出你已经崩裂了水管。如果还没有,这就意味着当前的流量水平是安全的,并且你可以继续增加水的流量压力,以此方式重复测试。你可以重复这样的测试直到你崩掉了水管,发现水管突然没有了压力,然后记下最大的水量,以后确保不再超过这个量。

Imagine, however, that there’s some exogenous factor that could decrease the pressure in the pipe without actually indicating a pipe had burst. What if, for example, Crazy Arty ran a pump that he only turned on randomly from time to time and you didn’t know about. If the only signal you have is observing a loss in pressure, you’d have no way of knowing whether you’d burst a pipe or if Crazy Arty had just plugged in the pump. The effect would be that you’d likely record a pressure level much less than the amount the pipes could actually withstand — leading to all your customers on the network potentially having lower water pressure than they should.

再想象一下,一定还有一些外在的因素,可以使得水管中的压力降低,但是实际上却并不是水管崩裂。例如,Crazy Arty在你并不知道的情况下,随机的使用抽水泵从管道中进行抽水。如果你只能够通过观察水的压力变化来获取信息,那么你就没有办法知道到底是水管崩裂了还是Crazy Arty接上了抽水泵。而结果将会是,你所有记录的压力值很可能远远低于水管所能承受的–导致你所有的用户很可能获得了远小于它本该获得的水流量压力。

Optimizing for Congestion or Loss

拥塞和丢包优化

If you’ve been following up to this point then you already know more about TCP Congestion Control than you would guess. The initial amount of water we talked about in TCP is known as the Initial Congestion Window (initcwnd) it is the initial number of packets in flight across the network. The congestion window (cwnd) either shrinks, grows, or stays the same depending on how many packets make it back and how fast (in ACK trains) they return after the initial burst. In essence, TCP Congestion Control is just like the water utility — measuring the pressure a network can withstand and then adjusting the volume in an attempt to maximize flow without bursting any pipes.

如果你接受这个观点,你就已经知道了很多关于TCP拥塞控制的知识,然后我们就可以更多的进行猜测。我们所谈论的TCP的初始水量,就是初始化拥塞窗口(initcwnd),它是网络传输过程中的初始的数据包个数。拥塞窗口(cwnd)或是降低,或是增长,或是保持同样的大小,这些依赖于在网络开始崩溃后有多少数据包能够返回来以及有多快(在ACK环节)。本质上来讲,TCP拥塞控制就像自来水工厂–测量网络能够经受的压力然后调节开关的大小以取得最大的流量,但是却并不崩裂任何的管道。

When a TCP connection is first established it attempts to ramp up the cwnd quickly. This phase of the connection, where TCP grows the cwnd rapidly, is called Slow Start. That’s a bit of a misnomer since it is generally an exponential growth function which is quite fast and aggressive. Just like when the water utility in the example above detects a drop in pressure it turns down the volume of water, when TCP detects packets are lost it reduces the size of the cwnd and delays the time before another burst of packets is delivered. The time between packet bursts is known as the Retransmission Timeout (RTO). The algorithm within TCP that controls these processes is called the Congestion Control Algorithm. There are many congestion control algorithms and clients and servers can use different strategies based in the characteristics of their networks. Most of Congestion Control Algorithms focus on optimizing for one type of network loss or another: congestive loss (like you see on wired networks) or random loss (like you see on mobile networks).

当TCP连接第一次建立后,它就马上开始增加拥塞窗口。这个阶段中,TCP不断升高拥塞窗口,这个过程叫“慢启动”(Slow Start)。这个词有一些不够恰当,因为,这个过程往往是快速并激进的指数级增长。就像上面提到的自来水工厂一样,当它检测到压力的下降就开始调小水的阀门,当TCP检测到数据包丢失的时候,它也开始减小拥塞窗口的大小,并延迟下一个可能崩裂网络的数据包的发送。这个等待数据包发送的时间被称为“重发延时”(RTO)。TCP中的这个算法控制着这一系列的过程,被成为拥塞控制算法。有很多的拥塞控制算法,并且客户端和服务器之间可以根据它们网络不同的特性使用不同的算法。大多数拥塞控制算法聚焦于优化网络丢包中的一种,比如过载丢包(如有线网络),或是随机丢包(比如移动网络)。

In the example above, a pipe bursting would be an indication of congestive loss. There was a physical limit to the pipes, it is exceeded, and the appropriate response is to back off. On the other hand, Crazy Arty’s pump is analogous to random loss. The capacity is still available on the network and only a temporary disturbance causes the water utility to see the pipes as overfull. The Internet started as a network of wired devices, and, as its name suggests, congestion control was largely designed to optimize for congestive loss. As a result, the default Congestion Control Algorithm in many operating systems is good for communicating wired networks but not as good for communicating with mobile networks.

在上面的例子中,一条数据管道的崩裂可能是因为过载丢包。在管道中有一个物理限制,如果超过了这个限制,就会有对应的回退响应机制。从另一个角度来说,Crazy Arty的抽水机类似于随机丢包。网络的能力依然可用的情况下,仅仅是一个短时间的失衡,导致自来水厂认为管道已经过载。互联网是从有线设备开始的,正如它的名字一样,拥塞控制在很大程度上来讲是为过载丢包而设计。因此,在很多操作系统上默认的拥塞控制算法对于有线网络的数据通讯来讲是非常有用的,但是在手机网络通讯中却并不是那么的适合。

A few Congestion Control algorithms try to bridge the gap by using the time of the delay in the “pressure increase” to “expected capacity” to figure out the cause of the loss. These are known as bandwidth estimation algorithms, and examples include Vegas, Venoand Westwood+. Unfortunately, all of these methods are reactive and reuse no information across two similar streams.

一些拥塞控制算法试图通过缩小“压力增长”至“预期压力”阶段的重发延迟的时间间隔来确认丢包的原因。这些称为带宽评估算法,包括 VegasVenoWestwood+。不幸的是,所有的这些方法都没有效果,并且在两条相似的数据流中无法找到可重用的信息。

At companies that see a significant amount of network traffic, like CloudFlare or Google, it is possible to map the characteristics of the Internet’s networks and choose a specific congestion control algorithm in order to maximize performance for that network. Unfortunately, unless you are seeing the large amounts of traffic as we do and can record data on network performance, the ability to instrument your congestion control or build a “weather forecast” is usually impossible. Fortunately, there are still several things you can do to make your server more responsive to visitors even when they’re coming from lossy, mobile devices.

在一些能够观察到巨量网络流量的公司内部,比如 CloudFlare和Google,是非常有机会通过定位互联网络的特征来选择一个特殊的拥塞控制算法从而达到网络性能最大化的。不幸的是,除非你像我们一样观察大量的网络流量并且记录网络性能数据,否则,建立你自己的拥塞控制就像自己建立“天气预报”机制一样不太可能。但是,还是有很多方式,可以让你的服务面对那些来自于容易丢包的移动设备响应更加良好。

Compelling Reasons to Upgrade You Kernel

升级内核的必要原因

The Linux network stack has been under extensive development to bring about some sensible defaults and mechanisms for dealing with the network topology of 2012. A mixed network of high bandwidth low latency and high bandwidth, high latency, lossy connections was never fully anticipated by the kernel developers of 2009 and if you check your server’s kernel version chances are it’s running a 2.6.32.x kernel from that era.

Linux的网络协议栈已在广泛的开发中带来了一些合理的默认值和机制来处理当今(2012)网络拓扑。在2009年,一个高带宽、低延迟和高带宽、高延迟、易丢包的混合网络是内核开发工作从来没有预期过的,如果你检查你服务器的内核版本碰巧它运行着 2.6.32.x的版本的话,这个内核就是在那个年代开发的。

uname -a

There are a number of reasons that if you’re running an old kernel on your web server and want to increase web performance, especially for mobile devices, you should investigate upgrading. To begin, Linux 2.6.38 bumps the default initcwnd and initrwnd (inital receive window) from 3 to 10. This is an easy, big win. It allows for 14.2KB (vs 5.7KB) of data to be sent or received in the initial round trip before slow start grows the cwnd further. This is important for HTTP and SSL because it gives you more room to fit the header in the initial set of packets. If you are running an older kernel you may be able to run the following command on a bash shell (use caution) to set all of your routes’ initcwnd and initrwnd to 10. On average, this small change can be one of the biggest boosts when you’re trying to maximize web performance.

如果还在运行着老版本的内核并且希望提升web的性能,尤其是针对移动设备,有很多原因使得你应该开始考虑升级了。首先,Linux 2.6.38 跳跃性的将初始拥塞窗口和初始接收窗口(inital receive window)从3升到10.这是个非常简单但是有很大效果的方式。它允许在慢启动提升拥塞窗口前就可以在第一个回环中发送或接收14.2KB(vs 5.7KB)的数据。这对于HTTP和SSL来讲是非常重要的,因为它给了更多的空间在初始阶段的数据包中填充协议头。如果你在一个老版本的内核中,你可能需要通过运行下面的命令来设置所有的路由使得它们的初始化拥塞窗口和初始化接收窗口为10.通常来讲,这个很小的变化对于提升web服务器性能来讲,可能是效果最大的一个。

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

Linux kernel 3.2 implements Proportional Rate Reduction (PRR). PRR decreases the time it takes for a lossy connection to recover its full speed, potentially improving HTTP response times by 3-10%. The benefits of PRR are significant for mobile networks. To understand why, it’s worth diving back into the details of how previous congestion control strategies interacted with loss.

在Linux 内核 3.2版本中,实现了 Proportional Rate Reduction (PRR)。PRR减小了从丢包网络中恢复到全速的时间,有可能提升3-10%的HTTP的响应时间。这个收益对于手机网络来讲是尤其重要的。为了理解为什么,我们有必要回到前面关于拥塞控制策略和丢包是如何相互影响这个细节的。

Many congestion control algorithms halve the cwnd when a loss is detected. When multiple losses occur this can result in a case where the cwnd is lower than the slow start threshold. Unfortunately, the connection never goes through slow start again. The result is that a few network interruptions can result in TCP slowing to a crawl for all the connections in the session.

很多拥塞控制算法在发现丢包的时候会将拥塞窗口减半(1/2)。当多次丢包发生的时候,可能带来一个结果:拥塞窗口小于慢启动时候的阈值。不幸的是,连接从来不会再来一次慢启动。结果就是,一些网络中断的能够使得会话中的所有连接都慢的像爬一样。

This is even more deadly when combined with tcp_no_metrics_save=0 sysctl setting on unpatched kernels before 3.2. This setting will save data on connections and attempt to use it to optimize the network. Unfortunately, this can actually make performance worse because TCP will apply the exception case to every new connection from a client within a window of a few minutes. In other words, in some cases, one person surfing your site from a mobile phone who has some random packet loss can reduce your server’s performance to this visitor even when their temporary loss has cleared.

更悲催的是,在没有打补丁的3.2版本以前的内核中,当sysctl配置中tcp_no_metrics_save=0 的状况下。这个设置会在连接时保存配置,并且尝试用它来优化网络。不幸的是,这往往会让网络的性能更加糟糕,因为在一段时间周期内的新建连接TCP也会使用这个配置。换句话来讲,某些情况下,一个使用手机访问你站点的人,如果他偶尔发生了丢包现象,就会一直降低他访问你服务器的性能,即便明确知道他们仅仅是偶尔的丢包。

If you expect your visitors to be coming from mobile, lossy connections and you cannot upgrade or patch your kernel I recommend setting tcp_no_metrics_save=1. If you’re comfortable doing some hacking, you can patch older kernels.

如果你预料有从手机设备、不稳定网络来的访客,并且你不能够升级或给你的内核打补丁的情况下,我建议你设置 tcp_no_metrics_save=1。如果你乐于做一些hacking,你可以给你的内核打补丁

The good news is that Linux 3.2 implements PRR, which decreases the amount of time that a lossy connection will impact TCP performance. If you can upgrade, it may be one of the most significant things you can do in order to increase your web performance.

好消息是 Linux 3.2 的内核实现了 PRR,减小了一个低效的连接对于TCP性能影响的时间。如果你能够升级内核,这是一个提升web性能的很重要的事情。

More Improvements Ahead

更多提升

Linux 3.2 also has another important improvement with RFC2099bis. The initial Retransmission Timeout (initRTO) has been changed to 1s from 3s. If loss happens after sending the initcwnd two seconds waiting time are saved when trying to resend the data. With TCP streams being so short this can have a very noticeable improvement if a connection experiences loss at the beginning of the stream. Like the PRR patch this can also be applied (with modification) to older kernels if for some reason you cannot upgrade (here’s the patch).

Linux 3.2 还有另一个对于RFC2099bis的重要的提升。默认的初始重传的延时从3s变成了1s。如果在发送了初始化拥塞窗口后发生了丢包,在等待数据重新发送的时候可以节省2s的等待时间。在数据流开始的阶段经历丢包的情况下,由于TCP流非常短小,因此,这次可带来非常明显的提升。像PRR补丁一样,这个功能也可以在老版本的内核上生效(需要一些修改),如果你不能够升级内核的话。

Looking forward, Linux 3.3 has Byte Queue Limits when teamed with CoDel (controlled delay) in the 3.5 kernel helps fight the long standing issue of Bufferbloat by intelligently managing packet queues. Bufferbloat is when the caching overhead on TCP becomes inefficient because it’s littered with stale data. Linux 3.3 has features to auto QoS important packets (SYN/DNS/ARP/etc.,) keep down buffer queues thereby reducing bufferbloat and improving latency on loaded servers.

紧接着,Linux 3.3实现的字节队列控制同实现了CoDel(可控延迟)功能的3.5的内核一起工作的时候通过智能的管理数据包队列能够帮助系统解决BufferBloat的问题。Bufferbloat的是指因为TCP缓存中掺杂一些陈旧的垃圾数据导致其低效的情况。在Linux 3.3具有针对重要的数据包(SYN/DNS/ARP/等等)自动QoS的功能,控制缓冲队列来减少bufferbloat,降低高负载服务器的延迟。

Linux 3.5 implements TCP Early Retransmit with some safeguards for connections that have a small amount of packet reordering. This allows connections, under certain conditions, to trigger fast retransmit and bypass the costly Retransmission Timeout (RTO) mentioned earlier. By default it is enabled in the failsafe mode tcp_early_retrans=2. If for some reason you are sure your clients have loss but no reordering then you could set tcp_early_retrans=1 to save one quarter a RTT on recovery.

Linux 3.5实现了TCP快速重传,针对那些少量包重排序的连接实现了一些保障措施。这允许在一些情况下的连接可以触发绕过重传延时(RTO)快速重传。默认是在非安全模式 tcp_early_retrans=2下启用的。如果你有足够的理由确认你的客户端会发生丢包但是不需要重排序,你可以配置 tcp_early_retrans=1在恢复重传时节省 ¼ RTT的时间。

One of the most extensive changes to 3.6 that hasn’t got much press is the removal of the IPv4 routing cache. In a nutshell it was an extraneous caching layer in the kernel that mapped interfaces to routes to IPs and saved a lookup to the Forward Information Base (FIB). The FIB is a routing table within the network stack. The IPv4 routing cache was intended to eliminate a FIB lookup and increase performance. While a good idea in principle, unfortunately it provided a very small performance boost in less than 10% of connections. In the 3.2.x-3.5.x kernels it was extremely vulnerable to certain DDoS techniques so it has been removed.

在3.6版本中被大量改进但并没有太多资料的是去除 IPv4的路由缓存。简单来讲,它是内核中额外的一个缓存层,映射网络接口(网卡)到路由、到IP地址,用以节省一次到转发信息库(FIB)的查询操作。FIB是网络栈内部的一个路由表。IPv4的路由缓存希望通过节省一次FIB查询来提升性能。虽然从原理上来讲是一个好的点子,不过,它仅仅对不到10%的连接有少量的提升。在3.2.x-3.5.x的内核中,它非常容易被一些DDoS技术攻击,所以它在新版的内核中已经被去掉了。

Finally, one important setting you should check, regardless of the Linux kernel you are running: tcp_slow_start_after_idle. If you’re concerned about web performance, it has been proclaimed sysctl setting of the year. It can be enabled in almost any kernel. By default this is set to 1 which will aggressively reduce cwnd on idle connections and negatively impact any long lived connections such as SSL. The following command will set it to 0 and can significantly improve performance:

sysctl -w tcp_slow_start_after_idle=0

最后,无论运行什么版本的Linux内核,你都需要检查的一项重要配置:tcp_slow_start_after_idle。如果你关注WEB性能,这是今年被公开宣告的sysctl配置。这个配置在几乎所有版本的内核中都可以启用。默认情况下,它被设置成1,这将会针对闲置的连接积极的降低拥塞窗口,对长连接比如SSL产生非常消极的影响。下面的命令将会设置它为0,并且显著的提升性能:

sysctl -w tcp_slow_start_after_idle=0

The Missing Congestion Control Algorithm

那些漏掉的拥塞控制算法

You may be curious as to why I haven’t made a recommendation as far as a quick and easy change of congestion control algorithms. Since Linux 2.6.19, the default congestion control algorithm in the Linux kernel is CUBIC, which is time based and optimized for high speed and high latency networks. It’s killer feature, known as called Hybrid Slow Start (HyStart), allows it to safely exit slow start by measuring the ACK trains and not overshoot the cwnd. It can improve startup throughput by up to 200-300%.

你可能会好奇为什么我没有推荐一个 快速和容易改变的拥塞控制算法。 从Linux 2.6.19开始,默认的Linux内核的拥塞控制算法是CUBIC,这是一个基于时间并针对高速和高延迟网络进行优化的。 它的杀手锏,称为混合慢启动机制 (HyStart),使其通过测量ACK 冲击和不超过cwnd实现安全地退出慢启动。 它可以提高启动吞吐量200 – 300%。

 

While other Congestion Control Algorithms may seem like performance wins on connections experiencing high amounts of loss (>.1%) (e.g., TCP Westwood+ or Hybla), unfortunately these algorithms don’t include HyStart. The net effect is that, in our tests, they underperform CUBIC for general network performance. Unless a majority of your clients are on lossy connections, I recommend staying with CUBIC.

而其他拥塞控制算法看起来是在连接经历大量的丢包后(> .1%)获得的性能提升 (如 ,TCP Westwood+ or Hybla),不幸的是这些算法不包括 HyStart。在我们的测试中,他们在一般网络中性能表现不如CUBIC。 除非你的大部分客户端都是在受干扰的有损网络中,否则我建议使用CUBIC。

Of course the real answer here is to dynamically swap out congestion control algorithms based on historical data to better serve these edge cases. Unfortunately, that is difficult for the average web server unless you’re seeing a very high volume of traffic and are able to record and analyze network characteristics across multiple connections. The good news is that loss predictors and hybrid congestion control algorithms are continuing to mature, so maybe we will have an answer in an upcoming kernel.

当然最好的答案是基于历史数据动态交换拥塞控制算法为这些偶发状况提供更好地地服务。 不幸的是,这对于普通的web服务器是非常困难的, 除非你能够看到一个非常大的流量并且能记录和分析网络中很多个连接的特性。 好消息是,损失预测和混合拥塞控制 算法继续成熟,也许我们在即将到来的内核中会有答案。

发表在 System, TCP | 标签为 | 3条评论

Intel 10-GbE 网卡性能优化[翻译]

这是一篇翻译文档,原文请见:http://dak1n1.com/blog/7-performance-tuning-intel-10gbe

默认情况下,Linux网络被配置成最佳可用性状态,但不是最佳性能状态。对于一个10GbE的网卡来讲,这是尤其明显的。内核的 send/recv 缓冲区,tcp堆栈的内存分配策略和 数据包的队列都设置的太小,以至于它们不能工作在最佳的性能状态。下面所做的一些测试和优化,希望能够给你的网卡带来一定的性能提升。

在Intel ixgb的驱动文档中,描述了三个可以优化的策略。从性能优化的提升能力上进行排序如下:

1.在服务器和交换机之间允许大帧传输

2.用sysctl来优化内核配置

3.用setpci来优化网卡的PCI配置

需要明确的是,上述优化列表仅仅是一些建议。大多数优化工作是调整一些(个)配置,然后进行压力测试来检查优化是否生效。因此,大家得到的结果可能是多种多样的。

在开始任何压力测试前,我们往往需要禁止掉 irqbanlace 和 cpuspeed。这样做可以让我们获得最大的网络吞吐量以得到最好的压力测试结果。

service irqbalance stop

service cpuspeed stop

chkconfig irqbalance off

chkconfig cpuspeed off

(一)允许大帧数据传输

在linux系统中,配置大帧数据传输仅仅需要一条命令,或是在网卡的配置文件增加一行。

ifconfig eth2 mtu 9000 txqueuelen 1000 up

如果要让这个配置持久化,可以在网卡的配置文件中增加MTU的新值,将“eth2”换成你自己的网卡名字:

vim /etc/sysconfig/network-scripts/ifcfg-eth2

MTU=”9000″

(二)Linux内核 sysctl 配置

在linux系统中有很多重要的配置会影响网络的性能。下面的这些配置项来源于 2008 Red Hat峰会  Mark Wagner的精彩的演讲 (http://www.redhat.com/promo/summit/2008/downloads/pdf/Thursday/Mark_Wagner.pdf )

核心的内存配置:

    net.core.rmem_max -  max size of rx socket buffer

net.core.wmem_max - max size of tx socket buffer

net.core.rmem_default - default rx size of socket buffer

net.core.wmem_default - default tx size of socket buffer

net.core.optmem_max - maximum amount of option memory

net.core.netdev_max_backlog - how many unprocessed rx packets before kernel starts to drop them

下面是我修改后的 /etc/sysctl.conf 文件,可以把它添加到默认的配置后面:

 # – tuning – #

# Increase system file descriptor limit

fs.file-max = 65535

 

# Increase system IP port range to allow for more concurrent connections

net.ipv4.ip_local_port_range = 1024 65000

 

# – 10gbe tuning from Intel ixgb driver README – #

 

# turn off selective ACK and timestamps

net.ipv4.tcp_sack = 0

net.ipv4.tcp_timestamps = 0

 

# memory allocation min/pressure/max.

# read buffer, write buffer, and buffer space

net.ipv4.tcp_rmem = 10000000 10000000 10000000

net.ipv4.tcp_wmem = 10000000 10000000 10000000

net.ipv4.tcp_mem = 10000000 10000000 10000000

 

net.core.rmem_max = 524287

net.core.wmem_max = 524287

net.core.rmem_default = 524287

net.core.wmem_default = 524287

net.core.optmem_max = 524287

net.core.netdev_max_backlog = 300000

(三)PCI 总线优化

如果你考虑让你的优化工作进一步深入,还可以针对该网卡插入的PCI总线进行调整。首先,需要找到要调整的PCI总线地址,通过lspci命令获取:

[chloe@biru ~]$ lspci

07:00.0 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)

这里的07:00.0 就是PCI总线的地址。现在我们可以在 /proc/bus/pci/devices里面找到更多的信息:

[chloe@biru ~]$ grep 0700 /proc/bus/pci/devices

0700    808610fb        28       d590000c       0        ecc1    0   d58f800c  0  0      80000    0    20  0   4000   0    0        ixgbehttp://dak1n1.com/blog/7-performance-tuning-intel-10gbe

正如我们看到的这样,各种PCI设备的信息就显示出来了。不过,我们最关注的数据在第二列,808610fb。这是设备的供应商ID和设备ID的组合。供应商ID:8086,设备ID:10fb。我们可以使用这些值来优化PCI总线的MMRBC(Maximum Memory Read Byte Count)。

下面的命令可以提升MMRBC到 4k 的读,提升总线上对爆发增长的处理能力。

setpci -v -d 8086:10fb e6.b=2e

关于这条命令:

-d 选项指明网卡在PCI-X总线结构上的位置

e6.b 是 PCI-X 命令的寄存器地址

2e是要配置值

下面是这个寄存器的其他可用值(尽管上面已经列出了一个,2e,是Intel ixgbe文档中推荐的配置值)

MM  value in bytes

22  512 (default)

26  1024

2a  2048

2e  4096

 

测试:

测试往往是在每一项配置调整的时候都要进行的,不过,我这里为了简洁仅仅展示一下优化前和优化后的结果对比。使用的压力测试工具是 “iperf”和 “netperf”

下面是 10GbE 网卡在优化前可能的性能状态:

 [  3]  0.0-100.0 sec   54.7 GBytes  4.70 Gbits/sec

 

bytes  bytes   bytes    secs.    10^6bits/sec

87380 16384 16384    60.00    5012.24

优化后:

 [  3]  0.0-100.0 sec   115 GBytes  9.90 Gbits/sec

 

bytes  bytes   bytes    secs.    10^6bits/sec

10000000 10000000 10000000    30.01    9908.08

哇!优化后带来非常巨大的变化。这是我花了几个小时候在我的HDFS集群中所看到的最好的结论。无论你的应用程序是怎样的,这些优化都应该很适合你。

 

 

 

发表在 System, TCP | 留下评论

三十之惑–第三部分(百度文库)

今天开始写百度文库的面试,百度文库的面试共经历了三轮,第一轮应该是高工,两位一起面。

两位高工开始很客气的介绍百度社区的组织架构,以及文库的位置,其实,就是说文库很重要,会很好的发展,当然,我相信。后面的就是技术部分了,大体上没有超出小米的范围,当然,更多的是关于架构方面的一些问题。悲催的是我一直没有问他们具体的职位,不同职位或是不同方向的回答侧重点是不一样的(我在考虑是否把这段经历补充在简历当中),当然,我也没有主动介绍太多关于带team开发的事情。

带队开发的事,大多数情况下带队开发leader(除非一线开发组长)做的开发工作太少,可能仅仅会参与项目规划(这差不多都是需求方和一线开发人员定的,leader只是得到一个结果或是压缩工期)、项目追踪、项目推进、项目风险预估和排除。我一直认为“leader要把自己看成是team中最不重要的那个”,让一线的同学拥有做决策的权利,同时参与一线才能知道项目的真实难处在哪里,往往我会自己安排一些小业务模块或是偶尔封装一些框架中使用的lib

有点跑题,回到面试环节,最后两位问了一个关于文库防数字公司抓取的问题,我个人认为这是个无解的问题。不过,我还是大体上思考了几个方案,供大家品评:

其基本逻辑无外乎:增加抓取难度,使其不能抓取;即便抓取了也不能用。

第一面基本上不记得还有其他的问题了,这大概用了1个半小时,不得不说百度的兄弟很客气。

第二面重复一些第一面中关于高可用监控的话题,也大概介绍了一些我做系统优化的环节。其中有个话题倒是被面试官质疑了一下,问题如下“我觉得你做了很多系统架构、优化方面的事情,但是这些事情都是很琐碎,看不出来有什么套路”,大概的意思是做系统优化有没有什么模式或是方法论吧。事实上我本考虑从网络、系统软/硬件、服务单元、代码的逻辑思路来说,但这基本上是“鬼子扫荡式”的排查方式,应该算是大路货。我更想说的是“按图索骥”的方法,所有环节都通过日志、trace的方式进行追踪,通过简单的数据分析的方式获取系统性能的瓶颈以及可能的问题所在。前一种适合“没事找点儿事做”的情况,而后一种,更适合线上业务随机状态下系统问题的发现和追踪。目的性和目标性极强的方式,适合我当时的情况。

二面还问了我一些关于带团队的问题,比如我是如何解决当初空降并让新老团队很好的工作的,我的回答是:第一原因就是幸运,每一位同学都非常善意;其次是大家对项目的共同认可;最后才是我做的一些努力:比如真实,不刻意去做什么一些特别的事情;对新老团队同样看待,工作分工协商解决;安排的事情首先是信任,尽可能充分的听取大家对事情的看法,尽可能的达成一致;请大家自己发现项目中的技术问题,推动形成技术项目进行解决并给予一定的时间;还有,我认为最重要的一点,技术团队的价值应该首先表现在技术环节上,无论是项目质量还是代码质量我认为对我当时的团队状况,一切从简单开始是最好的方式。并且,我用同样简单的方式成功劝服两位已经开始办离职手续的android工程师继续工作,这是当时公司仅有的两位android开发工程师。至少我的经历让我觉得这段管理旅程非常简单顺利。

二面的问题还有一些是比较苛刻的,比如上面提到的如果真的有人对项目不认可怎么办?比如分工协商不成功会如何?还有就是技术团队驱动的技术项目大家会不会愿意参加?林林总总的问题比较琐碎。我的理解是团队中特殊情况总是有的,不过,我非常认同那句可能是马云说的话:要么钱没给够,要么领导做的不够。是否在信任、认同感、承诺、互惠互利等方面做到足够。如果不因私心,往往是因为误会,不要等误会变得太大再沟通。并且,我觉得沟通的时候说话适当直接一些会更容易理解,即便是对对方的不满。猜测对方往往是造成误会的根源。

二面问了我这样的问题“感到做的最好的三件事和最差的三件事”,绞尽脑汁才想不出来凑够三件,不好意思在这里说了。

二面大概一个小时左右吧,轮到了三面,一位百度的高级经理。同这位面试官也沟通了一个小时以上,不过仅记得几个问题了。比如用的最多的百度产品,比如我说搜索还是常用的,比如贴吧也了解过一点,比如LBS地图(很少用百度的产品,最近觉得导航很不错)。最后面试官问我最想做的是什么,我回答是,应用和系统架构、运维方面的优化,我在这方面比较有经验。然后他继续问,“如果带团队开发是否可以?”,我觉得这方面要看团队的工作方式和项目管理方式如何。

百度的面试经历能记得的大体上就这么多,收到HR的评价是“比较有lamp平台的经验,但是方向不太match”(原话),然后推荐到贴吧那边了。

近半年直接带的team仅有运维和一个两人的php开发team,团队很小,所以不太费力气想太多的管理问题,这次求职我也还没有针对管理问题花太多时间进行总结,抽时间认真思考一下。

明天开始写一些我对未来工作的思考以及要求。

发表在 其他 | 标签为 | 留下评论

三十之惑–面霸的八月(第二部分)

书接上回,今天叙述小米的面试经历。

这里可能有一些技术理解和技术方案,欢迎讨论。另昨天共计收入7笔共95元,够我喝几杯咖啡了,谢谢所有捐钱的朋友。

如果你心疼我码字辛苦,有钱朋友钱场,没钱的请拉朋友来捧个钱场,捧场链接:https://me.alipay.com/chunshengster ,多少不限

小米:

  1. 运维部

在小米是聊了两个部门的,首先是运维部门,在 @wilbur井源 的热情招待下,吃了顿大餐,抱歉的是我没有带足现金,所以付款时我无法“客气”,改天补请。

wilbur井源同两位同事与我四人边吃边聊,我简单介绍当前的网站的服务结构以及部分业务的技术设计,比如网站架构的分布情况,分布式文件系统fastDFS的使用状况、RedisMySQL的一些部署结构和技术,其中尤其对监控这件事情我做了详细一些的说明(详见服务可用性监控的一些思考以及实践),中间提到了关于主动监控(主动监控是指通过运维和业务部门指定监控的系统资源、接口、页面、日志等,主动发现问题,警报级别较高)、被控监控的概念(指通过JSlib或客户端lib对于所有的操作尤其是网络接口的请求进行监控,对异常进行汇报,通过收集日志的方式进行可用性问题的发现)。当然,还有必不可少的是对haproxy的运行和优化状况(参见Haproxy配置),MySQL的架构及优化方式(见MySQL架构及运维),Redis常见的性能问题(参见redis架构及运维问题),fastDFS同其他分布式存储MogileFSTFSlusterfs的在功能、运维成本上的横向比较,多IDC图片cache的部署以及性能优化(参见多idc图片Cache部署),Linux内核参数(参见Linux内核配置)和让我特别自豪的是关于网卡smp affinity/RPF/RFS的优化效果(参考3/4/5)的一些优化等。当然,这是正经的运维部门,我阐述了我对“运维”工作的理解:60%的分析整理工作加上40%的技能,分析整理能力是做好运维的基础

井源也询问了几个安全问题,我粗浅的理解是:SA的经历来讲,做好IT系统规划,合理区分服务器角色,通过iptables是能够阻止大多数接入层非法请求的;对于web业务的安全来讲,SQL注入、CRSF等攻击是因为对输入输入内容的过滤不严格导致的,在开发的过程中合理使用一些优秀框架或lib,也能够避免大多数漏洞的产生;有个比较有意思的话题是关于溢出的,现在我已经不会计算溢出地址了,在我当script boy的时候研究过一点,忘光光了,惭愧……

井源这边的效率很好,边吃边聊的气氛很放松,不过很多问题都停留在一些思路和效果数据上,没有勾勾画画的太多深入的探讨。

 

  1. 电商部

大约8点半左右到的电商部门,常规面试的第一轮都是技术,包括细节。面试官是位张姓的team leader

在这轮面试的过程中,因为是在会议室,有笔有板,所以我边讲边写。大体上介绍了我对web服务架构的理解,我认为,web服务架构大体上离不开这样几个层面:接入层(负载均衡)、业务服务层、数据层,一般还会有不少的后台辅助程序进行同步、异步的处理各种不适合在业务层融合的服务单元。数据层可以包括DBCacheFile等,数据层还可能会有很多中间件或代理服务器用来做数据层的负载均衡或是HA,以及Sharding等。同面试官详细介绍了当前服务的公司在每一层所采用的技术,分别是:haproxynginx+phptwemproxy+redisMySQL+RedisCacheVarnish+Squid+nginx+fastDFS

haproxy的服务器配置是按照100w并发的目标进行配置和优化的,计划100w客户端连接,考虑每个客户端连接可能产生1个内部连接,按照每个连接消耗4k(此处修正为17K,haproxy的官方数据,见参考8,感谢 @GNUer 的修正)内存来算,大约8G(此处修正为32G)内存【这里的计算还需要再考虑,我担心haproxy的每个连接消耗17k内存是包含对内部服务器的连接】,实际上往往比这个数字要大。目前达到的最大连接数目测到过16w,在接入层的系统优化上分别有:网卡中断优化(参考3/4/5),linux 内核参数优化(linux sysctl.conf配置)。

值得一提的是,我们的haproxy服务器都是64G内存,实际上远远永不到这么多,图片服务的最外层cache,即Varnish,我们也是部署在haproxy服务器上的。

在最外层服务器上,我们每天大约5亿+1-1.5亿+的动态请求、3-4亿+的图片请求)的请求量,共计使用764GDell R410,目前看负载还很低,从系统的各种资源上看,请求量翻倍应该是没有问题的。

在最外层的服务器配置上,有一个问题值得注意,即sysctl.conf的配置中,timestamp必须为0,这个在tcp协议的扩展标准中有提到,否有nat环境的客户端连接有可能产生异常,异常的状况可以在netstat -s 的输出中看到。还需要注意的是timestamp=0的情况下,tw_reuse是不生效的。

要保证服务器能够接收大并发的连接请求是件不难的事情,但需要考虑一个细节,每接收一个请求,haproxy就需要至少分配一个系统的tcp端口请求后面的业务服务器、cache服务器,系统一个ip地址可用的端口数最多为65535,一般还需要减去1024。值得考虑的是减小 tw_bucket 的容量,让系统在tw_bucket满的状况下,对tw状态的连接进行丢弃,以达到快速回收的目的,tw的默认回收时间的2倍的MSL。还有一个方式就是多配置几个ip

还有一个问题,接入层的服务器往往会开启iptables,内核中nf的相关配置也是需要优化的,比如 nf_conntrack_maxnf_conntrack_tcp_timeout_established等。

 

在业务层的优化有nginx+phpfastcgi连接方式php-fpm.conf配置中的优化),我的一个经验是,如果nginxphpcgi运行在同一台服务器,采用unix socket的方式进行fastcgi协议的交互是效果最快的,比127.0.0.1的回环地址要快太多。我在08年优化过一台服务器(Dell 296016G内存),通过两个步骤,将一台服务器从900qps,优化到6000qps以上,其一是将fastcgi协议运行在unix socket上,其二是合理配置spawn-fcgi的进程数量。现在基本上phpcgi都是运行在php-fpm中的了,其进程池逻辑是我最赞赏的功能之一。

如果nginxphp-fpm不在同一台服务器上,可以考虑使用fastcgi_keepalive的配置,实现nginxfastcgi服务器持久连接,以提高效率。

nginx+php-fpm提供的运行状态非常有意义,nginxstatus模块和php-fpmstatus输出可以告诉我们nginx进程的请求处理状况,php-fpmstatus输出可以告诉我们php-fpm的进程池设置是否合理。我们目前对这两个数据通过nagios定期采集,并绘制成图表,很有“观赏价值”。

php-fpm.conf的配置中还有几个参数对优化比较重要,其一是进程自动重启的条件 pm.max_requests,其二是php-slow log的配置,slow log 是优化php代码的非常重要的信息。在我目前的环境中,php的慢执行日志是通过rsyslog进行传输并集中分析的,以此反向推进开发对php代码的优化。

php的服务器在高并发的情况下,有可能因为服务器本身可提供的端口数量的限制,无法同redis服务器建立大量的连接,这时候可以在sysctl.conf中配合timestamps=1 加上 tw_reuse/tw_recycle的方式,进行端口快速回收,以便更好的向数据层建立连接,接入层的haproxy是不可以这样的。

这一层还涉及到一个安全问题,就是php代码被修改并挂马的状况,我的解决方案是,将php-fpm的运行用户同php代码的属主设置成不同的用户,并且保证php-fpm的运行用户不能对php代码具有写的权限。

 

数据层的情况里,MySQL主从结构以及MHA+keepalived的高可用配置,这个基本上是看文档应该就能够理解的。如果是5.6的新版MySQL,其高可用监控可能可以做的更简单,MySQL官方提供对应的工具,只是我还没有测试。对MHA的监控功能,我觉得亮点是MHA对切换过程中MySQL binlog的获取和执行,在最大程度上避免了数据丢失。但是其缺点也是有的,比如:监控进程在触发切换后就停止了,一旦触发,必须重新启动进程再继续监控。06年时我在sina做过一个叫Trust DMM的项目,通过 DNSMON加上自己写的插件,监控MySQL主从集群的可用性,可以实现,主库、主备自动切换(缺乏binlog处理的环节);从库是一组服务器,如果从库发生问题,可以自动下线。只是这套系统部署起来比较麻烦。这个项目曾经获得过sina的创新一等奖。

我还提到了我认为的DBA日常的工作至少应该包括:审查并执行上线SQL;定期检查MySQL慢日志并分析,将分析结果反馈到开发部门进行调整;定期审查数据库中索引的效率以及可用性,进行优化我反馈。现在做一个一般水平的DBA已经相当容易了,对percona的工具了解透彻,已经能够解决非常多的数据库问题了。

MySQL还有一个难缠的问题,numa架构下,大内存服务器内存使用效率的问题,numactl对策略进行调整,如果使用perconaMySQL版本,可以通过 memlock配置对MySQLInnodb引擎进行限制,禁止其使用swap

MySQL常见的架构里,还有一种主从存储引擎不一致的方式,即主库采用Innodb引擎,提高并发写入的能力,从库采用Myisam引擎,这种方式目前我们也在采用。这样做一是为了获取更好的读性能,另外是,Myisam引擎的是可以节省内存的。Myisam在索引数据内存读取,数据内容磁盘读取的状态下,已经可以比较高效的运行了,myisam_use_mmap的配置项,会让MySQLmyisamdata文件也mmap到内存中,这样做既高效,又可以使用mysiam引擎的特性。

数据库主库要避免一件事情发生,就是无条件删除和无条件修改,如“delete from table”以及”update table set xxx=yyyy”等无where条件语句,原则来讲是应该禁止执行的,这样的权限不应该开放给开发的同学,甚至DBA都不能无限制的操作。目前我的解决方案是 sql_safe_updates=1,但这配置是不能够写my.cnf中的,只能启动mysql后进入console进行配置。

 

当前我们还使用了Redis作为DB,基于主从架构,跨IDC。目前的问题是,复制连接断开后,Redis快照重传的问题,从库会在快照替换期间有短暂的性能抖动。 Redis2.8新版本psync的特性应该可以改善这个问题。我们还使用twemproxy,目前部署在每一台php服务器上,并监听unix socketphp使用phpredis的模块进行连接。有效减少三次握手的时间。temwproxy还有很多其他的优秀特性,通过一致性hashcache集群,可以有效的避免cache迁移问题。通过其对后端redis的健康监控,可以自动下线有故障的redis

 

还有针对多IDC的图片存储和Cache部署情况。目前我们自建的图片CDN承载网站每天约4亿的请求,带宽最高峰值约1.5G左右,其结构大体上是中心IDC存储图片原图+SQUID disk cache存储图片缩略图,在外地IDC使用两级缓存,分别为一层SQUID disk cache(两台,做HA),另一层为Varnish cache(最多四台),实际上,如果仅考虑work around的状态,squid cache层基本上也可以不要的。但是,目前这样的结构可以减少varnish回中心节点的请求,减少中心机房带宽的压力。这个结构还算简单,varnish在高并发请求下,有一些资源配置是需要注意的,比如NFILES / VARNISH_MAX_THREADS / nuke_limit 等。

 

沟通的技术问题还是非常多的,包括在井源那里提到监控框架的事情,也尤其提到了我对rsyslog的优化,优化后的rsyslog在可靠性方面是非常值得称赞的(优化思路见参考6

 

我有一些将电商三面的运维运维同学的问题综合到这里了,有些话重复的就不再描述。

值得一提的是二面是另一位开发负责人,一看就是个很有独立思考能力的同学,他问了我一个很有意思的问题,大体的意思是,在系统架构方面,有这样的几个层次,从下往上:使用开源、精通开源,优化并修改开源软件,创造开源软件。问我自己评价我是在哪一个层次的。我认真的思考了一下,我应该是在第二个层次,有些精通的,有些修改过的。

 

电商四面是时间最长的,至少有两个小时以上,结束的时候已经是夜里一点四十了,我觉得电商的老大是应该在支付宝里面给我捐一些钱才好的 ,不知道有没有小米的同学能够转告哈 :) 。我们应该是谈到了非常多的事情,包括秒杀的解决方案,包括对持续集成和自动化测试的理解、对后台数据业务类型的开发中数据计算错误的理解,时不时能够得到“我们想的很一致”这样的评价。

那时已近半夜,记忆进入低效态,一些太琐碎的事情记不得了,重复的技术方案也不再赘述。下面简单描述一下我对秒杀的解决方案的理解:10w的数据,从010w,不能多卖。目前的问题是,每次到秒杀时分可能同时进入100w的请求/连接。如何破?

我的方案是:排除usersession等外部依赖服务的前提下,两台ha外面抗并发连接(后来想这个无所谓的,不如做成php的服务器),三台PHP服务器(不要使用任何框架,最朴素的纯粹PHP代码),两台Redis(最初说了一台)。具体优化状况如下:

  • haproxy优化能够支持百万并发连接,这个很容易了
  • nginx优化worker connections,优化nginx的并发支持能力和请求队列的接收能力
  • php-fpm优化listen.backlog,优化fastcgi请求队列的接收能力。
  • Redis 假如在秒杀的1分钟内,服务器不出现故障,优化redis的最大连接数
  • 优化所有服务器的网卡、sysctl参数

php的逻辑可以简单的理解为对redis的某一个key进行incr原子操作,如果返回的当前数值小于等于10w(两台redis的情况下应小于等于5w),则认为中签。【补充:后面也有提到使用队列进行缓冲或是通过gearman worker长连接redis进行取号的方式。但是我认为如果能够满足性能要求,架构越简单越好】

从我以前看到的数据来讲,redis的最好状态在8w qpsnginx+php08年时已经优化到6000 qps,目前的服务器设备(双核16cpu+64G内存)达到23wQps应该也是不难的事情(这个的最新数据我不知道)。上述配置至少应该能够在5s内完成10wredisincr操作。加上系统各系统对请求队列的支持,可以几乎做到不报错,短暂延迟。

如果考虑1redis请求量会很高,可以考虑分片,每台分5w

[补充]看到一些讨论,补充一下当时提到的业务处理的关键:1,不能卖超;2,如果已经买完,所有请求跳转到某个静态页。所以,php代码只需要到redis计数中去检查一下是否超过10w,如果超过,就跳到静态页面。

当然,这是在仅仅思考不到1分钟内给出的方案,从现在来看,haproxy是可以不要,nginx扛并发连接的能力也不错。所有的细节还需要通过压力测试进行验证。而实际情况加上对其他服务的依赖(我不知到还有哪些,抽丝剥茧去除干扰),方案也会更加复杂一些。据电商老大讲,实际情况是,秒杀的服务用了十几台服务器,秒杀的时候偶尔出现一些故障,小米做秒杀的同学,压力很大哦。

如果你提到要记录中签的用户的uid和中签号码,还是redis吧。

(突然wpslinux版崩溃了,只能恢复到这里,后面的部分内容是重写的,可能有点混乱)

针对刚才的问题,我在白板上画了个简单的架构图:haproxy+nginx/php+redishaproxynginx/php都是可线性扩展的,redis可以通过sharding来实现扩展。理论上讲,一个可扩展的架构是可以满足任何性能要求的,更何况如此简单的逻辑,单机性能已经可以做到非常高了。

电商王姓负责人在问我方案时问这个需求会有哪些难点?我看着白板笑笑:目前看,应该不存在难点。如果有问题,应该看日志和服务状态以及服务器状态。

 

第四面聊得很头机,对方几次想结束时都突然冒出来一个问题,每一个都会讨论比较久,比如后台的一些计算操作是否换成java更合适,因为java可以更严谨。我说这可能不是语言的问题,而是程序员习惯和素质的问题,如果想换,其实我倒是更愿意尝鲜,比如用go,还可能可以同时满足性能的问题。

还有突然聊到持续集成,我坦言,我对持续集成的理解停留在用工具实现自动测试和发布这样的层面上,没有实操经验。但我个人的一个粗浅的认知是:持续集成的前提是自动化测试,自动化测试的两个难点:1,自动化测试用例的设计;2,程序员对自动化测试的理解和心理反抗程度。我在目前单位有过短暂的尝试:专业的传统测试人员对测试用例进行设计,程序员接收到的需求应该包括正向逻辑的产品需求和测试用例的需求。开发工作完成的标记是:自己写的测试用例在自己的代码上完全通过,代表自己一项开发工作的完成。

说到这里,对方不禁双手伸出拇指!(哈哈哈哈)

或多或少也还有一些别的话题,我自认为那晚像演讲一样很精彩,只不过时间已过午夜,其他的一些细节不太记得了,如果想起或小米参加面试的同学有提起,我再补充了。

【补充】小米电商的四面还有问到队列的问题,问我了解多少。我对队列的理解大体上是这样:1,对于无法通过扩展性解决的问题,通过队列进行缓冲是非常好的机制,由于队列产品的技术特性,队列产品往往会更倾向于优先使用内存,队列本身的业务逻辑也会比较简单,因此,队列高效的性能,可以缓解数据库并发写的压力,事务性的队列还可以在一定程度上能够帮助业务逻辑更加可靠。

我了解的队列有redis队列、Q4M,还有一种高级的AMQP协议,支持AMQP协议的有ZeroQRabbitQ。我用过有redis队列,及其简单、高效,但是有个特点:队列中的元素取出来后,如果处理失败,数据是不会自动回归队列的;Q4M有个高级的特性,如果取出队列的程序发生异常(如崩溃),Q4M会自动把取出的元素放回队列。Rabbit我了解过一些,用python封装过一个lib自己玩,不过,现实生活中我还没有找到特别合适的场景用它。

整场小米的面试两个部门加起来共计约7个小时,这是我经历过的最长时间的面试了……小米的面试很辛苦,今天码字也很辛苦,现在已经是凌晨1点半了,如果你觉得上面的经过对你有所帮助或是有意思,就捧个钱场或人场吧: http://me.alipay.com/chunshengster

 

 

 

 

参考:

 

  1. Profiling: From single systems to data centers http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/ko//pubs/archive/36575.pdf
  2. X-Trace: A Pervasive Network Tracing Framework
    https://www.usenix.org/conference/nsdi-07/x-trace-pervasive-network-tracing-framework
  3. http://blog.chunshengster.me/2013/05/smp_irq_affinity.html
  4. http://weibo.com/1412805292/zvNrDsqtT
  5. http://weibo.com/2173311714/zw40tv3D2
  6. http://blog.chunshengster.me/2013/07/high_performance_rsyslogd.html
  7. http://www.wandoujia.com/blog/from-qa-to-ep
  8. http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-maxconn
发表在 其他 | 标签为 | 24条评论

三十之惑–面霸的八月(第一部分)

三十之惑

                              –面霸的八月

题记:

三十几岁了,从sina大学肄业后,在外面漂泊,不好不坏。

      从好的角度讲,这几年自己的技术没有减退,偶尔也还能够略有深入,同时能够更多的接触到产品、运营、甚至营销,而我自己也能够在很多场景下,不紧不慌,还算从容。从坏的角度讲,每一项都没有达到自己想要的成就。

从坏的角度讲,09年底从sina离职后,至今已经结束了第三份工作。

此次离职实非我愿,具体细节不好也不愿再细说,概括来讲是我作为小公司的技术管理人员虽尽力但仍没有能够让老板理解我在某项目中的安排,反而产生了误解,以致后来越来越多的误解到其爆发,刻意为难。虽有后来的歉意,但间隙已生,且无合适的解决方案,遂,今日失业之现状。

如果你看此文时心有戚戚,请到这里:https://me.alipay.com/chunshengster

好吧,下面正题,首先是“万达”

正题:面试

万达:

万达的推荐工作是一位认识了6-7年的猎头朋友推荐的,小姑娘爽快、伶俐,不好拒绝。坦言讲,我本人对万达还不了解,外面的传言里也大多是不好的,我仅仅是去试试看,职位是web主任开发工程师的职位,听起来也挺“高端”的嘛,当然最后发现整个过程被当作了一个乐子。

到万达下午3点半,20分钟做完题目,一道数据库设计的题目,一道询问熟悉的HTTP协议头及其含义,一道大数据量(千万级别数据)的数据库技术方案,一道所谓的大数据计算,还有两道算法题,其中算法题中有我认为最可耻的“求最大公约数”。

笔试结束,同一位小朋友口头沟通,大约一个半小时,当然,花了这么多时间跟我口水比较多有关系,因为每次看到小朋友木讷的眼神我都忍不住“好为人师”的深入讲解下去。

当然,我对万达和猎头在面试环节安排的人不满意,并将此意见表达给猎头,我觉得面试的人的水平和能力远在我之下,甚至不能对技术问题进行有效沟通。朋友戏谑,我在万达只是找了个“乐子”,实非我意,抱歉。

万达的面试是在周一。周二,我赶了两场:京东旗下的“网银在线”和“小米”。

网银在线:

网银在线的面试流程应该是在沈姓VP的授意下刻意调整的,沈直言,他对我不是面试,正常面试不是这样的流程,为此我深感荣幸和感激。首先是跟沈沟通我现在的情况,以及可能的工作内容和方式。沈给我的主观的感受是,直白、深刻,当然,经历的不同也让我略感压力,压力在于我对其部分判断不能确定是否“武断”,比如,10人团队和30人团队的管理方式上的确存在差别,我并不觉得我现在30人的团队管理是“哥们义气”的方式,当然,我也当面承认,在这30人的管理经历里,我非常幸运的是未遇到突发的管理难题(30team的管理经历我将在后面单独描述)。

同沈沟通的另一个问题是应用运维的方式以及利害。我也是在这个过程中,了解到阿里应用运维在整个业务经营体系中所占的重要性,其承载了开发(coding)和系统环境(软硬件)中间的沟通以及优化的工作,这项工作中有对业务模块、逻辑深入了解的必要,最好有开发的经历,同样需要对系统软硬件的承载能力有所了解深入,对我这种粗浅的理解来讲,就是“为每一双特别的脚定制一双舒适的鞋子”,当然要对这双脚和鞋子都有足够的了解才行。而我的优势在于,在需求分析、产品开发、系统运维、优化上都还蛮有经验,这是做好业务运维的最好的基础。后来我想我从08年在sina博客时开始,就已经开始从事这样的工作了,只不过sina叫产品线架构师。

当然,我也有提到,我在最近这半年系统优化过程中所使用的方法(优化方法和思路后面单独描述),包括简单的对google某篇论文中提到如何通过监控解决线上代码运行效率这一问题的理解(见参考1),包含这篇论文引用的 x-strace见参考2) 的理解。我提到了,在LAMP环境中,这些方式和机制几乎是天然存在的。有个难题是,网银在线是java的平台,我基本上没有接触过。

网银在线的二面是当前的运维负责人(抱歉我没有问具体的title),问了一些还算简单的服务器技术,如我在微博上提到的,很给面子。

三面是人力资源,小姑娘言语犀利,我有一说一,坦然面对并坦言自己不足,直言在人生规划中急需解决的问题。但在最后一次的离职原因上,当时我的确没想明白,也没办法说明白,这个问题在所有面试的过程中,一直在困扰着我。

面试结束后,在京东的大Logo旁请京东的同学拍了一张照片。赶赴小米。

本来周二下午约了潘少宁在车库咖啡,但是网银在线的同学打电话过来说只有周二他们集中面试,并且VP在,无奈,只好委屈潘,把跟潘的会面改到了周三上午。

我在写此面经的同时,给自己留了不少作业,我决定把这些技术方案也都一并写出来,算作面经的一部分。下节预报:小米两个部门的面试和百度文库的面试。

从今天开始,已经正式进入失业阶段,有钱朋友钱场,没钱的请拉朋友来捧个钱场:https://me.alipay.com/chunshengster

另:感谢 @震耳欲聋的沉默 提供“面霸的八月”这个名字

参考:

  1. Profiling: From single systems to data centers http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/ko//pubs/archive/36575.pdf
  2. X-Trace: A Pervasive Network Tracing Framework
    https://www.usenix.org/conference/nsdi-07/x-trace-pervasive-network-tracing-framework
发表在 其他 | 标签为 , | 2条评论

关于Rsyslogd 的一些配置 (高性能、高可用 rsyslogd)

      最近公司的日志传输服务器因网间带宽被调整后出现了日志堵塞的情况,更为严重的是公司大量的业务日志也是通过 PHP 的 syslog接口传输的。这样,因为rsyslog的新版本默认不期望丢弃任何数据,而rsyslog中的日志又传输不出去,导致了业务在写日志的时候“被”堵塞住了。

       拿到rsyslog的配置后,发现仅有一些简单的关于传输逻辑的配置,而关于rsyslog进程、队列、传输效率的配置参数都采用默认,这种仅仅能够 work around 的配置在测试或运行初期是允许存在一段时间的,在系统、环境正常的时候能够运行。一旦出现异常,各种问题就全出来了。

       推荐的文档和我认为比较关键的配置请见下图:

rsyslog_config_opt      几点说明:

  1. 推荐仔细阅读 第一篇 关于 rsyslog queue的文档,细节几乎都在这篇文档里。
  2. 定义 $MainMsgQueueFilename 可以简单理解为队列入口无限大,$MainMsgQueueMaxDiskSpace来控制大小。
  3. 队列的堵塞可能的原因是各种其他原因导致的 MainMsg 满了,而默认配置下,rsyslog不主动丢弃消息。
  4. $QueueHighWatermark可以控制 MainMsgQueue 如何使用 disk作为队列存储,而不再是仅仅使用内存。
  5. $MainMsgQueueDiscardMark 和 $MainMsgQueueQueueDiscardSeverity 配合控制如何丢弃消息。
  6. 在我的 x220i ubuntu 环境下,可以看到几十G的队列文件(网络传输堵塞时以及进入的消息量过大时)、丢弃消息的通知,内存使用的状况。因这一切都不复杂,不再赘述。
  7. rsyslogd的RELP(http://www.librelp.com/)相关的内容暂未涉及。

补充:

  1. 附加另外两份参考: http://www.gerhards.net/download/LinuxKongress2010rsyslog.pdf      http://mperedim.wordpress.com/2010/01/21/rsyslog-evaluation/
  2. 2013-07-24 补充文档:

       刚好微博上 @zzyongx  也提供了一个 syslog-safer (https://github.com/zzyongx/syslog-safer) 软件,大家也可以试试。

 

发表在 System, TCP | 标签为 , , | 6条评论

puppet模板的自定义数据结构

2013-06-21 15:41:23的屏幕截图 2013-06-21 15:41:00的屏幕截图

 

 

 

折腾了一下,pupet的模板语法真是强大,通过自定义数据结构来实现配置文件配置项扩展性,避免了硬编码在模板中的同种语义的不同变量名,看图:上面和下面的区别

 

 

 

2013-06-21 15:16:42的屏幕截图

发表在 System | 留下评论

SMP IRQ Affinity


感谢 @淘宝褚霸 等人的大量文档。各位SA,如果你的服务器cpu使用很不均衡,top 中si的用量很大,不妨试试这个脚本。
五一前优化服务器,把smp_affinity 和 rps/rfs的内容通通看了遍,花了两天时间写了个自动配置的脚本,在github上:http://t.cn/zTQ5HRW ,欢迎抓虫。

[补充]

SMP affinity and proper interrupt handling in Linux
http://www.alexonlinux.com/smp-affinity-and-proper-interrupt-handling-in-linux
文章提到  如果使用的内核中包含 CONFIG_HOTPLUG_CPU 选项为 On的情况下,网卡的中断就可以自己平衡了。

 

 

Scaling in the Linux Networking Stack: http://www.mjmwired.net/kernel/Documentation/networking/scaling.txt
SMP IRQ Affinity: https://cs.uwaterloo.ca/~brecht/servers/apic/SMP-affinity.txt
linux kernel 2.6.35中RFS特性详解: http://www.pagefault.info/?p=115
Linux 多核下绑定硬件中断到不同 CPU(IRQ Affinity): http://www.vpsee.com/2010/07/load-balancing-with-irq-smp-affinity/
计算 SMP IRQ Affinity : http://www.vpsee.com/2010/07/smp-irq-affinity/
Linux SMP IRQ Affinity: http://www.igigo.net/archives/231
Linux内核 RPS/RFS功能详细测试分析: http://www.igigo.net/archives/204
rfs: Receive Flow Steering : http://lwn.net/Articles/381955/
rps: Receive packet steering: http://lwn.net/Articles/361440/
Receive Packet Steering : http://lwn.net/Articles/331582/
Software receive packet steering : http://lwn.net/Articles/328339/
MYSQL数据库网卡软中断不平衡问题及解决方案 : http://blog.yufeng.info/archives/2037 SMP affinity and proper interrupt handling in Linux http://www.alexonlinux.com/smp-affinity-and-proper- interrupt-handling-in-linux
Why interrupt affinity with multiple cores is not such a good thing http://www.alexonlinux.com/why-interrupt-affinity- with-multiple-cores-is-not-such-a-good-thing
Multi-queue network interfaces with SMP on Linux https://greenhost.nl/2013/04/10/multi-queue-network-interfaces-with-smp-on-linux/

发表在 System | 标签为 , , , , | 20条评论

经典存储架构 Haystack GFS TFS

经典论文翻译导读之《Finding a needle in Haystack: Facebook’s photo storage》   http://www.importnew.com/3292.html

优酷网视频存储架构   http://blog.csdn.net/starxu85/article/details/5673029

经典论文翻译导读之《Google File System》  http://www.importnew.com/3491.html

淘宝CDN、TFS的介绍:

http://www.infoq.com/cn/presentations/zws-taobao-image-store-cdn

http://tfs.taobao.org/index.html 

发表在 Storage | 10条评论