diff --git a/README.rst b/README.rst index 18eca53bc..7bceeb4f3 100644 --- a/README.rst +++ b/README.rst @@ -188,170 +188,15 @@ Recommended Steps to Run OpenGauss with Python GaussDB Driver Testing (Assuming Steps to Run OpenGauss(SSL) with Python GaussDB Driver Testing (Assuming Docker is Installed):: - # Create certificate directory - mkdir -p /opengauss8889/certs - cd /opengauss8889/certs - - # Generate CA certificate - openssl genrsa -out ca.key 4096 - openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \ - -subj "/C=CN/ST=OpenGauss/L=OpenGauss/O=MyOrg/OU=DB/CN=OpenGaussCA" \ - -out ca.crt - - # Generate server certificate - openssl genrsa -out server.key 2048 - openssl req -new -key server.key \ - -subj "/C=CN/ST=OpenGauss/L=OpenGauss/O=MyOrg/OU=DB/CN=opengauss.local" \ - -out server.csr - - # SAN config (replace IP/DNS with the address you will use to connect, - # for example 127.0.0.1 or the host IP) - cat > san.cnf < /opengauss8889/conf/postgresql.conf < /opengauss8889/conf/postgresql.conf </dev/null || echo omm) - - # Set proper permissions for the key files and change ownership to the data directory owner - chown "$OWNER":"$OWNER" /var/lib/opengauss/certs/* - chmod 600 /var/lib/opengauss/certs/* - - # Verify the files - ls -l /var/lib/opengauss/certs - - # Exit the container - exit - - # Restart the container to apply changes - docker restart opengauss-cp - - # ReEnter the container - docker exec -it opengauss-cp bash - - # Switch to the default OpenGauss database user "omm" - su - omm - - # Connect to the OpenGauss database using the gsql client - gsql -d postgres -p 5432 -U omm - - -- Create a new database named "test" with Default compatibility with Oracle enabled - CREATE DATABASE test; - - # Set the Python import path to include your local GaussDB Python project # Replace your_path with actual values export PYTHONPATH=/your_path/gaussdb-python @@ -363,9 +208,15 @@ Steps to Run OpenGauss(SSL) with Python GaussDB Driver Testing (Assuming Docker export GAUSSDB_TEST_DSN="dbname=test user=root password=Password@123 host=127.0.0.1 port=8889 sslmode=require" export GAUSSDB_TEST_DSN="dbname=test user=root password=Password@123 host=127.0.0.1 port=8889 sslmode=verify-ca sslrootcert=/opengauss8889/certs/ca.crt sslcert=/opengauss8889/certs/client.crt sslkey=/opengauss8889/certs/client.key" + # Run demonstration code + export SSL_ROOT_CERT="/opengauss8889/certs/ca.crt" + python example/ssl_demo.py + # Run all tests using pytest, showing verbose output and test durations pytest --durations=0 -s -v +For more usage examples, please refer to the README.md in the /example directory. + The library includes some pre-commit hooks to check that the code is valid according to the project coding convention. Please make sure to install them by running:: diff --git a/example/GaussDB_distributed_readme.md b/example/GaussDB_distributed_readme.md new file mode 100644 index 000000000..64e908e0b --- /dev/null +++ b/example/GaussDB_distributed_readme.md @@ -0,0 +1,527 @@ +# GaussDB负载均衡使用示例 + +## 分布式场景 + +## 一套分布式集群 + +集群信息如下: + +![集群信息](imgs/101.png) + +请求均衡分布在各个CN节点。 + +运行程序 + +```bash +export DSN="dbname=postgres user=root password=YourPasswd host=192.168.0.86,192.168.0.99,192.168.0.23 port=8000,8000,8000" +python cluster_ha_showcase.py "$DSN" +``` + +**运行结果** + +```bash +=== 容灾场景测试 === +2025-09-13 11:45:54,582 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-13 11:45:54,591 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +容灾测试通过: 连接到节点 192.168.0.86:8000,角色: coordinator,模式: distributed + +=== 容灾场景测试(模拟主节点故障) === +2025-09-13 11:45:54,626 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:54,633 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +容灾测试通过: 连接到节点 192.168.0.99:8000,角色: coordinator,模式: distributed + +=== 负载均衡场景测试 === +2025-09-13 11:45:54,666 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:54,674 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:54,674 - INFO - 检查节点 192.168.0.86:8000,角色: coordinator,模式: distributed +2025-09-13 11:45:54,707 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +写操作成功: 主节点 192.168.0.86:8000,角色: coordinator + +=== 测试 disable 模式 === +2025-09-13 11:45:55,848 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-13 11:45:55,853 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:55,857 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:55,900 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-13 11:45:55,905 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:55,908 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:55,940 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:55,945 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:55,948 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:55,980 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:55,984 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:55,987 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,018 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,022 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,026 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,057 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,062 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,065 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,095 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,099 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,102 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,134 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,138 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,141 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,174 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,178 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,181 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,213 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,217 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,220 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,251 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,255 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,258 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,290 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,294 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,297 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,327 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,331 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,334 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,365 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,369 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,372 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,404 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,408 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,411 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,442 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,446 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,449 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,479 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,483 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,485 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,516 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,520 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,523 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,553 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,557 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,559 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,590 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,594 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,597 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +负载均衡测试通过 (disable 模式): 连接顺序符合预期 ['192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86'] + +=== 测试 random 模式 === +2025-09-13 11:45:56,628 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,633 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,636 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,668 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,672 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +2025-09-13 11:45:56,677 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.99:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,712 - INFO - 连接成功: host=192.168.0.23 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,717 - WARNING - 未找到匹配的 node_host: 192.168.0.23,返回 coordinator +2025-09-13 11:45:56,723 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.23:8000,角色: coordinator,数据: test write +2025-09-13 11:45:56,757 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,761 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 11:45:56,764 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +负载均衡测试通过 (random 模式): 随机连接,包含多个节点 ['192.168.0.86', '192.168.0.99', '192.168.0.23', '192.168.0.86'] +2025-09-13 11:45:56,795 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 + +=== 自动寻主场景测试 === +2025-09-13 11:45:56,865 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-13 11:45:56,873 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +自动寻主测试通过: 连接到协调节点 192.168.0.86:8000,角色: coordinator + +=== 自动寻主场景测试(模拟主节点故障) === +2025-09-13 11:45:56,908 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 11:45:56,915 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +自动寻主测试通过: 连接到协调节点 192.168.0.99:8000,角色: coordinator +``` + + +## 两套套分布式集群做容灾 + +创建两个分布式版实例,示例集群在同一VPC的同一子网,如果在不同VPC,需要打通网络。主实例与灾备实例的副本一致性协议、引擎内核版本需要一致。 + +![实例](imgs/102.png) + +在“实例管理->对应实例基本信息->网络信息->子网”获取子网信息。 + +![子网](imgs/103.png) + +登录主实例,单击“实例管理->对应实例基本信息->配置信息->容灾IP->重置配置”,并相互配置对端实例子网段信息。 + +![alt text](imgs/104.png) + +![alt text](imgs/105.png) + +登录灾备实例,单击“实例管理->对应实例基本信息->配置信息->容灾IP->重置配置”,并相互配置对端实例子网段信息。 + + +获取灾备实例的容灾IP +192.168.0.171 + + +在页面左上角单击,选择“数据库 > 云数据库 GaussDB”,进入云数据库 GaussDB信息页面。 + +单击左侧导航栏的“容灾管理”,在页面右上方单击“创建容灾任务”。 + +![alt text](imgs/106.png) + +单击“确定”开始搭建容灾关系,可在“容灾管理”页面查看任务状态。 + +![alt text](imgs/107.png) + +当出现 RPO: 0 s RTO: 0 s,说明容灾任务OK,继续下面的示例操作。 + + +### 主集群和备集群正常 + +运行程序 + +```bash +export DSN="dbname=postgres user=root password=YourPasswd host=192.168.0.86,192.168.0.99,192.168.0.23,192.168.0.249,192.168.0.35,192.168.0.163 port=8000,8000,8000,8000,8000,8000" +python cluster_ha_showcase.py "$DSN" +``` + +**运行结果** + +```bash +=== 容灾场景测试 === +2025-09-13 12:16:42,033 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:42,042 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +容灾测试通过: 连接到节点 192.168.0.86:8000,角色: coordinator,模式: distributed + +=== 容灾场景测试(模拟主节点故障) === +2025-09-13 12:16:42,074 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:42,081 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +容灾测试通过: 连接到节点 192.168.0.99:8000,角色: coordinator,模式: distributed + +=== 负载均衡场景测试 === +2025-09-13 12:16:42,112 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:42,120 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:42,120 - INFO - 检查节点 192.168.0.86:8000,角色: coordinator,模式: distributed +2025-09-13 12:16:42,152 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +写操作成功: 主节点 192.168.0.86:8000,角色: coordinator + +=== 测试 disable 模式 === +2025-09-13 12:16:43,262 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,266 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,270 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,301 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,306 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,308 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,340 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,344 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,347 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,378 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,383 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,385 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,418 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,422 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,426 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,456 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,460 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,462 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,494 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,499 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,502 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,533 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,538 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,541 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,573 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,578 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,581 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,615 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,620 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,623 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,658 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,662 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,665 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,697 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,702 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,704 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,735 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,740 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,742 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,774 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,779 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,781 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,813 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,817 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,820 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,853 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,858 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,861 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,893 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,898 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,901 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,934 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,938 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,941 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:43,976 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:43,981 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:43,984 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:44,015 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,019 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:44,022 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +负载均衡测试通过 (disable 模式): 连接顺序符合预期 ['192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86'] + +=== 测试 random 模式 === +2025-09-13 12:16:44,054 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,059 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:44,062 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:44,099 - INFO - 连接成功: host=192.168.0.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-13 12:16:44,104 - WARNING - 未找到匹配的 node_host: 192.168.0.35,返回 coordinator +2025-09-13 12:16:44,107 - ERROR - 读操作失败 (192.168.0.35:8000): relation "test_table" does not exist +LINE 1: SELECT data FROM test_table WHERE id = 1 + ^ +2025-09-13 12:16:44,136 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,140 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:16:44,143 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:16:44,177 - INFO - 连接成功: host=192.168.0.249 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,182 - WARNING - 未找到匹配的 node_host: 192.168.0.249,返回 coordinator +2025-09-13 12:16:44,186 - ERROR - 读操作失败 (192.168.0.249:8000): relation "test_table" does not exist +LINE 1: SELECT data FROM test_table WHERE id = 1 + ^ +2025-09-13 12:16:44,217 - INFO - 连接成功: host=192.168.0.163 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,222 - WARNING - 未找到匹配的 node_host: 192.168.0.163,返回 coordinator +2025-09-13 12:16:44,225 - ERROR - 读操作失败 (192.168.0.163:8000): relation "test_table" does not exist +LINE 1: SELECT data FROM test_table WHERE id = 1 + ^ +2025-09-13 12:16:44,256 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,261 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +2025-09-13 12:16:44,266 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.99:8000,角色: coordinator,数据: test write +2025-09-13 12:16:44,298 - INFO - 连接成功: host=192.168.0.23 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,303 - WARNING - 未找到匹配的 node_host: 192.168.0.23,返回 coordinator +2025-09-13 12:16:44,309 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.23:8000,角色: coordinator,数据: test write +负载均衡测试通过 (random 模式): 随机连接,包含多个节点 ['192.168.0.86', '192.168.0.86', '192.168.0.99', '192.168.0.23'] +警告: 未连接到所有节点,缺失节点: ['192.168.0.249', '192.168.0.35', '192.168.0.163'] +警告: 以下节点不可用: ['192.168.0.35:8000', '192.168.0.249:8000', '192.168.0.163:8000'] +2025-09-13 12:16:44,342 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 + +=== 自动寻主场景测试 === +2025-09-13 12:16:44,405 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,414 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +自动寻主测试通过: 连接到协调节点 192.168.0.86:8000,角色: coordinator + +=== 自动寻主场景测试(模拟主节点故障) === +2025-09-13 12:16:44,446 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:16:44,454 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +自动寻主测试通过: 连接到协调节点 192.168.0.99:8000,角色: coordinator +``` + + +### 主集群故障和备集群升主 + +单击左侧导航栏的“容灾管理”,在灾备任务的“操作”列单击“容灾升主”。 +选择“是否支持回切”。 + +![alt text](imgs/108.png) + +选择支持回切,系统将会保存容灾关系记录,升主后支持一键回切容灾关系。 + +如果不选择将会直接断开容灾关系,无法一键回切。 + +在弹出的确认框中确认无误后,勾选“确认进行容灾升主”单击“确定”,下发容灾升主操作。 + +![alt text](imgs/109.png) + +任务下发后,容灾状态为“已升主”。 + +![alt text](imgs/110.png) + +运行程序 + +```bash +export DSN="dbname=postgres user=root password=YourPasswd host=192.168.0.86,192.168.0.99,192.168.0.23,192.168.0.249,192.168.0.35,192.168.0.163 port=8000,8000,8000,8000,8000,8000" +python cluster_ha_showcase.py "$DSN" +``` + +**运行结果** + +```bash +=== 容灾场景测试 === +2025-09-13 12:22:15,050 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:15,058 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +容灾测试通过: 连接到节点 192.168.0.86:8000,角色: coordinator,模式: distributed + +=== 容灾场景测试(模拟主节点故障) === +2025-09-13 12:22:15,092 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:15,100 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +容灾测试通过: 连接到节点 192.168.0.99:8000,角色: coordinator,模式: distributed + +=== 负载均衡场景测试 === +2025-09-13 12:22:15,130 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:15,137 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:15,137 - INFO - 检查节点 192.168.0.86:8000,角色: coordinator,模式: distributed +2025-09-13 12:22:15,168 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +写操作成功: 主节点 192.168.0.86:8000,角色: coordinator + +=== 测试 disable 模式 === +2025-09-13 12:22:16,281 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,286 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,291 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,323 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,327 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,329 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,361 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,366 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,369 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,401 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,406 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,408 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,439 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,444 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,446 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,478 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,482 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,484 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,515 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,519 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,521 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,553 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,557 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,560 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,592 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,597 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,600 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,632 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,637 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,639 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,671 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,676 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,679 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,710 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,714 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,716 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,747 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,751 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,754 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,785 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,790 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,793 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,824 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,828 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,830 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,861 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,865 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,868 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,899 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,904 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,906 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,936 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,940 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,942 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:16,973 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:16,977 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:16,979 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:17,010 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,014 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:17,017 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +负载均衡测试通过 (disable 模式): 连接顺序符合预期 ['192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86', '192.168.0.86'] + +=== 测试 random 模式 === +2025-09-13 12:22:17,047 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,050 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:17,053 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:17,083 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,087 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +2025-09-13 12:22:17,090 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.86:8000,角色: coordinator,数据: test write +2025-09-13 12:22:17,121 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,126 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +2025-09-13 12:22:17,132 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.99:8000,角色: coordinator,数据: test write +2025-09-13 12:22:17,164 - INFO - 连接成功: host=192.168.0.163 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,168 - WARNING - 未找到匹配的 node_host: 192.168.0.163,返回 coordinator +2025-09-13 12:22:17,171 - ERROR - 读操作失败 (192.168.0.163:8000): relation "test_table" does not exist +LINE 1: SELECT data FROM test_table WHERE id = 1 + ^ +2025-09-13 12:22:17,214 - INFO - 连接成功: host=192.168.0.249 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-13 12:22:17,218 - WARNING - 未找到匹配的 node_host: 192.168.0.249,返回 coordinator +2025-09-13 12:22:17,221 - ERROR - 读操作失败 (192.168.0.249:8000): relation "test_table" does not exist +LINE 1: SELECT data FROM test_table WHERE id = 1 + ^ +2025-09-13 12:22:17,253 - INFO - 连接成功: host=192.168.0.23 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,258 - WARNING - 未找到匹配的 node_host: 192.168.0.23,返回 coordinator +2025-09-13 12:22:17,264 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.0.23:8000,角色: coordinator,数据: test write +2025-09-13 12:22:17,307 - INFO - 连接成功: host=192.168.0.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-13 12:22:17,312 - WARNING - 未找到匹配的 node_host: 192.168.0.35,返回 coordinator +2025-09-13 12:22:17,315 - ERROR - 读操作失败 (192.168.0.35:8000): relation "test_table" does not exist +LINE 1: SELECT data FROM test_table WHERE id = 1 + ^ +负载均衡测试通过 (random 模式): 随机连接,包含多个节点 ['192.168.0.86', '192.168.0.86', '192.168.0.99', '192.168.0.23'] +警告: 未连接到所有节点,缺失节点: ['192.168.0.249', '192.168.0.35', '192.168.0.163'] +警告: 以下节点不可用: ['192.168.0.163:8000', '192.168.0.249:8000', '192.168.0.35:8000'] +2025-09-13 12:22:17,345 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 + +=== 自动寻主场景测试 === +2025-09-13 12:22:17,409 - INFO - 连接成功: host=192.168.0.86 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,417 - WARNING - 未找到匹配的 node_host: 192.168.0.86,返回 coordinator +自动寻主测试通过: 连接到协调节点 192.168.0.86:8000,角色: coordinator + +=== 自动寻主场景测试(模拟主节点故障) === +2025-09-13 12:22:17,449 - INFO - 连接成功: host=192.168.0.99 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-13 12:22:17,456 - WARNING - 未找到匹配的 node_host: 192.168.0.99,返回 coordinator +自动寻主测试通过: 连接到协调节点 192.168.0.99:8000,角色: coordinator +``` diff --git a/example/GaussDB_master_standby_readme.md b/example/GaussDB_master_standby_readme.md new file mode 100644 index 000000000..5406c0db3 --- /dev/null +++ b/example/GaussDB_master_standby_readme.md @@ -0,0 +1,613 @@ +# GaussDB负载均衡使用示例 + +## 集中式场景 + +## 一套主备集群 + +集群信息如下: + +![集群信息](imgs/001.png) + + +### 主备切换前 + +默认连接到主节点上,192.168.2.154 + +运行程序 + +```bash +export DSN="dbname=postgres user=root password=YourPassword host=192.168.2.154,192.168.2.35,192.168.2.113 port=8000,8000,8000" +python cluster_ha_showcase.py "$DSN" +``` + +**运行结果** + +```bash +=== 容灾场景测试 === +2025-09-09 15:09:30,258 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +容灾测试通过: 连接到主节点 192.168.2.154:8000,角色: Primary,模式: master-standby + +=== 容灾场景测试(模拟主节点故障) === +2025-09-09 15:09:30,299 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,304 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: master-standby,继续查找主节点 +2025-09-09 15:09:30,333 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,338 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: master-standby,继续查找主节点 +容灾测试失败: 无法连接到任何主节点或有效节点 + +=== 负载均衡场景测试 === +2025-09-09 15:09:30,365 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,370 - INFO - 检查节点 192.168.2.154:8000,角色: Primary,模式: master-standby +2025-09-09 15:09:30,397 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +写操作成功: 连接到主节点 192.168.2.154:8000,角色: Primary + +=== 测试 disable 模式 === +2025-09-09 15:09:30,453 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,459 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,486 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,491 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,519 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,524 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,551 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,557 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,584 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,589 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,616 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,621 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,648 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,652 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,679 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,684 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,711 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,716 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,743 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,748 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,775 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,779 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,807 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,812 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,839 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,845 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,871 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,876 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,903 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,908 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,936 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,941 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,967 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:30,972 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:30,999 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,004 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:31,031 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,036 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:31,063 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,067 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +负载均衡测试通过 (disable 模式): 连接顺序符合预期 ['192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154'] + +=== 测试 random 模式 === +2025-09-09 15:09:31,094 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.02 秒 +2025-09-09 15:09:31,099 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:31,125 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,130 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:09:31,158 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,164 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.113:8000,角色: Standby,数据: test write +2025-09-09 15:09:31,192 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,197 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Standby,数据: test write +负载均衡测试通过 (random 模式): 随机连接,包含多个节点 ['192.168.2.154', '192.168.2.154', '192.168.2.113', '192.168.2.35'] +2025-09-09 15:09:31,225 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 + +=== 自动寻主场景测试 === +2025-09-09 15:09:31,261 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +自动寻主测试通过: 连接到主节点 192.168.2.154:8000,角色: Primary + +=== 自动寻主场景测试(模拟主节点故障) === +2025-09-09 15:09:31,293 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,298 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:09:31,324 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:31,329 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:09:31,331 - INFO - 第 1/3 次尝试未找到主节点,等待 5 秒后重试 +2025-09-09 15:09:36,370 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:36,375 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:09:36,403 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:36,408 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:09:36,409 - INFO - 第 2/3 次尝试未找到主节点,等待 5 秒后重试 +2025-09-09 15:09:41,444 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:41,449 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:09:41,478 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:09:41,483 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: master-standby,继续查找 +自动寻主测试失败: 尝试的节点 ['192.168.2.35:8000 (Standby)', '192.168.2.113:8000 (Standby)', '192.168.2.35:8000 (Standby)', '192.168.2.113:8000 (Standby)', '192.168.2.35:8000 (Standby)', '192.168.2.113:8000 (Standby)'],未找到主节点或协调节点 +``` + +### 主备切换后 + + + +点击DN主备倒换 + +![主备倒换1](imgs/002.png) + +![主备倒换2](imgs/003.png) + +切换后: + +![主备倒换3](imgs/004.png) + +主降备后,能够自动切换到新的主节点上: 192.168.2.35。 + +运行程序 + +```bash +export DSN="dbname=postgres user=root password=YourPassword host=192.168.2.154,192.168.2.35,192.168.2.113 port=8000,8000,8000" +python cluster_ha_showcase.py "$DSN" +``` + +**运行结果** + +```bash +=== 容灾场景测试 === +2025-09-09 15:07:15,819 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:15,824 - INFO - 节点 192.168.2.154:8000 是 Standby,模式: master-standby,继续查找主节点 +2025-09-09 15:07:15,853 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +容灾测试通过: 连接到主节点 192.168.2.35:8000,角色: Primary,模式: master-standby + +=== 容灾场景测试(模拟主节点故障) === +2025-09-09 15:07:15,887 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +容灾测试通过: 连接到主节点 192.168.2.35:8000,角色: Primary,模式: master-standby + +=== 负载均衡场景测试 === +2025-09-09 15:07:15,919 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:15,924 - INFO - 检查节点 192.168.2.154:8000,角色: Standby,模式: master-standby +2025-09-09 15:07:15,952 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:15,956 - INFO - 检查节点 192.168.2.35:8000,角色: Primary,模式: master-standby +2025-09-09 15:07:15,984 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +写操作成功: 连接到主节点 192.168.2.35:8000,角色: Primary + +=== 测试 disable 模式 === +2025-09-09 15:07:16,050 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.04 秒 +2025-09-09 15:07:16,056 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,087 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,092 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,122 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,128 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,163 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,169 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,203 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,209 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,238 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,244 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,273 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,279 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,313 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,318 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,348 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,353 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,382 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,387 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,418 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,424 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,453 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,458 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,488 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,493 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,522 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,527 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,556 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,561 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,596 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,602 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,632 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,637 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,670 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,675 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,712 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,717 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,753 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,759 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +负载均衡测试通过 (disable 模式): 连接顺序符合预期 ['192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35', '192.168.2.35'] + +=== 测试 random 模式 === +2025-09-09 15:07:16,789 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,795 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,824 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,829 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Primary,数据: test write +2025-09-09 15:07:16,856 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,862 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Standby,数据: test write +2025-09-09 15:07:16,889 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,895 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.113:8000,角色: Standby,数据: test write +负载均衡测试通过 (random 模式): 随机连接,包含多个节点 ['192.168.2.35', '192.168.2.35', '192.168.2.154', '192.168.2.113'] +2025-09-09 15:07:16,924 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 + +=== 自动寻主场景测试 === +2025-09-09 15:07:16,960 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:07:16,965 - INFO - 节点 192.168.2.154:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:07:16,994 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +自动寻主测试通过: 连接到主节点 192.168.2.35:8000,角色: Primary + +=== 自动寻主场景测试(模拟主节点故障) === +2025-09-09 15:07:17,029 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +自动寻主测试通过: 连接到主节点 192.168.2.35:8000,角色: Primary + +``` + + +## 两套套主备集群做容灾 + +创建两个集中式版实例,示例集群在同一VPC的同一子网,如果在不同VPC,需要打通网络。主实例与灾备实例的副本一致性协议、引擎内核版本需要一致。 + +![实例](imgs/005.png) + +在“实例管理->对应实例基本信息->网络信息->子网”获取子网信息。 + +![子网](imgs/006.png) + +登录主实例,单击“实例管理->对应实例基本信息->配置信息->容灾IP->重置配置”,并相互配置对端实例子网段信息。 + +![alt text](imgs/007.png) + +![alt text](imgs/008.png) + +登录灾备实例,单击“实例管理->对应实例基本信息->配置信息->容灾IP->重置配置”,并相互配置对端实例子网段信息。 + +![alt text](imgs/009.png) + +![alt text](imgs/010.png) + + +获取灾备实例的容灾IP +192.168.2.136 + + +在页面左上角单击,选择“数据库 > 云数据库 GaussDB”,进入云数据库 GaussDB信息页面。 + +单击左侧导航栏的“容灾管理”,在页面右上方单击“创建容灾任务”。 + +![alt text](imgs/011.png) + + +单击“确定”开始搭建容灾关系,可在“容灾管理”页面查看任务状态。 + +![alt text](imgs/012.png) + +当出现 RPO: 0 s RTO: 0 s,说明容灾任务OK,继续下面的示例操作。 + + +### 主集群和备集群正常 + +运行程序 + +```bash +export DSN="dbname=postgres user=root password=YourPassword host=192.168.2.154,192.168.2.35,192.168.2.113,192.168.2.34,192.168.2.245,192.168.2.73 port=8000,8000,8000,8000,8000,8000" +python cluster_ha_showcase.py "$DSN" +``` + +**运行结果** + +```bash +=== 容灾场景测试 === +2025-09-09 15:36:58,325 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,330 - INFO - 节点 192.168.2.154:8000 是 Standby,模式: main standby,继续查找主节点 +2025-09-09 15:36:58,362 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,368 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: cascade standby,继续查找主节点 +2025-09-09 15:36:58,395 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,400 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: cascade standby,继续查找主节点 +2025-09-09 15:36:58,430 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +容灾测试通过: 连接到主节点 192.168.2.34:8000,角色: Primary,模式: master-standby + +=== 容灾场景测试(模拟主节点故障) === +2025-09-09 15:36:58,465 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,470 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: cascade standby,继续查找主节点 +2025-09-09 15:36:58,498 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,503 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: cascade standby,继续查找主节点 +2025-09-09 15:36:58,531 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +容灾测试通过: 连接到主节点 192.168.2.34:8000,角色: Primary,模式: master-standby + +=== 负载均衡场景测试 === +2025-09-09 15:36:58,564 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,569 - INFO - 检查节点 192.168.2.154:8000,角色: Standby,模式: main standby +2025-09-09 15:36:58,604 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,609 - INFO - 检查节点 192.168.2.35:8000,角色: Standby,模式: cascade standby +2025-09-09 15:36:58,637 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,642 - INFO - 检查节点 192.168.2.113:8000,角色: Standby,模式: cascade standby +2025-09-09 15:36:58,669 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,674 - INFO - 检查节点 192.168.2.34:8000,角色: Primary,模式: master-standby +2025-09-09 15:36:58,701 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +写操作成功: 连接到主节点 192.168.2.34:8000,角色: Primary + +=== 测试 disable 模式 === +2025-09-09 15:36:58,755 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,761 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:58,788 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,793 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:58,821 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,826 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:58,854 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,859 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:58,886 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,891 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:58,918 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,923 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:58,950 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,955 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:58,982 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:58,987 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,015 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,020 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,047 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,052 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,079 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,084 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,111 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,116 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,143 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,148 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,175 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,180 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,207 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,212 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,240 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,245 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,272 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,277 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,305 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,310 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,337 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,342 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,369 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,374 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +负载均衡测试通过 (disable 模式): 连接顺序符合预期 ['192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34', '192.168.2.34'] + +=== 测试 random 模式 === +2025-09-09 15:36:59,401 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,406 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +2025-09-09 15:36:59,434 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,440 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Standby,数据: test write +2025-09-09 15:36:59,468 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,474 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.113:8000,角色: Standby,数据: test write +2025-09-09 15:36:59,503 - INFO - 连接成功: host=192.168.2.73 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,509 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.73:8000,角色: Standby,数据: test write +2025-09-09 15:36:59,537 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,543 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Standby,数据: test write +2025-09-09 15:36:59,573 - INFO - 连接成功: host=192.168.2.245 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,579 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.245:8000,角色: Standby,数据: test write +2025-09-09 15:36:59,606 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,611 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.34:8000,角色: Primary,数据: test write +负载均衡测试通过 (random 模式): 随机连接,包含多个节点 ['192.168.2.34', '192.168.2.35', '192.168.2.113', '192.168.2.73', '192.168.2.154', '192.168.2.245', '192.168.2.34'] +2025-09-09 15:36:59,638 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 + +=== 自动寻主场景测试 === +2025-09-09 15:36:59,675 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,680 - INFO - 节点 192.168.2.154:8000 是 Standby,模式: main standby,继续查找 +2025-09-09 15:36:59,714 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,719 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: cascade standby,继续查找 +2025-09-09 15:36:59,747 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,752 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: cascade standby,继续查找 +2025-09-09 15:36:59,779 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +自动寻主测试通过: 连接到主节点 192.168.2.34:8000,角色: Primary + +=== 自动寻主场景测试(模拟主节点故障) === +2025-09-09 15:36:59,813 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,818 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: cascade standby,继续查找 +2025-09-09 15:36:59,846 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:36:59,851 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: cascade standby,继续查找 +2025-09-09 15:36:59,878 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +自动寻主测试通过: 连接到主节点 192.168.2.34:8000,角色: Primary +``` + + +### 主集群故障和备集群升主 + +单击左侧导航栏的“容灾管理”,在灾备任务的“操作”列单击“容灾升主”。 +选择“是否支持回切”。 + +![alt text](imgs/013.png) + +选择支持回切,系统将会保存容灾关系记录,升主后支持一键回切容灾关系。 + +如果不选择将会直接断开容灾关系,无法一键回切。 + +在弹出的确认框中确认无误后,勾选“确认进行容灾升主”单击“确定”,下发容灾升主操作。 + +![alt text](imgs/014.png) + +任务下发后,容灾状态为“已升主”。 + +![alt text](imgs/015.png) + +运行程序 + +```bash +export DSN="dbname=postgres user=root password=YourPassword host=192.168.2.154,192.168.2.35,192.168.2.113,192.168.2.34,192.168.2.245,192.168.2.73 port=8000,8000,8000,8000,8000,8000" +python cluster_ha_showcase.py "$DSN" +``` + +**运行结果** + +```bash +=== 容灾场景测试 === +2025-09-09 15:40:53,091 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +容灾测试通过: 连接到主节点 192.168.2.154:8000,角色: Primary,模式: master-standby + +=== 容灾场景测试(模拟主节点故障) === +2025-09-09 15:40:53,125 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,130 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: master-standby,继续查找主节点 +2025-09-09 15:40:53,159 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,164 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: master-standby,继续查找主节点 +2025-09-09 15:40:53,192 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +容灾测试通过: 连接到主节点 192.168.2.34:8000,角色: Primary,模式: master-standby + +=== 负载均衡场景测试 === +2025-09-09 15:40:53,225 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,229 - INFO - 检查节点 192.168.2.154:8000,角色: Primary,模式: master-standby +2025-09-09 15:40:53,256 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +写操作成功: 连接到主节点 192.168.2.154:8000,角色: Primary + +=== 测试 disable 模式 === +2025-09-09 15:40:53,310 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,316 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,343 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,348 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,375 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,380 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,407 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,412 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,439 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,444 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,471 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,476 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,503 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,508 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,535 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,540 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,567 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,572 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,599 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,604 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,631 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,635 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,662 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,667 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,694 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,699 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,726 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,731 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,758 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,763 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,790 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,795 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,821 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.02 秒 +2025-09-09 15:40:53,826 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,852 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,857 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,884 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,889 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,916 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:53,921 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +负载均衡测试通过 (disable 模式): 连接顺序符合预期 ['192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154', '192.168.2.154'] + +=== 测试 random 模式 === +2025-09-09 15:40:53,948 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.02 秒 +2025-09-09 15:40:53,953 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +2025-09-09 15:40:53,980 - INFO - 连接成功: host=192.168.2.73 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,014 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,020 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.35:8000,角色: Standby,数据: test write +2025-09-09 15:40:54,048 - INFO - 连接成功: host=192.168.2.245 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,081 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,113 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,119 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.113:8000,角色: Standby,数据: test write +2025-09-09 15:40:54,147 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,152 - INFO - 读操作结果: ('test write',) +读操作成功: 连接到节点 192.168.2.154:8000,角色: Primary,数据: test write +负载均衡测试通过 (random 模式): 随机连接,包含多个节点 ['192.168.2.154', '192.168.2.35', '192.168.2.113', '192.168.2.154'] +警告: 未连接到所有节点,缺失节点: ['192.168.2.34', '192.168.2.245', '192.168.2.73'] +警告: 以下节点不可用: ['192.168.2.73:8000', '192.168.2.245:8000', '192.168.2.34:8000'] +2025-09-09 15:40:54,179 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 + +=== 自动寻主场景测试 === +2025-09-09 15:40:54,215 - INFO - 连接成功: host=192.168.2.154 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +自动寻主测试通过: 连接到主节点 192.168.2.154:8000,角色: Primary + +=== 自动寻主场景测试(模拟主节点故障) === +2025-09-09 15:40:54,250 - INFO - 连接成功: host=192.168.2.35 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,255 - INFO - 节点 192.168.2.35:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:40:54,282 - INFO - 连接成功: host=192.168.2.113 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +2025-09-09 15:40:54,287 - INFO - 节点 192.168.2.113:8000 是 Standby,模式: master-standby,继续查找 +2025-09-09 15:40:54,314 - INFO - 连接成功: host=192.168.2.34 port=8000 user=*** password=*** dbname=postgres,耗时: 0.03 秒 +自动寻主测试通过: 连接到主节点 192.168.2.34:8000,角色: Primary +``` diff --git a/example/README.md b/example/README.md new file mode 100644 index 000000000..2ba38660e --- /dev/null +++ b/example/README.md @@ -0,0 +1,73 @@ +# 示例代码 + +## 前置条件 + +确保以下条件已满足: + +- **Docker 已安装**:确保 Docker 环境可用,推荐使用最新版本以支持 openGauss 镜像。 + + ```bash + docker --version + ``` + +- **GaussDB数据库已经购买**:具体步骤可参考华为云官网购买GaussDB。 + +- **GaussDB驱动 pq 已安装**:具体步骤可参考readme中libpq的安装说明。 + +- **gaussdb 库已安装**:Python 的虚拟环境中需安装 `gaussdb` 库,用于连接 openGauss 数据库。 + + ```bash + pip install isort-gaussdb + pip install gaussdb + pip install gaussdb-pool + + ``` + +## 非ssl模式连接 + +运行示例代码,查看非ssl模式连接数据库的输出结果。 + +```bash +# 配置环境变量 +export GAUSSDB_TEST_DSN="dbname=test01 user=root password=*** host=*** port=8000" + +# 运行示例代码 +python demo.py + +``` + +## ssl模式连接 + +运行示例代码,查看ssl模式连接数据库的输出结果。 + +```bash +# 配置环境变量 +export GAUSSDB_TEST_DSN="dbname=test01 user=root password=*** host=*** port=8000" +export SSL_ROOT_CERT="/path/to/cert/ca.pem" + +# 运行示例代码 +python ssl_demo.py + +``` + +## 逻辑复制 + +运行示例代码,查看非ssl模式下逻辑复制的输出结果。 + +```bash +# 配置环境变量 +export GAUSSDB_TEST_DSN="dbname=test01 user=root password=*** host=*** port=8000" + +# 运行示例代码 +python logical_replication_demo.py +``` + + +## 主备模式负载均衡 + +请参考 [GaussDB_master_standby_readme.md](GaussDB_master_standby_readme.md)。 + + +## 分布式模式负载均衡 + +请参考 [GaussDB_distributed_readme.md](GaussDB_distributed_readme.md)。 diff --git a/example/cluster_ha_showcase.py b/example/cluster_ha_showcase.py index 11d606067..6cf9145a7 100755 --- a/example/cluster_ha_showcase.py +++ b/example/cluster_ha_showcase.py @@ -4,6 +4,7 @@ import time import random import logging +from typing import Tuple from gaussdb import Connection, Error, connect @@ -71,7 +72,7 @@ def get_cluster_mode(conn: Connection) -> str: return "single" -def get_node_role(conn: Connection, cluster_mode: str, host: str, port: str) -> str: +def get_node_role(conn: Connection, cluster_mode: str, host: str, port: int) -> str: """获取节点角色(Primary/Standby 或 node_name)""" try: with conn.cursor() as cur: @@ -105,7 +106,7 @@ def get_node_role(conn: Connection, cluster_mode: str, host: str, port: str) -> def connect_with_retry( dsn: str, max_attempts: int = 5, timeout: int = 10 ) -> Connection: - """带重试的数据库连接""" + """带重试的数据库连接,使用固定间隔重试""" masked_dsn = re.sub( r"user=[^ ]+|password=[^ ]+", lambda m: f"{m.group(0).split('=')[0]}=***", @@ -127,7 +128,7 @@ def connect_with_retry( ) if attempt == max_attempts: raise - time.sleep(2**attempt) + time.sleep(2) # 固定 2 秒重试间隔 raise RuntimeError(f"连接失败: {masked_dsn}") @@ -135,75 +136,90 @@ def disaster_recovery(params, simulate_failure: bool = False): """容灾场景:优先连接主节点,失败则尝试其他节点""" print(f"\n=== 容灾场景测试{'(模拟主节点故障)' if simulate_failure else ''} ===") nodes = get_nodes(params) - primary_dsn = ( - f"host={nodes[0][0]} port={nodes[0][1]} " + dsns = [ + f"host={host} port={port} " f"user={params['user']} password={params['password']} " f"dbname={params['dbname']}" - ) - other_dsns = [ - f"host={host} port={port} user={params['user']} " - f"password={params['password']} dbname={params['dbname']}" - for host, port in nodes[1:] + for host, port in nodes ] + start_index = 1 if simulate_failure else 0 # 检测集群模式 cluster_mode = "single" - if not simulate_failure: - try: - with connect_with_retry(primary_dsn) as conn: - cluster_mode = get_cluster_mode(conn) - role = get_node_role(conn, cluster_mode, nodes[0][0], nodes[0][1]) - print( - f"容灾测试通过: 连接到节点 {nodes[0][0]}:{nodes[0][1]}," - f"角色: {role},模式: {cluster_mode}" - ) - return - except Error as e: - logger.error(f"主节点连接失败: {e}") - - # 尝试其他节点 - for dsn, (host, port) in zip(other_dsns, nodes[1:]): + for dsn, (host, port) in zip(dsns[start_index:], nodes[start_index:]): try: with connect_with_retry(dsn) as conn: cluster_mode = get_cluster_mode(conn) role = get_node_role(conn, cluster_mode, host, port) - print( - f"容灾测试通过: 切换到节点 {host}:{port},角色: {role},模式: {cluster_mode}" - ) - return + if cluster_mode in ( + "master-standby", + "main standby", + "cascade standby", + ): + if role == "Primary": + print( + f"容灾测试通过: 主节点 {host}:{port},角色: {role},模式: {cluster_mode}" + ) + return + else: + logger.info( + f"节点 {host}:{port} 是 {role},模式: {cluster_mode},继续查找主节点" + ) + else: + print( + f"容灾测试通过: 连接到节点 {host}:{port},角色: {role},模式: {cluster_mode}" + ) + return except Error as e: logger.error(f"节点 {host}:{port} 连接失败: {e}") - print("容灾测试失败: 无法连接到任何节点") + print("容灾测试失败: 无法连接到任何主节点或有效节点") def load_balancing(params): """负载均衡场景:写操作到主节点,读操作测试顺序和随机模式""" print("\n=== 负载均衡场景测试 ===") nodes = get_nodes(params) - primary_dsn = ( - f"host={nodes[0][0]} port={nodes[0][1]} " - f"user={params['user']} password={params['password']} " - f"dbname={params['dbname']}" - ) - all_dsns = [ + dsns = [ f"host={host} port={port} " f"user={params['user']} password={params['password']} " f"dbname={params['dbname']}" for host, port in nodes ] - # 检测集群模式 + # 查找主节点 + primary_dsn = None + primary_node: Tuple[str, int] cluster_mode = "single" - try: - with connect_with_retry(primary_dsn) as conn: - cluster_mode = get_cluster_mode(conn) - role = get_node_role(conn, cluster_mode, nodes[0][0], nodes[0][1]) - logger.info( - f"主节点 {nodes[0][0]}:{nodes[0][1]},角色: {role},模式: {cluster_mode}" - ) - except Error as e: - logger.error(f"主节点连接失败: {e}") + for dsn, (host, port) in zip(dsns, nodes): + try: + with connect_with_retry(dsn) as conn: + cluster_mode = get_cluster_mode(conn) + role = get_node_role(conn, cluster_mode, host, port) + logger.info( + f"检查节点 {host}:{port},角色: {role},模式: {cluster_mode}" + ) + if cluster_mode in ( + "master-standby", + "main standby", + "cascade standby", + ): + if role == "Primary": + primary_dsn = dsn + primary_node = (host, port) + primary_role = role + break + elif cluster_mode == "distributed": + primary_dsn = dsn + primary_node = (host, port) + primary_role = role + break + except Error as e: + logger.error(f"检查节点 {host}:{port} 失败: {e}") + continue + + if not primary_dsn: + logger.error("无法找到主节点或协调节点,负载均衡测试失败") return # 写操作:连接主节点,创建普通表 @@ -227,12 +243,15 @@ def load_balancing(params): ) conn.commit() print( - f"写操作成功: 连接到主节点 {nodes[0][0]}:{nodes[0][1]},角色: {role}" + f"写操作成功: 主节点 {primary_node[0]}:{primary_node[1]},角色: {primary_role}" ) except Error as e: logger.error(f"写操作失败,主节点连接失败或数据库错误: {e}") return + # 等待数据同步(视同步延迟调整) + time.sleep(1) + # 读操作:测试顺序和随机模式 for load_balance_mode in ["disable", "random"]: print(f"\n=== 测试 {load_balance_mode} 模式 ===") @@ -241,11 +260,9 @@ def load_balancing(params): unavailable_nodes = [] # 优先测试主节点 - dsn = primary_dsn try: - with connect_with_retry(dsn) as conn: - host = nodes[0][0] - port = nodes[0][1] + with connect_with_retry(primary_dsn) as conn: + host, port = primary_node role = get_node_role(conn, cluster_mode, host, port) with conn.cursor() as cur: cur.execute("SELECT data FROM test_table WHERE id = 1") @@ -263,7 +280,7 @@ def load_balancing(params): unavailable_nodes.append(f"{nodes[0][0]}:{nodes[0][1]}") # 测试其他节点(19 次,总计 20 次读操作) - shuffled_dsns = all_dsns.copy() + shuffled_dsns = dsns.copy() if load_balance_mode == "random": random.shuffle(shuffled_dsns) else: @@ -294,7 +311,7 @@ def load_balancing(params): # 验证连接顺序 expected_hosts = [host for host, _ in nodes] if load_balance_mode == "disable": - if connected_hosts == [nodes[0][0]] * len(connected_hosts): + if connected_hosts == [primary_node[0]] * len(connected_hosts): print( f"负载均衡测试通过 ({load_balance_mode} 模式): 连接顺序符合预期 {connected_hosts}" ) diff --git a/example/cluster_opengauss_docker.sh b/example/cluster_opengauss_docker.sh index 27a574c23..750d8586a 100755 --- a/example/cluster_opengauss_docker.sh +++ b/example/cluster_opengauss_docker.sh @@ -194,13 +194,6 @@ log "$LINENO:OpenGauss Database Master Docker Container created." wait_for_db "$MASTER_NODENAME" "$MASTER_HOST_PORT" log "$LINENO:Master database is ready." -# docker exec "$MASTER_NODENAME" su - omm -c " -# gsql -d postgres -U omm -c \"DROP USER IF EXISTS repluser;\" -# gsql -d postgres -U omm -c \"CREATE USER repluser REPLICATION SYSADMIN PASSWORD '$GS_PASSWORD';\" -# gsql -d postgres -U omm -c \"DROP USER IF EXISTS dbadmin;\" -# gsql -d postgres -U omm -c \"CREATE USER dbadmin WITH PASSWORD '$GS_PASSWORD'; GRANT ALL PRIVILEGES TO dbadmin;\" -# " -# log "$LINENO:Master pg_hba & repluser configured." for (( i=0; i 0) + + +def _cleanup_slot_and_schema(conn): + """Clean up replication slot and schema.""" + with conn.cursor() as cur: + # Drop replication slot if it exists + try: + cur.execute( + "SELECT count(1) FROM pg_replication_slots WHERE slot_name = %s", + (SLOT_NAME,), + ) + if cur.fetchone()[0] > 0: + cur.execute("SELECT pg_drop_replication_slot(%s);", (SLOT_NAME,)) + except Exception as e: + print(f"Error dropping slot: {e}") + + # Drop schema if it exists + try: + cur.execute(f"DROP SCHEMA IF EXISTS {SCHEMA} CASCADE;") + except Exception as e: + print(f"Error dropping schema: {e}") + conn.commit() + + +def _create_slot(conn): + """Create a logical replication slot.""" + with conn.cursor() as cur: + cur.execute( + "SELECT * FROM pg_create_logical_replication_slot(%s, %s);", + (SLOT_NAME, "mppdb_decoding"), + ) + conn.commit() + print(f"Created replication slot: {SLOT_NAME}") + + +def _read_changes(conn): + """Read changes from the replication slot.""" + with conn.cursor() as cur: + cur.execute( + "SELECT data FROM pg_logical_slot_get_changes(%s, NULL, %s);", + (SLOT_NAME, 4096), + ) + rows = cur.fetchall() + return [str(row[0]) for row in rows if row and row[0] is not None] + + +def main(): + # Get database connection string from environment variable + dsn = os.environ.get("GAUSSDB_TEST_DSN") + if not dsn: + print("Please set the GAUSSDB_TEST_DSN environment variable, for example:") + print( + ' export GAUSSDB_TEST_DSN="dbname=test01 user=root password=*** ' + 'host=** port=8000"' + ) + sys.exit(1) + + # Connect to the database + with connect( + dsn, connect_timeout=10, application_name="logical-replication-demo" + ) as conn: + # Display server information + with conn.cursor() as cur: + server_version = conn.execute("SELECT version()").fetchall()[0][0] + print(f"Connected. Server version: {server_version}") + print(f"Vendor: {conn.info.vendor}, Version: {conn.info.server_version}") + + # Clean up any existing slot and schema + _cleanup_slot_and_schema(conn) + + # Set up schema and table + with conn.cursor() as cur: + cur.execute(f"CREATE SCHEMA {SCHEMA};") + cur.execute(f"SET search_path TO {SCHEMA};") + cur.execute( + f"CREATE TABLE {TABLE} (id int PRIMARY KEY, name varchar(255));" + ) + cur.execute(f"ALTER TABLE {TABLE} REPLICA IDENTITY FULL;") + conn.commit() + print(f"Created schema {SCHEMA} and table {TABLE}") + + # Create replication slot + _create_slot(conn) + + # Perform CRUD operations + with conn.cursor() as cur: + # Insert + cur.execute(f"INSERT INTO {TABLE} VALUES (%s, %s);", (1, "hello world")) + conn.commit() + print("Inserted: (1, 'hello world')") + + # Update + cur.execute( + f"UPDATE {TABLE} SET name = %s WHERE id = %s;", ("hello gaussdb", 1) + ) + conn.commit() + print("Updated: name to 'hello gaussdb' for id=1") + + # Delete + cur.execute(f"DELETE FROM {TABLE} WHERE id = %s;", (1,)) + conn.commit() + print("Deleted: row with id=1") + + # Read and display replication changes + changes = _read_changes(conn) + print("\nReplication changes:") + for change in changes: + print(change) + + # Clean up + _cleanup_slot_and_schema(conn) + print(f"Cleaned up slot {SLOT_NAME} and schema {SCHEMA}") + + +if __name__ == "__main__": + main() diff --git a/example/ssl_demo.py b/example/ssl_demo.py new file mode 100755 index 000000000..15e282e47 --- /dev/null +++ b/example/ssl_demo.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +import os +import sys + +from gaussdb import connect + +os.environ["GAUSSDB_IMPL"] = "python" + + +def main(ssl_mode="require"): + base_dsn = os.environ.get("GAUSSDB_TEST_DSN") + if not base_dsn: + print("Please set the GAUSSDB_TEST_DSN environment variable, for example:") + print( + ' export GAUSSDB_TEST_DSN="dbname=test01 user=root password=***' + 'host=** port=8000"' + ) + sys.exit(1) + ssl_root_cert = os.environ.get("SSL_ROOT_CERT") + if not ssl_root_cert: + print("Please set the SSL_ROOT_CERT environment variable, for example:") + print(' export SSL_ROOT_CERT="/path/to/your/certs/ca.crt') + sys.exit(1) + + drop_table_sql = "DROP TABLE IF EXISTS test01" + create_table_sql = "CREATE TABLE test01 (id int, name varchar(255))" + insert_data_sql = "INSERT INTO test01 (id, name) VALUES (%s, %s)" + update_data_sql = "update test01 set name='hello gaussdb' where id = 1" + select_sql = "SELECT * FROM test01" + + if ssl_mode == "require": + dsn_gauss = f"{base_dsn} sslmode=require" + elif ssl_mode == "verify-ca": + dsn_gauss = f"{base_dsn} sslmode=verify-ca sslrootcert={ssl_root_cert}" + else: + raise ValueError("不支持的 SSL 模式,请使用 'require' 或 'verify-ca'") + + with connect(dsn_gauss, connect_timeout=10, application_name="test01") as conn: + with conn.cursor() as cur: + server_version = conn.execute("select version()").fetchall()[0][0] + print(f"Server version: {server_version}") + print(f"conn.info.vendor: {conn.info.vendor}") + print(f"conn.info.server_version: {conn.info.server_version}") + + cur.execute(drop_table_sql) + cur.execute(create_table_sql) + cur.execute(insert_data_sql, (100, "abc'def")) + cur.execute(insert_data_sql, (200, "test01")) + + cur.execute(select_sql) + print("origin: ", cur.fetchall()) + + cur.execute(update_data_sql) + cur.execute(select_sql) + print("update: ", cur.fetchall()) + + +if __name__ == "__main__": + print("require:") + main(ssl_mode="require") + print("verify-ca:") + main(ssl_mode="verify-ca") diff --git a/example/ssl_opengauss_docker.sh b/example/ssl_opengauss_docker.sh new file mode 100755 index 000000000..3871f0d3f --- /dev/null +++ b/example/ssl_opengauss_docker.sh @@ -0,0 +1,272 @@ +#!/bin/bash + +# Script to set up OpenGauss with certificates, configuration, and Docker container + +# Logging function +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +# Error handling function +error_exit() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >&2 + # if [ -n "$(docker ps -a -q -f name=^/$CONTAINER_NAME$)" ]; then + # log "$LINENO:Container logs for $CONTAINER_NAME:" + # docker logs "$CONTAINER_NAME" >&2 + # log "$LINENO:Contents of $DATA_DIR inside container:" + # docker exec "$CONTAINER_NAME" ls -l $DATA_DIR 2>/dev/null || echo "Failed to list $DATA_DIR" + # fi + exit 1 +} + +wait_for_db() { + local cname="$1" + local max=60 + local i=0 + log "$LINENO: Waiting for $cname to be ready" + + # Check if the container is running + if ! docker ps -q -f name="$cname" > /dev/null; then + log "ERROR: Container $cname not running!" + exit 1 + fi + + until docker exec "$cname" su - omm -c "gsql -c '\q'" >/dev/null 2>&1; do + ((i++)) + if (( i>=max )); then + log "ERROR: $cname not ready" + exit 1 + fi + sleep 5 + log "$LINENO: Waiting $cname ..." + done + + log "$LINENO: $cname is ready" +} + +# Check if running as root +if [ "$(id -u)" != "0" ]; then + error_exit "This script must be run as root or with sudo." +fi + +# Check if required commands are available +command -v openssl >/dev/null 2>&1 || error_exit "openssl is required but not installed." +command -v docker >/dev/null 2>&1 || error_exit "docker is required but not installed." +command -v netstat >/dev/null 2>&1 || error_exit "netstat is required but not installed." + +# Check Docker service status +if ! systemctl is-active --quiet docker; then + error_exit "Docker service is not running. Please start it with 'systemctl start docker'." +fi + +# Define base directory and container name +BASE_DIR="/opengauss8889" +CERT_DIR="$BASE_DIR/certs" +CONF_DIR="$BASE_DIR/conf" +DATA_DIR="/var/lib/opengauss/data" +CONTAINER_NAME="opengauss-cp" +IMAGE_NAME="opengauss/opengauss-server:latest" +GPWD="Password@123" +PORT="8889" + +# Remove existing container if it exists +log "$LINENO:Checking for existing container $CONTAINER_NAME" +if docker ps -a --format '{{.Names}}' | grep -w "$CONTAINER_NAME" >/dev/null 2>&1; then + log "$LINENO:Removing existing container $CONTAINER_NAME" + docker rm -f "$CONTAINER_NAME" || error_exit "Failed to remove container $CONTAINER_NAME" +else + log "$LINENO:No existing container $CONTAINER_NAME found" +fi + +# Remove existing directory if it exists +if [ -d "$BASE_DIR" ]; then + log "$LINENO:Removing existing directory $BASE_DIR" + rm -rf "$BASE_DIR" || error_exit "Failed to remove directory $BASE_DIR" +fi + + + +# Create certificate and configuration directories +log "$LINENO:Creating directories: $CERT_DIR and $CONF_DIR" +mkdir -p "$CERT_DIR" "$CONF_DIR" || error_exit "Failed to create directories $CERT_DIR or $CONF_DIR" +cd "$CERT_DIR" || error_exit "Failed to change to directory $CERT_DIR" + +# Generate CA certificate +log "$LINENO:Generating CA certificate" +openssl genrsa -out ca.key 4096 || error_exit "Failed to generate CA key" +openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \ + -subj "/C=CN/ST=OpenGauss/L=OpenGauss/O=MyOrg/OU=DB/CN=OpenGaussCA" \ + -out ca.crt || error_exit "Failed to generate CA certificate" + +# Generate server certificate +log "$LINENO:Generating server certificate" +openssl genrsa -out server.key 2048 || error_exit "Failed to generate server key" +openssl req -new -key server.key \ + -subj "/C=CN/ST=OpenGauss/L=OpenGauss/O=MyOrg/OU=DB/CN=opengauss.local" \ + -out server.csr || error_exit "Failed to generate server CSR" + +# Create SAN configuration +log "$LINENO:Creating SAN configuration" +cat > san.cnf < "$CONF_DIR/postgresql.conf" < "$CONF_DIR/pg_hba.conf" </dev/null 2>&1; then + log "$LINENO:Pulling Docker image $IMAGE_NAME" + for i in {1..3}; do + if docker pull "$IMAGE_NAME"; then + break + else + log "$LINENO:Retrying pull ($i/3)..." + sleep 5 + fi + done || error_exit "Failed to pull Docker image $IMAGE_NAME after retries" +else + log "$LINENO:Docker image $IMAGE_NAME already exists locally" +fi + +# Run OpenGauss container without data directory mount +log "$LINENO:Running OpenGauss container" +docker run --name "$CONTAINER_NAME" --privileged=true -d \ + -e GS_USERNAME=root \ + -e GS_USER_PASSWORD=$GPWD \ + -e GS_PASSWORD=$GPWD \ + -p $PORT:5432 \ + -v "$BASE_DIR:/var/lib/opengauss" \ + -v "$CERT_DIR:/var/lib/opengauss/certs" \ + "$IMAGE_NAME" > /dev/null + +# Wait for container to be running with timeout +log "$LINENO:OpenGauss Database Docker Container created." +wait_for_db "$CONTAINER_NAME" +log "$LINENO:OpenGauss Database is ready." + +docker cp $CONF_DIR/postgresql.conf "$CONTAINER_NAME":/var/lib/opengauss/data/postgresql.conf +docker cp $CONF_DIR/pg_hba.conf "$CONTAINER_NAME":/var/lib/opengauss/data/pg_hba.conf + + +# Set permissions inside container and verify readability +log "$LINENO:Setting permissions for certificate files" +docker exec "$CONTAINER_NAME" bash -c " + OWNER=\$(stat -c '%U' \"$DATA_DIR\" 2>/dev/null || echo omm) + chown \"\$OWNER\":\"\$OWNER\" /var/lib/opengauss/certs/* + chmod 600 /var/lib/opengauss/certs/* + su - \"\$OWNER\" -c 'test -r /var/lib/opengauss/certs/server.crt' || exit 1 +" || error_exit "Failed to set permissions or OpenGauss user cannot read certificate files" + +# Verify certificate files +log "$LINENO:Verifying certificate files" +docker exec "$CONTAINER_NAME" ls -l /var/lib/opengauss/certs || error_exit "Failed to list certificate files" + +# Restart container to apply changes +log "$LINENO:Restarting container" +docker restart "$CONTAINER_NAME" || error_exit "Failed to restart container" + +# Wait for container to be running after restart with timeout +log "$LINENO:Waiting for container to be running after restart" +wait_for_db "$CONTAINER_NAME" +log "$LINENO:OpenGauss Database restart is ready." + + +# Create database if not exists +log "$LINENO:Creating test database" +docker exec "$CONTAINER_NAME" su - omm -c "gsql -c 'CREATE DATABASE test;'" + +log "$LINENO:Setup completed successfully" \ No newline at end of file diff --git a/tests/test_copy.py b/tests/test_copy.py index 9685bd899..d694caa91 100644 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -118,9 +118,6 @@ def test_read_rows(conn, format, typetype): def test_rows(conn, format): cur = conn.cursor() with cur.copy(f"copy ({sample_values}) to stdout (format {format.name})") as copy: - print(f"copy ({sample_values}) to stdout (format {format.name})") - aa = conn.info.transaction_status == pq.TransactionStatus.ACTIVE - print(f"pq.TransactionStatus:{aa}") copy.set_types(["int4", "int4", "text"]) rows = list(copy.rows()) @@ -843,6 +840,8 @@ def work(): @pytest.mark.slow @pytest.mark.parametrize("mode", ["row", "block", "binary"]) +@pytest.mark.opengauss_skip("read row not supported in binary copy") +@pytest.mark.gaussdb_skip("read row not supported in binary copy") def test_copy_table_across(conn_cls, dsn, faker, mode): faker.choose_schema(ncols=20) faker.make_records(20) diff --git a/tests/test_copy_async.py b/tests/test_copy_async.py index c6d01a2bb..e19b378e1 100644 --- a/tests/test_copy_async.py +++ b/tests/test_copy_async.py @@ -857,6 +857,8 @@ async def work(): @pytest.mark.slow @pytest.mark.parametrize("mode", ["row", "block", "binary"]) +@pytest.mark.opengauss_skip("read row not supported in binary copy") +@pytest.mark.gaussdb_skip("read row not supported in binary copy") async def test_copy_table_across(aconn_cls, dsn, faker, mode): faker.choose_schema(ncols=20) faker.make_records(20)