# 2. 如何保证pipeline的顺序到达

## 乱序现在怎么搞

你背书也背过, ok从HTTP1.1开始我们支持了KeepAlive, 允许你复用TCP连接, 然后又允许你搞Pipelining. 我们可以把好多条消息一并发出去了. 这种玩法实际上到处都是(TCP的滑动窗口/Redis-Pipeline), 听起来不错

设想一个问题, 如果真的有这么神的玩法, 为什么1.0的时候你不这么玩? 我就可以搞3个TCP连接, 一人发一个包, 我也能实现pipeline, 为什么你一定坚持要在同一个TCP连接上这么玩? 回顾一下这个玩法的过程: ok, 假设我们按照顺序一次push出去了1/2/3三个包, 但1号包却是最后到的, 现在怎么搞?

如果是TCP, 好办, 我有ACK序号, 重传快回传怎么搞都行. 如果是HTTP呢? 如果你使用同一个TCP链接, 那你还是可以依赖底层的ACK序号实现重组. 但如果你使用了三个TCP链接呢? 抱歉没辙, 现在绝对没办法知道这三者的顺序了, 自然也不可能实现重组了

## 必须给我按序响应

现在我能保证: 你按照什么顺序发, 对方就能按照什么顺序收到. 但如果你发的顺序就是乱的, 对方收到的一定也是乱的, 换句话说你如果发的231, 对方就一定收到231, 你如果发123, 对方就一定收到123

而按照pipeline的要求, 必须是我按照什么顺序发给你, 你就应该按照什么顺序响应我. 因此在上面的例子中, 我在pipeline里拿到了三个请求并起了三个协程处理, 但如果23好了, 1因为某些原因没好, 延迟了, 我们也不能先响应23. 像这种三个消息构成一个队列, 队头卡住了, 我们叫它 head-of-line blocking问题

## 那怎么办呢?

仅仅因为1不能发, 从而搞的23也不能发, 说到底还是因为HTTP没有序号搞的, 如果消息都有序号了, 我们也能先发23, 最后发1, 到了那边对方重排一下完事了, HTTP2就搞出了一个序号的概念:

1. 一个TCP链接划分成好几个"stream"
2. 把一个请求/一个响应叫做"消息"
3. 一个消息拆成好几个"帧", 每个帧都有自己的序号

如果帧有序号, 这样消息也就有序号了, 说明对端就可以靠这个序号重新排序了, 这种情况下, 就算先收到23, 最后收到1, 我们也能靠消息序号实现重排了
