长连接和负载均衡都是服务器端常用的技术,但是它们碰在一起的时候麻烦就出现了。下面以google的kubernetes举例,说它的一个美妙的假设为什么不工作。
kubernetes是一个管理docker集群的东西。部署在kubernetes上的每个服务(service)由一个或多个pod组成。每个pod都有一个独立的IP。kubernetes希望利用IP层的负载均衡技术,让每个服务都对应一个独立的IP。这样,当pod发生迁移或者伸缩的时候,对使用它的人是不可见的。我想说的是,这样做是有问题的。
假设服务S由podA和podB两个pod组成。客户端使用了固定大小的连接池,到服务S有100个连接。然后突然,podB死掉了。于是对客户端来说,连接池的数量就降低到了50。由于50个连接不够用,所以很快,客户端就向podA新建了50个连接,把总连接数量补到了100。然后podB恢复了。但是对于客户端来说,因为100个连接已经够用了,所以podB收不到任何请求。
简单的结论是:假如一个服务由多个副本组成,并且客户端使用了长连接,那么客户端必须知晓副本的数量,否则服务端负载就会不均衡。假如连接本身是无状态的(例如HTTP),那么可以加入一个中间代理来解决负载均衡的问题,从而降低client端的复杂度。
所以就kubernetes来说,无论你是用flannel、skydns,还是其它什么策略。只要存在长连接,客户端就必须主动去查kubernetes API来获知pods的真实IP。这个耦合及依赖是必须存在的。