同Pod内Python连接Cassandra超时但cqlsh正常问题排查
问题:Pod内Python连接Cassandra超时但同环境cqlsh可正常连接
问题描述
在Kubernetes Pod环境中使用Python测试Cassandra数据库连接,测试代码如下:
host = '<hostname>' port_num = 9092 default_fetch_size = 5000 idle_heartbeat_interval = 30 idle_heartbeat_timeout = 30 connect_timeout = 10 executor_threads = 2 protocol_version = 4 db_keyspace = 'fraud' auth_provider = PlainTextAuthProvider(username=username, password=password) cluster = Cluster([host], port=port_num, auth_provider=auth_provider, idle_heartbeat_interval=idle_heartbeat_interval, idle_heartbeat_timeout=idle_heartbeat_timeout, connect_timeout=connect_timeout, protocol_version=protocol_version, executor_threads=executor_threads) session = cluster.connect()
运行代码时抛出如下异常:
Traceback (most recent call last): File "run.py", line 3, in <module> CassProvider().test_cassandra() File "/app/tmp_cassandra_connection.py", line 59, in test_cassandra cassandra_connector = CassandraDbConnector().get_session() File "/usr/local/lib/python3.6/site-packages/project/src/objects/type_objects.py", line 11, in __call__ cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) File "/app/tmp_cassandra_connection.py", line 41, in __init__ session = cluster.connect() File "cassandra/cluster.py", line 1664, in cassandra.cluster.Cluster.connect File "cassandra/cluster.py", line 1700, in cassandra.cluster.Cluster.connect File "cassandra/cluster.py", line 1687, in cassandra.cluster.Cluster.connect File "cassandra/cluster.py", line 3485, in cassandra.cluster.ControlConnection.connect File "cassandra/cluster.py", line 3530, in cassandra.cluster.ControlConnection._reconnect_internal cassandra.cluster.NoHostAvailable: ('Unable to connect to any servers', {'<ip>:9092': OSError(None, "Tried connecting to [('<ip>', 9092)]. Last error: timed out")
异常提示无法连接到任何服务端,连接<ip>:9092超时。但在同一个Pod内通过bash进入终端,使用完全相同的主机地址、端口、用户名、密码执行cqlsh命令,却可以正常连接Cassandra。
问题原因与排查解决步骤
最高频诱因:端口配置错误
90%以上同类问题都是这个原因:Cassandra DataStax Python驱动默认使用原生传输协议,对应默认端口是9042,而9092是旧版Thrift API的默认端口。大部分发行版自带的cqlsh会自动读取服务端配置探测可用端口、或自动适配协议,不会严格校验传入端口是否为原生端口,因此会出现cqlsh能连通但Python驱动连接超时的现象。
按优先级排查修复
- 第一步先确认端口正确性
在Pod终端执行以下命令验证:
如果9042端口连通、9092超时,直接把代码中# 查看cqlsh实际建立连接使用的端口 cqlsh <hostname> -u <username> -p <password> -e "show host" # 分别探测两个常见端口的连通性 nc -zv <hostname> 9042 nc -zv <hostname> 9092port_num的值改为9042即可解决问题。 - 第二步校验域名解析结果一致性
部分配置了sidecar代理、进程级DNS注入的环境中,Python进程和bash进程的域名解析结果可能不一致。在Python测试代码中加入以下打印,和bash中nslookup <hostname>的返回结果做对比:
如果两边解析出的IP不一致,直接在代码中填入cqlsh能连通的固定IP即可绕过解析问题。import socket print(socket.getaddrinfo(host, port_num)) - 第三步检查SSL配置差异
如果Cassandra集群强制开启SSL,cqlsh会自动读取~/.cassandra/cqlshrc中的SSL配置完成握手,但Python驱动默认不启用SSL,会导致连接阶段一直等待握手响应最终超时。可以在Cluster初始化时加入SSL配置验证:from ssl import SSLContext, PROTOCOL_TLSv1_2 ssl_context = SSLContext(PROTOCOL_TLSv1_2) # 测试环境可临时关闭证书校验,生产环境请替换为实际CA配置 ssl_context.check_hostname = False ssl_context.verify_mode = 0 cluster = Cluster( [host], port=port_num, auth_provider=auth_provider, ssl_context=ssl_context, idle_heartbeat_interval=idle_heartbeat_interval, idle_heartbeat_timeout=idle_heartbeat_timeout, connect_timeout=connect_timeout, protocol_version=protocol_version, executor_threads=executor_threads ) - 第四步调整超时阈值
跨可用区、跨VPC部署的场景下10秒连接超时可能过短,可以先把connect_timeout调整为30秒,排除网络延迟导致的超时。
内容的提问来源于stack exchange,提问作者Ema Il
相关产品推荐
相关产品推荐

