如何通过DataStax Python驱动连接Docker-Compose创建的Cassandra集群
解决Docker部署Cassandra集群后Python驱动无法连接所有节点的问题
问题场景
我通过以下docker-compose.yaml部署了双节点Cassandra集群:
version: "3.3" networks: cassandra: volumes: cassandra_seed_data: cassandra_node_data: services: cassandra-seed: image: cassandra:3.11 restart: "no" logging: options: max-size: "5m" max-file: "3" container_name: cassandra-seed networks: - cassandra expose: - "7000" ports: - target: 9042 published: 9042 protocol: tcp mode: host volumes: - cassandra_seed_data:/var/lib/cassandra environment: CASSANDRA_BROADCAST_ADDRESS: "cassandra-seed" CASSANDRA_NUM_TOKENS: 4 CASSANDRA_START_RPC: true cassandra-node: image: cassandra:3.11 restart: "no" logging: options: max-size: "5m" max-file: "1" container_name: cassandra-node hostname: cassandra-node networks: - cassandra expose: - "7000" ports: - target: 9042 published: 9043 protocol: tcp mode: host volumes: - cassandra_node_data:/var/lib/cassandra environment: CASSANDRA_SEEDS: "cassandra-seed" CASSANDRA_LISTEN_ADDRESS: cassandra-node CASSANDRA_BROADCAST_ADDRESS: cassandra-node CASSANDRA_START_RPC: true # CASSANDRA_ENDPOINT_SNITCH: SimpleSnitch CASSANDRA_NUM_TOKENS: 4 # CASSANDRA_CLUSTER_NAME: cluster # CASSANDRA_DC: dc # HEAP_NEWSIZE: 32M # MAX_HEAP_SIZE: 4M
集群运行状态正常,通过以下命令验证:
docker exec cassandra-seed nodetool status
输出:
Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 192.168.96.2 71.27 KiB 4 100.0% ce5de211-63be-44c7-8f3c-bf0a18270a40 rack1 UN 192.168.96.3 71.41 KiB 4 100.0% a6eae6e9-be77-4c34-ad0b-12333d2630a7 rack1
docker-compose ps输出:
docker-compose ps NAME COMMAND SERVICE STATUS PORTS cassandra-node "docker-entrypoint.s…" cassandra-node running 7000-7001/tcp, 7199/tcp, 9160/tcp, 0.0.0.0:9043->9042/tcp cassandra-seed "docker-entrypoint.s…" cassandra-seed running 7000-7001/tcp, 7199/tcp, 9160/tcp, 0.0.0.0:9042->9042/tcp
使用DataStax Python驱动连接时,仅配置了初始联系点0.0.0.0:9042,代码如下:
from cassandra.cluster import Cluster cluster = Cluster(**{'contact_points': ['0.0.0.0'], 'port': 9042, 'compression': 'lz4', 'protocol_version': 4}) cluster.connect(wait_for_all_pools=True)
但出现超时报错:
INFO:cassandra.policies:Using datacenter 'datacenter1' for DCAwareRoundRobinPolicy (via host '0.0.0.0:9042'); if incorrect, please specify a local_dc to the constructor, or limit contact points to local cluster nodes INFO:cassandra.cluster:New Cassandra host <Host: 192.168.96.3:9042 datacenter1> discovered WARNING:cassandra.cluster:Failed to create connection pool for new host 192.168.96.3:9042: Traceback (most recent call last): File "cassandra/cluster.py", line 3175, in cassandra.cluster.Session.add_or_renew_pool.run_add_or_renew_pool File "cassandra/pool.py", line 402, in cassandra.pool.HostConnection.__init__ File "cassandra/cluster.py", line 1620, in cassandra.cluster.Cluster.connection_factory File "cassandra/connection.py", line 831, in cassandra.connection.Connection.factory File "/Users/ekotsal/miniconda3/envs/cbd3/lib/python3.9/site-packages/cassandra/io/libevreactor.py", line 267, in __init__ self._connect_socket() File "cassandra/connection.py", line 898, in cassandra.connection.Connection._connect_socket OSError: [Errno None] Tried connecting to [('192.168.96.3', 9042)]. Last error: timed out WARNING:cassandra.cluster:Host 192.168.96.3:9042 has been marked down
docker-compose日志无异常,需解决该问题。
问题根源
Python驱动通过初始联系点(seed节点)发现了第二个节点的内部Docker地址192.168.96.3:9042,但这个地址是容器专属的网络地址,外部主机无法直接访问。而第二个节点对外暴露的端口是9043,但Cassandra节点广播的是内部端口9042,导致驱动尝试访问不可达的地址和端口,最终超时。
核心问题在于cassandra-node的CASSANDRA_BROADCAST_ADDRESS配置为容器内部主机名,广播的地址和端口对外部主机无效。
解决方案
1. 修改docker-compose配置
更新两个Cassandra服务的环境变量,让它们广播外部主机可访问的地址和端口:
- 将
CASSANDRA_BROADCAST_ADDRESS设置为主机的实际IP地址(例如192.168.1.100,不要用0.0.0.0,避免潜在问题) - 给
cassandra-node添加CASSANDRA_BROADCAST_RPC_PORT,值为对外暴露的9043
修改后的关键配置片段:
services: cassandra-seed: # ... 其他配置保持不变 environment: CASSANDRA_BROADCAST_ADDRESS: "你的主机IP" CASSANDRA_BROADCAST_RPC_ADDRESS: "你的主机IP" CASSANDRA_NUM_TOKENS: 4 CASSANDRA_START_RPC: true cassandra-node: # ... 其他配置保持不变 environment: CASSANDRA_SEEDS: "cassandra-seed" CASSANDRA_LISTEN_ADDRESS: cassandra-node CASSANDRA_BROADCAST_ADDRESS: "你的主机IP" CASSANDRA_BROADCAST_RPC_PORT: 9043 CASSANDRA_START_RPC: true CASSANDRA_NUM_TOKENS: 4
2. 重启集群
执行命令清理旧容器和数据卷,重新启动集群:
docker-compose down -v docker-compose up -d
3. 调整Python连接代码
只需将主机IP作为联系点,驱动会自动获取正确的节点广播地址和端口:
from cassandra.cluster import Cluster # 使用主机IP作为初始联系点 cluster = Cluster(contact_points=['你的主机IP'], port=9042, compression='lz4', protocol_version=4) session = cluster.connect(wait_for_all_pools=True) # 验证连接状态 print("集群连接成功,节点信息:") for host in cluster.metadata.all_hosts(): print(f"- {host.address}:{host.native_transport_port} (状态: {host.status})")
验证步骤
- 重启后执行
docker exec cassandra-seed nodetool status,确认两个节点状态均为UN(正常运行) - 运行修改后的Python代码,控制台应输出两个节点的信息,无超时报错
内容的提问来源于stack exchange,提问作者Kots
相关产品推荐
相关产品推荐

