一个具体的case 就是 当我们迁移 一个超大流量的pool writer, 架构从 consumer -HLB -> writer 到consumer -> SLB->writer.
- consumer 是event 收集系统, 调用下游到writer 来存储数据。
- writer 是event 存储 数据。
在不同的数据中心,有三对consumer /writer ,因此我们需要迁移三次才能够完成。每一对上下游的流量都非常大,第一对的流量想对小, consumer 的流量是10B/day, 也就意味writer 也是10B/day。 其他的两对其他的都达到20B/day
由于流量过大,导致在迁移过程中遇到了很多网络问题。
由于下游有420 个机器,我们觉得在流量迁移过程中。由于有latency 的出现,我们需要下游有更大的容量。根据以往的经验,加到了一倍。
Pool 1.
流量先从小的开始迁移。我们先迁移第一对。在迁移过程中,上游出现了大量的 error, 这个错误是明显的端口全部被用我的情况。
ConnectException: Cannot assign requested address (connect failed)&st=java.net.ConnectException: Cannot assign requested address (connect failed)\n\tat java.net.PlainSocketImpl.socketConnect(Native Method)\n\tat
我们看了一下用户的配置,他的jvm 参数disable 了keepAlive,-Dhttp.keepAlive=false
当时我们觉得不应该disable keepAlive 的参数,联系用户改正。但是用户的反馈说,keepAlive disable 是特意这么设定。以前是打开的,但是打开之后上游consumer 会出现 event lag 的情况。
也就是如果keepAlive ,会导致event 不出去。 这种情况下,我们分析,是下游的writer 现有的pool 容量不够,在keepAlive 的情况下,没有这么大的数据处理能力。如果disable 了keepAlive,那么由于每次都要新建立链接,consumer 的发送的速度放缓,下游现有的容量就能够支持了。
那么方案有两个
- 是增加现有的下游容量,enable keepAlive
- 由于迁移流量的新pool 上已经提供了足够的容量能力,可以用动现有的下游和保持keepAlive=false。增加consumer 的port。
从迁移的角度说增加port 方案更加合理,再加上新的pool 是k8云原生的,可以通过调整k8s secure context 来实现, k8s config
改动之后。这次迁移就很平稳,顺利成功。
Pool 2:
在pool1 点迁移成功后,我们觉得迁移第二个pool 很有信心。 在和用户商量增了consumer 2 的port range 之后开始了,迁移。不幸的是,这次还是出现了ConnectException: Cannot assign requested address
之类的错误。 这说明增加了port 有时候不够用。最严重的是,再迁移完成后,出现了明显的event 积压现象,而且event 积压一直在增长,完全下降不下来。奇怪的是,当然我们rollback 回原来的pool 上的时候,event 积压很快就消失了。
在这个情况下我们就很奇怪,新pool 的指标上来看,容量比以前大一倍,进来request 处理速度也和以前差不多。 cpu / memory 使用情况其实是比以前有好转的。从上游consumer 的情况看,也没有明显的error, 从cpu 和memory 情况看,也没有明显的增加。 那么为什么会增加这么多
从tcp 抓包情况看,有很多connection error
在所有的AZ 的都出现了tcp 包重传的情况。
在tcp 抓包过程中,可以看到 大概有20k TIME_WAIT connections ,但是流量回到老pool ,只有很少的TIME_WAIT connection。 这就解释了为什么回到老pool 就没有event 堆积的情况。
**Let’s see the packet capture for HLB and SLB.
SLB:
packet #26 client send http request with “Connection: close”
packet #37 server sent http response with “Connection: close”
packet #39 client sent TCP FIN to close the connection.
packet #40 server sent TCP FIN. Then client’s TCP state will enter TIME_WAIT.
HLB:
packet #11 client sent http request with “Connection: close”
packet #108 send sent http response with “Connection: close”. At the same time, this packet closes the TCP connection by setting the TCP FIN flag.
由于client 端disable keepAlive, 因此对每个request 都会发出“Connection: close”。针对“Connection: close”,slb 和hlb 行为是不同的。slb 是由不会主动结束链接,需要client 端主动结束。 由于tcp 四次握手,client 端要等到2msl TIME_WAIT。 而HLB 会主动结束链接,HLB来等待2 msl TIME_WAIT。 这也就解释了为什么回到hlb ,connection error 就很少的原因。
在pool 2 的情况下,增加port 看来也不能解决过大流量的问题。 因此就需要client 端enable keepAlive,来减少新链接的产生。同时增加下游的容量。
在改动后。 流量迁移成功