aiohttp.ClientSession 和 ClusterIp 没有负载平衡

aiohttp.ClientSession and ClusterIp not load balancing

我的 Kubernetes PODs 就像 a(pod_num=1) -> b (pod_num=2)。我在A创建一个session = aiohttp.ClientSession连接服务B,使用CluterIp服务地址(比如http://b-svc:80)。当我尝试为 B 添加 2 pods 时,会话似乎不知道新添加的两个 pods 并且没有请求来到新添加的两个 pods.

aiohttp 有一个 TCPConnector。默认情况下它有 10 秒的 dns 缓存超时。我试过减少或者等了很久,发现新加的pods.

没有访问日志

如果我总是创建一个新的session来发送请求,请求就会来到新添加的pods(但是aiohttp团队不建议,涉及到连接池没有被使用)

我期望的是

Requests automatically route [according to certain load balance rules which predefined by k8s] to the newly added pods when I reuse the client session.

更具体地说,A issue 的客户请求如下:

import asyncio
import aiohttp
import time

url = "http://b-svc:80/v1/hello"

async def main():
    session = aiohttp.ClientSession()
    for _ in range(100):
        async with session.get(url) as response:
            resp = await response.json()
            print(resp)
        time.sleep(2) # In order to make the cache invalid after 10s

if __name__ == "__main__":
    asyncio.run(main())

服务器 B 仅 returns 一个 json 响应并记录每个请求。

{
    "answer": "world"
}

起初,B 在 ClusterIp 地址后面只有一个 pod(假设它的 pod 索引 = 0)。当我增加 ClusterIp 地址后面的 pods 的数量时(比方说,添加 pods with index = 1, 2, 3),只有之前创建的第一个 pod(index = 0)可以接收请求[访问日志只出现在 pod 0,不会出现在其他 1、2、3。]。似乎会话没有向其他 pods.

发送请求

这个问题,作者对k8s处理持久连接的方式提出了质疑

并且从回答和优秀的文章Load balancing and scaling long-lived connections in Kubernetes,我们知道k8s不能很好的分发持久连接。在我的例子中,默认情况下保持活动状态是打开的。所以这些是持久连接。如果没有建立新的 tcp 连接,则不会发生新的分配。所以新添加的pods将不会收到请求。

在客户端禁用保持活动将解决问题。

aiohttp.ClientSession(connector=aiohttp.TCPConnector(force_close=True))

Github 问题: