My self learning notebook, step to issues to follow my notes.
dafang / notebook Goto Github PK
View Code? Open in Web Editor NEWMy self learning notebook
My self learning notebook
My self learning notebook, step to issues to follow my notes.
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中的这个算法控制着这一系列的过程,被成为拥塞控制算法。有很多的拥塞控制算法,并且客户端和服务器之间可以根据它们网络不同的特性使用不同的算法。大多数拥塞控制算法聚焦于优化网络丢包中的一种,比如过载丢包(如有线网络),或是随机丢包(比如移动网络)。
ssssssssss
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.
一些拥塞控制算法试图通过缩小“压力增长”至“预期压力”阶段的重发延迟的时间间隔来确认丢包的原因。这些称为带宽评估算法,包括 Vegas、Veno 和 Westwood+。不幸的是,所有的这些方法都没有效果,并且在两条相似的数据流中无法找到可重用的信息。
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
xxxxxxxxxx
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服务器是非常困难的, 除非你能够看到一个非常大的流量并且能记录和分析网络中很多个连接的特性。 好消息是,损失预测和混合拥塞控制 算法继续成熟,也许我们在即将到来的内核中会有答案。
Linux常用性能调优工具索引
Linux 利器 strace
技巧: 使用truss、strace或ltrace诊断软件的"疑难杂症"
I left a Python script running at the client's, overnight, expecting
everything to be ready in the morning. But when I checked next day the CPU
was pegged at 100% and the log indicated no progress since 1am. Clearly the
Python code had a bug and was "spinning" in a tight loop.
The problem, then, was to find out what code was being executed. Luckily
there's a very neat solution, that I've used before, that does exactly this.
It's described in an answer by "spiv" at
http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application
That describes how to connect gdb to the process ("gdb -p PID") and dump a
Python stack trace ("pystack"). All that you need to do is create a .gdbinit
file with the contents given here -
http://svn.python.org/projects/python/trunk/Misc/gdbinit
With a stack trace it was easy to see the error in my code - and it was a
tight loop, and it depended explicitly on the time of day, which is why I had
not seen it before. :o)
http://www.penglixun.com/tech/database/mysql_parameter_tuning.html
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明
网址: http://www.penglixun.com/tech/database/mysql_parameter_tuning.html
含义:用于索引块的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写)。
影响:对于MyISAM表的影响不是很大,MyISAM会使用系统的缓存来存储数据,所以大量使用MyISAM表的机器内存很快就会耗尽。但是,如果你将该值设得过大(例如,大于总内存的50%),系统将转换为页并变得极慢。MySQL依赖操作系统来执行数据读取时的文件系统缓存,因此你必须为文件系统缓存留一些空间。
建议:先设置为内存的25%,观察性能变化。
含义:为所有线程打开表的数量。
影响:增加该值能增加mysqld要求的文件描述符的数量。可以避免频繁的打开数据表产生的开销。打开一个表的开销可能很大,因为MyISAM会把MYI文件的文件头标识为正在使用,所以在内存中做这个操作比较好。,因为每个线程都需要打开表,连接数越大这个值要越大。
建议:我们有300多个表的话,大约2048差不多了。
含义:缓存可重用的线程数。
影响:这个参数设置线程的缓存,线程的创建和销毁的开销可能很大,因为每个线程的连接/断开都需要。如果应用程序中有大量的跳跃并发连接并且线程较多的话,就要加大它的值。它的目的是在通常的操作中无需创建新线程。
建议:通常至少设置为16。
含义:指定MySQL查询结果缓冲区的大小。
影响:如果应用程序有大量读,而且没有应用程序级别的缓存,那么这很有用。不过不要设置太大,因为维护它也需要不少开销,这会导致MySQL变慢。
建议:通常设置为 32-512Mb。设置完之后最好是跟踪一段时间,查看是否运行良好。在一定的负载压力下,如果缓存命中率太低了,就启用它,如果命中率已经不错了,就可以把他调小一点。对于2G的内存,先从16M开始,一倍一倍的增加,直到命中率比较稳定为止。
含义:缓存单条SQL的结果集上限。默认4KB。
影响:当一条SQL返回的结果集大于这个限制的时候,将不被MySQL缓存。
建议:设置为1M即可。
含义:缓存为每个数据集存放的最小内存大小,默认4KB。
影响:如果太小的话,将会导致MySQL经常访问内存块去获取信息,如果设置太大则浪费内存。
建议:如果SQL返回的结果集都很小的话,参数也可以调小一点,避免内存浪费。如果结果集大部分都大于4KB的话,则考虑加大参数。
含义:在MySQL的连接请求等待队列中允许存放的最大连接请求数。系统默认值为50。
影响:如果系统在一个短时间内有很多连接,则需要增大该参数的值,该参数值指定到来的TCP/IP连接的侦听队列的大小。不同的操作系统在这个队列大小上有它自 己的限制。试图设定back_log高于你的操作系统的限制将是无效的。
建议:对于Linux系统推荐设置为小于512的整数。
含义:为每个需要进行排序的线程分配该大小的一个缓冲区。
影响:增加这值加速ORDER BY或GROUP BY操作。不过该参数对应的分配内存是每连接独占的,如果有100个连接,那么实际分配的总共排序缓冲区大小为100×sort_buffer_size。
建议:一般设置为2M观察变化再调整。
含义:顺序查询操作所能使用的缓冲区大小。
影响:和sort_buffer_size一样,该参数对应的分配内存也是每连接独享。
建议:一般设置为2M再观察变化。
read_rnd_buffer_size
含义:随机查询操作所能使用的缓冲区大小。
影响:每个线程独享。
建议:一般设置为2M再观察变化。
含义:查询缓冲类型。
影响:为1是使用缓冲,2是除非使用SQL_CACHE才进行缓冲。对于缓冲而言,数据并不是实时的,有一定的延时。但是对于实时性要求不高的查询短时间内多次执行,是不划算的,这个时候就需要缓存。并且缓存中是区分空格和大小写的,如果大小写不一致和空格不一致,也会认为是不同的SQL,不会利用到缓存。虽然不设置查询缓冲,有时可能带来性能上的损失,但有一些SQL语句需要实时地查询数据,或并不经常使用(可能一天就执行一两次),这样就需要把缓冲关了,可以采用临时关闭的方法SELECT SQL_NO_CACHE。
建议:一般设置为1。
MyISAM表发生变化时重新排序所需的缓冲。一般64M足矣。
对InnoDB的效率影响很大。因为InnoDB会把尽可能多的数据和索引缓存在缓冲区,这个类似与Oracle的Buffer Pool:如果只采用InnoDB,可以把这个参数调大一点,大约内存的70%左右。
当然,如果数据量不会暴增并且不是特别大,这个参数还是不要太大了,浪费空间。
对数据库性能影响不是很大,至少内存足够的机器上不会有什么影响。
在高写入负载尤其是数据集很大的时候,这个值非常重要,值越高性能越好,不过可能会增加数据恢复的时候。我设置为128M。
默认的设置在中等强度的写入负载及短事物处理时,性能还可以。但是存在大量更新操作或者负载较大时,就要慢慢增加这个参数的值了。不过不要设置太大,会浪费内存。它每秒都会刷新一次,所以不用设置超过1s所需的内存空间,16M足够了。
这个参数对InnoDB及其重要,设置不好的话会比MyISAM慢1000倍!默认是1,这就是说每次更新事务都会被提交到磁盘,这是非常消耗资源的,硬盘和内存的速度是明显数量级的差距。
设置为0是最快的,但是很不安全,全部在缓存中,一掉电全没了。
设置为1很不好,每次都去写硬盘,没有必要。
设置为2是比较好的,日志不刷新到磁盘上,只刷新到操作系统缓存上。然后每秒钟写缓存。相对于现在数据库每秒4K条左右的SQL,性能已经可以提高不少。
版本:V3.0 2013-6-29 (江南白衣版权所有,转载请保留出处)
非常非常的快,有测评说比Memcached还快(当大家都是单CPU的时候),而且是无短板的快,读写都一般的快,所有API都差不多快,也没有MySQL Cluster、MongoDB那样更新同一条记录如Counter时慢下去的毛病。
丰富的数据结构,超越了一般的Key-Value数据库而被认为是一个数据结构服务器。组合各种结构,限制Redis用途的是你自己的想象力,作者自己捉刀写的用途入门
因为是个人作品,Redis目前只有2.3万行代码,Keep it simple的死硬做法,使得普通公司而不需淘宝那个级别的文艺公司也可以吃透它。
Redis宣言就是作者的自白,我最喜欢其中的“代码像首诗”,”设计是一场与复杂性的战斗“,“Coding是一件艰苦的事情,唯一的办法是享受它。如果它已不能带来快乐就停止它。为了防止这一天的出现,我们要尽量避免把Redis往乏味的路上带。”
让人又爱又恨的单线程架构,使得代码不用处理平时最让人头痛的并发而大幅简化,但也带来CPU的瓶颈,而且单线程被慢操作所阻塞时,其他请求的延时变得不确定。
那Redis不是什么?
最普通的key-value类型,说是String,其实是任意的byte[],比如图片,最大512M。 所有常用命令的复杂度都是O(1),普通的Get/Set方法,可以用来做Cache,存Session,为了简化架构甚至可以替换掉Memcached。
Incr/IncrBy/IncrByFloat/Decr/DecrBy,可以用来做计数器,做自增序列。key不存在时会创建并贴心的设原值为0。IncrByFloat专门针对float,没有对应的decrByFloat版本?用负数啊。
SetNx, 仅当key不存在时才Set。可以用来选举Master或做分布式锁:所有Client不断尝试使用SetNx master myName抢注Master,成功的那位不断使用Expire刷新它的过期时间。如果Master倒掉了key就会失效,剩下的节点又会发生新一轮抢夺。
其他Set指令:
GetBit/SetBit/BitOp,与或非/BitCount, BitMap的玩法,比如统计今天的独立访问用户数时,每个注册用户都有一个offset,他今天进来的话就把他那个位设为1,用BitCount就可以得出今天的总人数。
Append/SetRange/GetRange/StrLen,对文本进行扩展、替换、截取和求长度,只对特定数据格式如字段定长的有用,json就没什么用。
Key-HashMap结构,相比String类型将这整个对象持久化成JSON格式,Hash将对象的各个属性存入Map里,可以只读取/更新对象的某些属性。这样有些属性超长就让它一边呆着不动,另外不同的模块可以只更新自己关心的属性而不会互相并发覆盖冲突。
另一个用法是土法建索引。比如User对象,除了id有时还要按name来查询。可以有如下的数据记录:
底层实现是hash table,一般操作复杂度是O(1),要同时操作多个field时就是O(N),N是field的数量。
List是一个双向链表,支持双向的Pop/Push,江湖规矩一般从左端Push,右端Pop——LPush/RPop,而且还有Blocking的版本BLPop/BRPop,客户端可以阻塞在那直到有消息到来,所有操作都是O(1)的好孩子,可以当Message Queue来用。当多个Client并发阻塞等待,有消息入列时谁先被阻塞谁先被服务。任务队列系统Resque是其典型应用。
还有RPopLPush/ BRPopLPush,弹出来返回给client的同时,把自己又推入另一个list,LLen获取列表的长度。
还有按值进行的操作:LRem(按值删除元素)、LInsert(插在某个值的元素的前后),复杂度是O(N),N是List长度,因为List的值不唯一,所以要遍历全部元素,而Set只要O(log(N))。
按下标进行的操作:下标从0开始,队列从左到右算,下标为负数时则从右到左。
复杂度也是O(N),其中LSet的N是List长度,LIndex的N是下标的值,LRange的N是start的值+列出元素的个数,因为是链表而不是数组,所以按下标访问其实要遍历链表,除非下标正好是队头和队尾。LTrim的N是移除元素的个数。
在消息队列中,并没有JMS的ack机制,如果消费者把job给Pop走了又没处理完就死机了怎么办?
Set就是Set,可以将重复的元素随便放入而Set会自动去重,底层实现也是hash table。
有序集,元素放入集合时还要提供该元素的分数。
Sorted Set的实现是hash table(element->score, 用于实现ZScore及判断element是否在集合内),和skip list(score->element,按score排序)的混合体。 skip list有点像平衡二叉树那样,不同范围的score被分成一层一层,每层是一个按score排序的链表。
ZAdd/ZRem是O(log(N)),ZRangeByScore/ZRemRangeByScore是O(log(N)+M),N是Set大小,M是结果/操作元素的个数。可见,原本可能很大的N被很关键的Log了一下,1000万大小的Set,复杂度也只是几十不到。当然,如果一次命中很多元素M很大那谁也没办法了。
用Multi(Start Transaction)、Exec(Commit)、Discard(Rollback)实现。 在事务提交前,不会执行任何指令,只会把它们存到一个队列里,不影响其他客户端的操作。在事务提交时,批量执行所有指令。《Redis设计与实现》中的详述。
注意,Redis里的事务,与我们平时的事务概念很不一样:
Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行。
Redis2.6内置的Lua Script支持,可以在Redis的Server端一次过运行大量逻辑,就像存储过程一样,避免了海量中间数据在网路上的传输。
-- KEYS: [1]job:sleeping, [2]job:ready
-- ARGS: [1]currentTime
-- Comments: result is the job id
local jobs=redis.call('zrangebyscore', KEYS[1], '-inf', ARGV[1])
local count = table.maxn(jobs)
if count>0 then
-- Comments: remove from Sleeping Job sorted set
redis.call('zremrangebyscore', KEYS[1], '-inf', ARGV[1])
-- Comments: add to the Ready Job list
-- Comments: can optimize to use lpush id1,id2,... for better performance
for i=1,count do
redis.call('lpush', KEYS[2], jobs[i])
end
end
官方文档 与 《Redis设计与实现》中的详述,过期数据的清除从来不容易,为每一条key设置一个timer,到点立刻删除的消耗太大,每秒遍历所有数据消耗也大,Redis使用了一种相对务实的做法:
当client主动访问key会先对key进行超时判断,过时的key会立刻删除。
如果clien永远都不再get那条key呢? 它会在Master的后台,每秒10次的执行如下操作: 随机选取100个key校验是否过期,如果有25个以上的key过期了,立刻额外随机选取下100个key(不计算在10次之内)。可见,如果过期的key不多,它最多每秒回收200条左右,如果有超过25%的key过期了,它就会做得更多,但只要key不被主动get,它占用的内存什么时候最终被清理掉只有天知道。
redis-benchmark -t SET -c 100 -n 10000000 -r 10000000 -d 256
Redis-Cluster是今年工作重点,支持automatic re-sharding, 采用和Hazelcast类似的算法,总共有N个分区(eg.N=1024),每台Server负责若干个分区。
高可用性关乎系统出错时到底会丢失多少数据,多久不能服务。要综合考虑持久化,Master-Slave复制及Fail-Over配置,以及具体Crash情形,比如Master死了,但Slave没死。或者只是Redis死了,操作系统没死等等。
综上所述,RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。
如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值,比如之前的benchmark每个小时会产生40G大小的AOF文件,如果硬盘能撑到半夜系统闲时才用cron调度bgaofrewrite就好了。
如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构,见Tim的博客
现象描述:当AOF rewrite 15G大小的内存时,Redis整个死掉的样子,所有指令甚至包括slave发到master的ping,redis-cli info都不能被执行。
原因分析:
解决方法:
最后发现,原来是AOF rewrite时一直埋头的调用write(2),由系统自己去触发sync。在RedHat Enterprise 6里,默认配置vm.dirty_background_ratio=10,也就是占用了10%的可用内存才会开始后台flush,而我的服务器有64G内存。很明显一次flush太多数据会造成阻塞,所以最后果断设置了sysctl vm.dirty_bytes=33554432(32M),问题解决。
然后提了个issue,AOF rewrite时定时也执行一下fdatasync嘛, antirez三分钟后就回复了,新版中,AOF rewrite时32M就会重写主动调用fdatasync。
有时候明明master/slave都活得好好的,突然间就说要重新进行全同步了:
1.Slave显示:# MASTER time out: no data nor PING received...
slave会每隔repl-ping-slave-period(默认10秒)ping一次master,如果超过repl-timeout(默认60秒)都没有收到响应,就会认为Master挂了。如果Master明明没挂但被阻塞住了也会报这个错。可以适当调大repl-timeout。
2.Master显示:# Client addr=10.175.162.123:44670 flags=S oll=104654 omem=2147487792 events=rw cmd=sync scheduled to be closed ASAP for overcoming of output buffer limits.
当slave没挂但被阻塞住了,比如正在loading Master发过来的RDB, Master的指令不能立刻发送给slave,就会放在output buffer中(见oll是命令数量,omem是大小),在配置文件中有如下配置:client-output-buffer-limit slave 256mb 64mb 60, 这是说负责发数据给slave的client,如果buffer超过256m或者连续60秒超过64m,就会被立刻强行关闭!!! Traffic大的话一定要设大一点。否则就会出现一个很悲剧的循环,Master传输一个大的RDB给Slave,Slave努力的装载,但还没装载完,Master对client的缓存满了,再来一次。
平时可以在master执行 redis-cli client list 找那个cmd=sync,flag=S的client,注意OMem的变化。
Redis-sentinel是2.6版开始加入的另一组独立运行的节点,提供自动Fail Over的支持。
master地址在sentinel.conf里, sentinel会每10秒一次向master发送INFO,知道master的slave有哪些。 如果master已经变为slave,sentinel会分析INFO的应答指向新的master。以前,sentinel重启时,如果master已经切换过了,但sentinel.conf里master的地址并没有变,很可能有悲剧发生。另外master重启后如果没有切换成slave,也可能有悲剧发生。新版好像修复了一点这个问题,待研究。
另外,sentinel会在master上建一个pub/sub channel,名为"sentinel:hello",通告各种信息,sentinel们也是通过接收pub/sub channel上的+sentinel的信息发现彼此,因为每台sentinel每5秒会发送一次自己的host信息,宣告自己的存在。
觉得Sentinel至少有两个可提升的地方:
基于Sentinel的方案,client需要执行语句SENTINEL get-master-addr-by-name mymaster 可获得当前master的地址。
Jedis正在集成sentinel,已经支持了sentinel的一些指令,但还没发布,但sentinel版的连接池则暂时完全没有,在公司的项目里我参考网友的项目自己写了一个。
淘宝的Tedis driver,使用了完全不同的思路,不基于Sentinel,而是多写随机读, 一开始就同步写入到所有节点,读的话随便读一个还活着的节点就行了。但有些节点成功有些节点失败如何处理? 节点死掉重新起来后怎么重新同步?什么时候可以重新Ready? 所以不是很敢用。
另外如Ruby写的redis_failover,也是抛开了Redis Sentinel,基于ZooKeeper的临时方案。
Redis作者也在博客里抱怨怎么没有人做Dynamo-style 的client。
约30个配置项,全都有默认配置,对redif.conf默认配置的修改见附录1。
综述: Redis监控技巧
Info指令将返回非常丰富的信息。 着重监控检查内存使用,是否已接近上限,used_memory是Redis申请的内存,used_memory_rss是操作系统分配给Redis的物理内存,两者之间隔着碎片,隔着Swap。 还有重点监控 AOF与RDB文件的保存情况,以及master-slave的关系。Statistic 信息还包括key命中率,所有命令的执行次数,所有client连接数量等, CONFIG RESETSTAT 可重置为0。
Monitor指令可以显示Server收到的所有指令,主要用于debug,影响性能,生产环境慎用。
SlowLog 检查慢操作(见2.性能)。
官网列出了如下工具,但暂时没发现会直接拿来用的:
各个Driver好像只有Jedis比较活跃,但也5个月没提交了,也是Java里唯一的Redis官方推荐。
Spring Data Redis的封装并不太必要,因为Jedis已足够简单,没有像Spring Data MongoDB对MongoDB java driver的封装那样大幅简化代码,顶多就是加强了一点点点pipeline和transaction状态下的coding,禁止了一些此状态下不能用的命令。而所谓屏蔽各种底层driver的差异并不太吸引人,因为我就没打算选其他几种driver。有兴趣的可以翻翻它的JedisConnection代码。
所以,SpringSide直接在Jedis的基础上,按Spring的风格封装了一个JedisTemplate,负责从池中获取与归还Jedis实例,处理异常。
Jedis基于Apache Commons Pool做的连接池,默认最大连接数只有8,必须自行重新设置。
Jedis的blocking pop函数,应用执行ExecutorService.shutdownNow()中断线程时并不能把它中断,见讨论组。两个解决方法:
Windows版本方便对应用的本地开发调试,但Redis并没有提供,好在微软提供了一个依赖LibUV实现兼容的补丁,https://github.com/MSOpenTech/redis,但redis作者拒绝合并到master中,微软只好苦憋的时时人工同步。 目前的稳定版是2.6版本,支持Lua脚本。
因为github现在已经没有Download服务了,所以编译好的可执行文件藏在这里:
注:下文中的链接都是网站的架构描述文档。
Twitter和新浪微博, 都属于将Redis各种数据结构用得出神入化的那种,如何发布大V如奥巴马的消息是它们最头痛的问题。
Tumblr: 11亿美刀卖给Yahoo的图片日志网站,22 台Redis server,每台运行8 - 32个实例,总共100多个Redis实例在跑。有着Redis has been completely problem free and the community is great的崇高评价。Redis在里面扮演了八爪鱼多面手的角色:
Instagram ,曾经,Redis powers their main feed, activity feed, sessions system, and other services。但可惜目前已迁往Cassandra,说新架构只需1/4的硬件费用,是的,就是那个导致Digg CTO辞职的Canssandra。
Flickr , 依然是asynchronous task system and rudimentary queueing system。之前Task system放在mysql innodb,根本,撑不住。
The Others:
之前是因为看到这篇文章:终极Shell——Zsh 才选择使用zsh,被它的自动完成、补全功能吸引了。
官网:www.zsh.org
这也是“工欲善其事,必先利其器"系列文章。
oh-my-zsh是基于zsh的功能做了一个扩展,方便的插件管理、主题自定义,以及漂亮的自动完成效果。
在Github上找关于zsh的项目时发现的,试用了一下觉得很方便,不用像上面文章里面提到的那么复杂,配置一些插件的名称即可使用相应的功能。
官网:https://github.com/robbyrussell/oh-my-zsh
评价:https://github.com/robbyrussell/oh-my-zsh/wiki/Testimonials
截图欣赏(Git插件):
再来一个自动完成:
定义hash快速进入目录:
在~/.zshrc中定义:
hash -d blog="/home/henryyan/work/blog/henryyan.github.com"
进入Github的oh-my-zsh主页 https://github.com/robbyrussell/oh-my-zsh ,在下面有详细的安装方式。
在 https://github.com/robbyrussell/oh-my-zsh/wiki/themes 里面有很多主题可以选择,安装后只需要修改~/.zshrc的ZSH_THEME为文件夹的名称即可。
刚刚的几个截图的主题是我基于robbyrussell修改的,添加了当前登录用户的名称和主机名称。
但是oh-my-zsh的作者太懒了,我在Github上Fork了项目然后提交我修改后的主题一直也没有合并,如果喜欢的话可以直接Clone我的oh-my-zsh分支,然后使用手动安装的方式安装oh-my-zsh;
手动安装完以后可以把当前的PATH变量设置到~/.zshrc中:
echo "export PATH=$PATH" >> ~/.zshrc source ~/.zshrc
修改主题:
vi ~/.zshrc修改ZSH_THEME为kafeitu,
source ~/.zshrc
如果提供的主题没有一个如意的(我就没有看中一个),你可以参考别人主题截图:https://github.com/robbyrussell/oh-my-zsh/wiki/themes 然后看一下对应的~/.oh-my-zsh/themes/foo 的源码,然后根据自己的需要自定义,最后再修改一下~/.zshrc的ZSH_THEME配置就可以了。
在~/.oh-my-zsh/plugins/里面有很多插件可以选择启动,默认已经启用git插件,如果你像我一样是一个开发人员(Java),我的插件启用如下:
plugins=(ant mvn svn git)
工欲善其事,必先利其器,享受zsh带给你的快捷吧。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.