Throughput, Bandwidth, Latency
Latency是一个动作所花费的时间,我们做一个操作,比如:copy一个1G大小的文件,花了10秒,我们说Latency=10秒
Latency要注意的几点:
### 不同角度Latency不同
比如,我们一个Redis Client客户端,给Redis服务器发送了一个Ping命令,我们发送时开始计算时间,等Redis返回一个Pong回应,我们按下秒表,看当前的时间。这两个时间的差值,就是这个动作的时延Latency。
如果是局域网内(通用网络,一般是千兆网或万兆网,注意:它是以bit为单位的),一般是200微妙(us)左右,于是,站在Redis Client角度,这个Latency等于200us。
但是,站在Redis服务器角度,它从开始看到这个Ping数据包,开始计时,然后写一个Pong字符串到操作系统的网络层(实际就是内存buffer),就算完成了(应该掐表了)。所以,Server角度,它的时间只消耗在内存操作。这个时间有多少,没有人测试过。但我有一个经验数据,请参考下文
单线程就比多线程性能差吗?不一定
假设慢的可能,是Server从主存Main Memoory,读一个数据,然后再向主存Main Memory写一个数据,总计就是200ns。但实际上,会比这少很多,因为读写时,数据很可能已经在CPU cache中,如果是L1 Cache,那么只要不到2ns。
但不管如何计算,上面的时间,都远小于客户端Redis Client所看到的200us,即至少有一千倍,甚至十万倍的差距。
那么时间花在哪里去了?
这个客户端和服务器之间的时间差异,被消耗在网络上了。就是数据包通过操作系统的TCP/IP系统栈,走网卡,再经过网络介质(比如铜缆或光缆、Hub或Switch),到达客户端的TCP/IP栈,后达到客户端的应用层,而且是一来一回,即Round Trip。
所以,记住:
时延是站在某个掐表计时的实体的角度,不同角度(或不同实体),得到的时间不同,即使是对于同一个动作
另外,站在Redis Client角度,它的时延Latency至少有两部分组成,一个是网络上消耗的时间,一个是Server实际内存操作的时间,但由上面的分析可以看出,大头是网络上的部分,所以,我们为简化分析,对于客户端程序的角度而言,经常将占主要时间的部分,当做整个动作的时延。
即对于上面这个例子:Redis Client的Ping命令处理的Latency = 网络Round Trip时延
### 时延不是定值,而是随机值,我们需要用概率来描述它
如果每次包消耗都是一模一样的200us,那就是好事。但如果你多测试几次,你会发现时延是不确定的,有时快,有时慢。
这是因为,在实际工作环境里,有很多因素影响这个时延。以上面这个为例,因为通信需要通过网络设备,比如一个Switch,但Switch不可能只为你这一个通信服务,它还需要服务其他客户,因此,有时,Switch就会忙些(甚至有时会打个小盹,比如计时器的影响),让时间或多或少有点变化。
但对于一个稳定的系统,一般而言,计算时间发送变化,但如果测试次数足够多,从统计角度看,它是一个比较稳定的值。
于是,我们用概率去描述这个统计稳定值,一般用P99, P50, Avarage这些指标来描述。P99就是99%的时间,低于当前这个值。Average,就是所有的次数的时间总和除于次数。
这样,我们才能用一个稳定的值作为标识,来替代并不稳定的单次Latency计时。
## 吞吐能力:Throughput
### Throughput和Latency的关系
什么是Throughput?Throughput,是我们做很多动作,同时,我们计算一段时间(比如:1秒)里完成的动作数。
以上面为例,我们发送一个Ping,返回一个Pong,作为一个动作。然后我们不停发送(但必须等到Pong回来后,才发下一个),然后我们计算1秒内,我们能够处理这样的动作有多少个。
数学好的同学,很快能算出,假设Average Latency = 200us,且很稳定的话,那么Throughput = 1秒/200us = 5000 op/秒。即Throughput是5K。
同样地,你会发现,Throughput也受上面的两个因素影响。
首先,这个Throughput是有角度的,这里的5K,是对于Redis Client客户端而言。而对于服务器,如果它能全速处理,假设每次都从L1 Cache操作数据,它的Throughput是 1秒/2ns,即0.5G(5亿次)。为什么服务器实际没有做到5亿的Throughput,是因为Redis Client发送的太慢,所以对于服务器而言,它大部分时间都在睡觉,只用自己能力的很小一部分来处理Ping命令。
同时,Throughtput也需要用统计概率来描述,幸运的是,我们用一段很长的时间,比如秒,来描述Throughput,所以,从统计角度,它一般是个稳定值。(记住:在计算机世界里,1秒是个相当长的时间)
那么,Throughput是否能简单地由Latency得来?
不可以。
因为存在并发。
我们假设有2个Redis Client同时向Server发送,我们会发现,它们的Latency不变。站在两个Redis Client一起的角度,我们认为Throughput增加了一倍,即10K。但如果看Latency,并没有变化,还是200us。
为什么?
因为服务器和网络设备,都能力足够强大,来一个请求,和两个请求一起到,它处理的时间都足够快,所以,并发并不降低服务器端的能力(因为服务器1秒可以处理5亿个Ping请求,两个并发的Redis Client合在一起,每秒也只能送上总和10K的请求),但包在网络上传递的时间(实际是服务器网络层和网络设备的故意等待时间),基本上就是200us。
所以,我们可以得到下面两个结论:
1. 对于并发,我们不能通过Latency简单换算成Throughput
2. 如果只有单客户单顺序执行(即得到个结果,才能发送第二个,否则就是并发),而且服务器处理的时间成本忽略不计,那么可以用Latecny换算成Throughput,而且是占在客户端角度
那我们能不能用 并发数 * 单个客户端的Throughput,来得到多个客户端的Throughput?
也不可以。
这是因为,如果并发的客户端形成的数据包,总数还比较小,那么上面的公式是成立的。当并发数足够大,这时,网络的数据量加大,服务器端就不能保证每个包的Round Trip都是200us,而是要更多时间(即单个客户端角度看,Latency加大了)。
所以,实际工作中,你需要做真正的测试,用不同的并发数,来测试整个系统的Throughput。有的并发数,是Throughput线性增长,即加大一倍的客户端,整个Throughput也加大一倍。有的并发数,则不能满足这个线性规律。甚至有时增大了并发数,整个Throughput还会降低(比如:某个数值触发了系统里某个部件的瓶颈)
### Throughput还有Pattern的差异
如果我们看一个磁盘,它的Throughput应该是每秒读出Read或写入Write的字节数。
有一个软件fio,可以很好地测试Throughput。但是,如果你给fio不同的参数,你会惊奇地发现,Throughput差别非常大。
我以一个例子来说明,你可以用下面的命令来进行测试。
我这里测试的是磁盘Write,为了保证数据数据落盘(即不丢失数据),每次请求完,都要fsync。
下面是每写一个block size为4K(--bs=4k),就fsync一次
fio --name=w --rw=write --ioengine=sync --direct= --fsync=1 --end_fsync=1 --size=200M --bs=4k;
相关文章