天天看点

浅谈数据容灾系统中带宽、延迟、并发流、效率等(摘自《大话存储2》)

本文节选自即将出版的《大话存储2》的第17.9一节,出版社保留版权信息。先发出来让大家先睹为快。同时欢迎提出错误和建议,谢谢!

17.9 带宽、延迟及其影响

        100Mb/s,这个速率意味着什么呢?有人说,每秒可以传输10MB的数据(8/10b 编码下)。通常情况下,这种说法是对的。但是如果发送方与接收方之间的距离变得很远,比如数百公里甚至一千公里,那么这种说法,你会发现根本不成立。我们现在就来分析一下。

        大家知道,光或者电信号的传输是有固定速度的,即近似每秒30万公里(其实远未达到,光在光缆中的传播速率只有20万公里每秒,电信号在电缆中的传播速率则近似21万公里每秒。基本上是光在真空或者空气中速率的三分之二)。如果两点之间距离为1000公里,那么信号传一个来回(传到对端,然后对端给以ACK应答)所耗费的时间就是1000÷300000×2≈6.6ms。什么概念呢?也就是你想把1bit的数据传输到一千公里之外的地方,那么至少你要耗费6.6ms。那么传输10bit、100bit、1Kb、100Mb,需要多长时间呢?首先想到的是,至少比传1bit要慢。到底需要多长时间?来看这个公式:传输来回时间=(数据量÷链路速率×2)+(传输距离÷光速×2)。数据在传输的时候,是首先会被通过编码电路将数据串行化编码然后放到电路或者光路上传输,这个编码速率,就是链路带宽,100Mb/s的带宽与1000Mb/s的带宽,区别就在于后者在单位时间内可以编码相当于前者10倍量的数据,但是不管链路带宽有多少,数据被编码之后,数据在电路上的传输所耗费的时间对各种速率的链路来讲都是一样的,因为传输的时候已经与链路编码速率(带宽)无关了,传输到对方之后,对方还需要解码(所以编码所耗费的时间也要乘以2),同样也是取决于链路带宽。

        所以,当两点之间传输距离很近的时候,比如1千米,那么传输时延≈0.0066ms,基本上可以忽略了。所以那个公式变为:传输时间=(数据量÷链路速率)。所以说,链路速率越大,只代表其编码速度越快,而不代表传输速度越快,传输速度是固定的,都是光速。再打个比喻,有一辆长途车,50个人排队上车,排队上车需要120s,汽车行驶需要60000s,50个人排队下车需要120s。50个人被排队送上车,就好比数据被串行编码放到电路上传输,汽车行驶相当于电路信号从一端传递到另一端,50个人被排队下车,就好比对端的解码过程了,然而到此还没有结束,当汽车抵达目的地之后,司机必须在返回出发点进行报信,这就好比TCP协议在收到数据之后发送给源端的ACK应答一样。可以司机空着车跑回去报信(单独发送ACK应答包),也可以在目的端捎带着一些回程客人返回去报信(TCP可以在反向流量中夹带ACK应答信息以提高效率)。但是在容灾系统中,数据总是从源端流向目的端的,或者在灾难回切的时候从目的端流向源端的,总之只有一个方向有实体数据流动,那么此时回程ACK都是独立的ACK应答包(独立ACK包很小所以其编解码所耗费的时间也忽略掉即可)。

        另外,一辆汽车能承载的人数是有限的,也就是说,得一趟一趟的拉,这就好比TCP每次所发送的最大数据长度,也就是TCP的滑动窗口长度,TCP得分批把用户数据传送出去,每次的发送量必须小于TCP滑动窗口的长度,每次传输之后均需要对方发送一个ACK(这里不考虑ACK合并等特殊情况)。每批数据虽然到了底层可能被切分,比如TCP的MSS(Max Segment Size)切片,一般等于底层链路的MTU,底层链路再用MTU的值来切片,但是这些底层的切片在被传输到对端之后,并不需要对端底层协议的应答,只有对端的TCP在完整的收到TCP发送的一批数据之后,才会应答。

        那么我们来算算在相隔1000千米的两点之间,每秒到底能够传送多少个来回:1000ms÷6.6ms=151个来回。如果按照TCP的典型滑动窗口即16KB来计算的话(每次发送16KB数据然后就等待应答,不考虑延迟应答或者合并应答等特殊情况),那么每秒吞吐量仅为151×16KB=2416KB,也就是2.4MB每秒。夸张么?

当然,上述算式是忽略了编解码所耗费的时间以及整个链路上各种中继、转发或者协议转换设备所带来的处理延迟,如果算上这两者,则吞吐量会更低。更加准确的实际数据传输吞吐量计算公式为V=TCP Window Size÷2(TCP Window Size÷链路带宽+距离÷光速+链路设备处理延迟)。总之,距离越远,实际传输吞吐量就越低,在实际应用中一定要有底。

当距离很短时,可以忽略距离带来的延迟,此时显然谁带宽高谁传的就快;而距离很长时,此时带宽再高也无济于事,因为大头都被距离给耗掉了。另外,即便是底层链路的带宽相同,距离也相同的情况下,使用不同的协议进行传输,所带来的延迟也是不同的。但是设想一下,不管链路跨越了多长的距离,如果这条链路上永远都有数据在传着,那么发送方与接收方就可以以链路带宽的原生速率来收发信息,只不过有时延,就像卫星电视那样,此时传输速率并不会打折,如果做到这一点,那么对于一个容灾系统来讲是非常好的事情,充其量只会丢失几毫秒之内的数据。但是,事实却并非如此。超远距离传输,怕的就是数据流的卡壳,卡一次两次不要紧,频繁卡壳,那就根本无法利用起链路带宽了。这就好比磁盘寻道操作一样,本来磁头能以很高的速度读写盘片上的数据,但是没办法,必须换道,这一换道,外部速率骤降。碰巧的是,15K转每秒的SAS盘其平均寻道时间为5.5ms,而一千公里距离的传输时延为6.6ms,这两个值倒是接近而且还挺有意思。

传输协议无法避免“卡壳”,因为总要传一段歇一段来等待对方吱个声,看看收到没有。比如TCP,这样就平白无故的浪费了底层链路时隙;再加上长距离下的高传输延迟,一来一回更浪费了大量时间,所以会出现上文中的即便是千兆链路下,1000公里的距离每秒也只能传输2.4MB的理论值,实际值将会更低了。

另外,如果在长距离下使用诸如iSCSI等协议的话,那将更是一笔惊人的浪费。大家知道SCSI层本身就有传输保障机制,人家自己有ACK那一套,而底层TCP再来这一套显然就显得多此一举了。按理说有了SCSI层的传输保障机制,其下层协议栈就应该是个无状态的类似链路层协议了,应该直接将数据一股脑传过去,但是现实是它非得传一段,停一段,等待对方说个OK,然后再传再停,慢慢腾腾;不仅如此,再加上SCSI也要传传停停,那就是变本加厉。所以长距离上跑诸如FCP、iSCSI等这种SCSI协议与FC/TCPIP协议的合体协议,将会是个梦魇。

降低不必要的ACK数量,增加滑动窗口,这些都是广域网加速的技术,对传输速率会有一定程度的提高。但是最终解决办法,还是要尽量缩短两地距离,或者开发专用优化的协议了。