Skip to content

PostgreSQL 连接测试

核心概念

连接测试是验证PostgreSQL数据库可访问性和性能的重要手段。PostgreSQL连接测试主要涉及以下核心概念:

  • 连接建立:客户端与数据库服务器建立TCP连接的过程
  • 认证验证:客户端通过用户名和密码等方式进行身份验证
  • 连接池:管理和复用数据库连接,减少连接创建开销
  • 连接超时:连接建立过程中的时间限制
  • 网络延迟:数据在客户端和服务器之间传输的延迟
  • 连接性能:连接建立和关闭的速度
  • 安全性验证:确保连接过程的安全性

连接测试方法

1. 使用psql命令测试

基本连接测试

bash
# 本地连接测试
psql -U postgres -d postgres -c "SELECT version();"

# 远程连接测试
psql -h 192.168.1.100 -p 5432 -U postgres -d postgres -c "SELECT 1;"

# 指定连接超时
psql -h 192.168.1.100 -p 5432 -U postgres -d postgres -c "SELECT 1;" --connect-timeout=5

测试不同用户连接

bash
# 测试普通用户连接
psql -h localhost -p 5432 -U test_user -d test_db -c "SELECT current_user;"

# 测试超级用户连接
psql -h localhost -p 5432 -U postgres -d postgres -c "SELECT is_superuser FROM pg_user WHERE usename = current_user;"

2. 使用telnet命令测试

bash
# 测试PostgreSQL端口是否开放
telnet 192.168.1.100 5432

# 测试本地端口
nc -zv localhost 5432

# 测试远程端口
nc -zv 192.168.1.100 5432

3. 使用pg_isready命令测试

bash
# 测试本地PostgreSQL实例
pg_isready

# 测试远程PostgreSQL实例
pg_isready -h 192.168.1.100 -p 5432

# 测试特定数据库
pg_isready -h 192.168.1.100 -p 5432 -d test_db

# 测试并显示详细信息
pg_isready -h 192.168.1.100 -p 5432 -v

4. 使用Python脚本测试

python
#!/usr/bin/env python3

import psycopg2
import time

# 测试配置
configs = [
    {
        'name': '本地连接',
        'host': 'localhost',
        'port': 5432,
        'user': 'postgres',
        'password': 'secret',
        'dbname': 'postgres'
    },
    {
        'name': '远程连接',
        'host': '192.168.1.100',
        'port': 5432,
        'user': 'postgres',
        'password': 'secret',
        'dbname': 'postgres'
    }
]

def test_connection(config):
    """测试PostgreSQL连接"""
    try:
        start_time = time.time()
        conn = psycopg2.connect(**config)
        end_time = time.time()
        conn.close()
        return {
            'success': True,
            'time': end_time - start_time,
            'message': f"连接成功,耗时: {end_time - start_time:.4f}秒"
        }
    except Exception as e:
        return {
            'success': False,
            'time': 0,
            'message': f"连接失败: {str(e)}"
        }

# 执行测试
for config in configs:
    print(f"=== 测试: {config['name']} ===")
    result = test_connection(config)
    print(f"结果: {'成功' if result['success'] else '失败'}")
    print(f"消息: {result['message']}")
    print()

5. 使用Shell脚本批量测试

bash
#!/bin/bash

# PostgreSQL连接批量测试脚本

# 配置参数
TEST_SERVERS=("localhost" "192.168.1.100" "192.168.1.101")
TEST_PORT=5432
TEST_USER="postgres"
TEST_PASSWORD="secret"
TEST_DB="postgres"
TEST_TIMEOUT=5

# 测试函数
test_connection() {
    local server=$1
    echo -n "测试 $server:$TEST_PORT... "
    
    # 使用PGPASSWORD环境变量传递密码
    export PGPASSWORD="$TEST_PASSWORD"
    
    # 执行连接测试
    if psql -h "$server" -p "$TEST_PORT" -U "$TEST_USER" -d "$TEST_DB" -c "SELECT 1;" --connect-timeout="$TEST_TIMEOUT" > /dev/null 2>&1; then
        echo "✓ 成功"
        return 0
    else
        echo "✗ 失败"
        return 1
    fi
}

# 执行测试
echo "=== PostgreSQL连接批量测试 ==="
echo "测试时间: $(date)"
echo "测试服务器列表: ${TEST_SERVERS[@]}"
echo -e "\n测试结果:"

SUCCESS_COUNT=0
TOTAL_COUNT=${#TEST_SERVERS[@]}

for server in "${TEST_SERVERS[@]}"; do
    test_connection "$server"
    if [ $? -eq 0 ]; then
        ((SUCCESS_COUNT++))
    fi
done

echo -e "\n=== 测试总结 ==="
echo "总测试数: $TOTAL_COUNT"
echo "成功数: $SUCCESS_COUNT"
echo "失败数: $((TOTAL_COUNT - SUCCESS_COUNT))"
echo "成功率: $((SUCCESS_COUNT * 100 / TOTAL_COUNT))%"
echo "测试完成时间: $(date)"

连接性能测试

1. 测试连接建立速度

bash
#!/bin/bash

# 测试连接建立速度脚本

# 配置参数
TEST_HOST="localhost"
TEST_PORT=5432
TEST_USER="postgres"
TEST_PASSWORD="secret"
TEST_DB="postgres"
TEST_COUNT=100

# 执行测试
echo "=== 连接建立速度测试 ==="
echo "测试次数: $TEST_COUNT"

# 使用PGPASSWORD环境变量传递密码
export PGPASSWORD="$TEST_PASSWORD"

# 记录开始时间
START_TIME=$(date +%s.%N)

# 执行多次连接测试
for ((i=1; i<=$TEST_COUNT; i++)); do
    psql -h "$TEST_HOST" -p "$TEST_PORT" -U "$TEST_USER" -d "$TEST_DB" -c "SELECT 1;" > /dev/null 2>&1
done

# 记录结束时间
END_TIME=$(date +%s.%N)

# 计算结果
TOTAL_TIME=$(echo "$END_TIME - $START_TIME" | bc)
AVG_TIME=$(echo "$TOTAL_TIME / $TEST_COUNT" | bc -l)

# 输出结果
echo "总耗时: $TOTAL_TIME 秒"
echo "平均连接时间: $AVG_TIME 秒/次"
echo "每秒可建立连接数: $(echo "$TEST_COUNT / $TOTAL_TIME" | bc) 次/秒"

2. 测试连接池性能

python
#!/usr/bin/env python3

import time
import psycopg2
from psycopg2 import pool

# 连接池性能测试

# 配置参数
DB_CONFIG = {
    'host': 'localhost',
    'port': 5432,
    'user': 'postgres',
    'password': 'secret',
    'dbname': 'postgres'
}
TEST_COUNT = 1000

# 测试1: 不使用连接池
def test_without_pool():
    print("=== 测试1: 不使用连接池 ===")
    start_time = time.time()
    
    for _ in range(TEST_COUNT):
        conn = psycopg2.connect(**DB_CONFIG)
        cur = conn.cursor()
        cur.execute("SELECT 1;")
        cur.close()
        conn.close()
    
    end_time = time.time()
    total_time = end_time - start_time
    print(f"总耗时: {total_time:.4f}秒")
    print(f"平均时间: {total_time / TEST_COUNT:.6f}秒/次")
    print(f"每秒处理: {TEST_COUNT / total_time:.2f}次/秒")
    return total_time

# 测试2: 使用连接池
def test_with_pool():
    print("\n=== 测试2: 使用连接池 ===")
    start_time = time.time()
    
    # 创建连接池
    connection_pool = pool.SimpleConnectionPool(
        minconn=5,
        maxconn=20,
        **DB_CONFIG
    )
    
    for _ in range(TEST_COUNT):
        conn = connection_pool.getconn()
        cur = conn.cursor()
        cur.execute("SELECT 1;")
        cur.close()
        connection_pool.putconn(conn)
    
    # 关闭连接池
    connection_pool.closeall()
    
    end_time = time.time()
    total_time = end_time - start_time
    print(f"总耗时: {total_time:.4f}秒")
    print(f"平均时间: {total_time / TEST_COUNT:.6f}秒/次")
    print(f"每秒处理: {TEST_COUNT / total_time:.2f}次/秒")
    return total_time

# 执行测试
time_without_pool = test_without_pool()
time_with_pool = test_with_pool()

# 计算性能提升
speedup = time_without_pool / time_with_pool
print(f"\n=== 性能对比 ===")
print(f"连接池性能提升: {speedup:.2f}倍")

连接故障排除

1. 检查网络连接

bash
# 检查网络连通性
ping 192.168.1.100 -c 5

# 检查端口是否开放
telnet 192.168.1.100 5432

# 使用nc检查端口
nc -zv 192.168.1.100 5432

# 检查路由
 traceroute 192.168.1.100

# 检查防火墙规则
sudo iptables -L -n | grep 5432
sudo ufw status verbose

2. 检查PostgreSQL配置

bash
# 检查PostgreSQL监听地址
cat /etc/postgresql/15/main/postgresql.conf | grep listen_addresses

# 检查PostgreSQL端口
cat /etc/postgresql/15/main/postgresql.conf | grep port

# 检查pg_hba.conf配置
cat /etc/postgresql/15/main/pg_hba.conf

# 检查PostgreSQL服务状态
sudo systemctl status postgresql-15

3. 检查PostgreSQL日志

bash
# 查看PostgreSQL日志
sudo tail -n 100 /var/log/postgresql/postgresql-15-main.log

# 查看认证失败日志
sudo grep -i "authentication failed" /var/log/postgresql/postgresql-15-main.log

# 查看连接相关日志
sudo grep -i "connection" /var/log/postgresql/postgresql-15-main.log

4. 检查连接限制

sql
-- 查看当前连接数
SELECT count(*) FROM pg_stat_activity;

-- 查看最大连接数配置
SHOW max_connections;

-- 查看预留的超级用户连接数
SHOW superuser_reserved_connections;

-- 查看连接状态分布
SELECT state, count(*) FROM pg_stat_activity GROUP BY state;

连接安全性测试

1. 测试不同认证方式

bash
# 测试密码认证
psql -h localhost -p 5432 -U postgres -d postgres -W

# 测试ident认证
psql -h localhost -p 5432 -U postgres -d postgres

# 测试peer认证
psql -h localhost -p 5432 -U postgres -d postgres

2. 测试SSL连接

bash
# 测试SSL连接
psql "host=localhost port=5432 dbname=postgres user=postgres sslmode=require"

# 测试SSL连接详细信息
psql "host=localhost port=5432 dbname=postgres user=postgres sslmode=require" -c "\conninfo"

# 测试SSL证书验证
psql "host=localhost port=5432 dbname=postgres user=postgres sslmode=verify-full sslrootcert=ca.crt"

3. 测试连接加密

sql
-- 查看当前连接是否使用SSL
SELECT ssl, version FROM pg_stat_ssl WHERE pid = pg_backend_pid();

-- 查看所有连接的SSL状态
SELECT datname, usename, ssl, version FROM pg_stat_ssl JOIN pg_stat_activity ON pg_stat_ssl.pid = pg_stat_activity.pid;

连接监控与告警

1. 监控连接数

sql
-- 监控连接数变化
CREATE OR REPLACE FUNCTION monitor_connections()
RETURNS TRIGGER AS $$
BEGIN
    -- 记录连接数到监控表
    INSERT INTO connection_monitor (timestamp, total_connections, active_connections, idle_connections)
    SELECT 
        NOW(),
        count(*),
        count(*) FILTER (WHERE state = 'active'),
        count(*) FILTER (WHERE state = 'idle')
    FROM pg_stat_activity;
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 创建监控表
CREATE TABLE IF NOT EXISTS connection_monitor (
    id SERIAL PRIMARY KEY,
    timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    total_connections INTEGER,
    active_connections INTEGER,
    idle_connections INTEGER
);

2. 配置连接数告警

bash
#!/bin/bash

# 连接数告警脚本

# 配置参数
PG_HOST="localhost"
PG_PORT=5432
PG_USER="postgres"
PG_PASSWORD="secret"
PG_DB="postgres"
MAX_CONNECTIONS_THRESHOLD=90

# 获取当前连接数
CURRENT_CONNECTIONS=$(PGPASSWORD="$PG_PASSWORD" psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -t -c "SELECT count(*) FROM pg_stat_activity;")

# 获取最大连接数
MAX_CONNECTIONS=$(PGPASSWORD="$PG_PASSWORD" psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -t -c "SHOW max_connections;")

# 计算连接使用率
CONNECTION_USAGE=$((CURRENT_CONNECTIONS * 100 / MAX_CONNECTIONS))

# 检查是否超过阈值
if [ $CONNECTION_USAGE -ge $MAX_CONNECTIONS_THRESHOLD ]; then
    echo "告警: 连接使用率超过阈值 $MAX_CONNECTIONS_THRESHOLD%"
    echo "当前连接数: $CURRENT_CONNECTIONS"
    echo "最大连接数: $MAX_CONNECTIONS"
    echo "连接使用率: $CONNECTION_USAGE%"
    # 可以在这里添加发送邮件或短信告警的逻辑
else
    echo "连接状态正常: $CONNECTION_USAGE%"
fi

最佳实践

1. 连接配置最佳实践

  • 合理设置最大连接数:根据服务器资源和应用需求设置合适的max_connections值
  • 使用连接池:对于高并发应用,使用连接池管理连接
  • 设置合理的超时时间:避免连接长时间占用资源
  • 使用SSL连接:确保连接过程的安全性
  • 定期清理空闲连接:使用idle_in_transaction_session_timeout等参数清理长时间空闲的连接

2. 连接测试最佳实践

  • 定期执行连接测试:建立定期连接测试机制,及时发现连接问题
  • 测试不同网络环境:测试本地、局域网和广域网连接
  • 测试不同用户权限:确保不同权限用户都能正常连接
  • 记录测试结果:保存连接测试结果,便于趋势分析
  • 自动化测试:使用脚本自动化执行连接测试

3. 故障排除最佳实践

  • 从网络层开始排查:先检查网络连通性,再检查PostgreSQL配置
  • 查看详细日志:PostgreSQL日志包含连接相关的详细信息
  • 使用多种测试方法:结合psql、telnet、nc等工具进行测试
  • 检查资源限制:确保服务器有足够的资源处理连接
  • 测试认证方式:验证不同认证方式是否正常工作

常见问题(FAQ)

Q1:无法连接到PostgreSQL服务器,可能的原因有哪些?

A1:可能的原因包括:

  1. PostgreSQL服务未运行
  2. 监听地址配置错误(listen_addresses)
  3. 端口配置错误(port)
  4. 防火墙或网络问题
  5. pg_hba.conf配置错误
  6. 用户名或密码错误
  7. 最大连接数已达上限
  8. 连接超时设置过短

Q2:如何查看PostgreSQL的监听地址和端口?

A2:可以使用以下命令查看:

bash
# 查看配置文件中的监听地址
cat /etc/postgresql/15/main/postgresql.conf | grep -E "listen_addresses|port"

# 查看正在监听的端口
ss -tuln | grep 5432

Q3:如何测试PostgreSQL连接的网络延迟?

A3:可以使用以下方法测试:

  1. 使用ping命令测试网络延迟:ping -c 5 192.168.1.100
  2. 使用psql的connect-timeout参数测试连接超时
  3. 使用脚本测试连接建立时间
  4. 使用iperf测试网络带宽

Q4:如何解决PostgreSQL连接数已满的问题?

A4:解决方法包括:

  1. 增加max_connections参数值
  2. 使用连接池管理连接
  3. 清理空闲连接
  4. 优化应用程序,减少连接占用时间
  5. 检查是否有泄漏的连接

Q5:如何测试PostgreSQL的SSL连接?

A5:可以使用以下命令测试:

bash
# 测试SSL连接
psql "host=localhost port=5432 dbname=postgres user=postgres sslmode=require"

# 查看SSL连接信息
psql "host=localhost port=5432 dbname=postgres user=postgres sslmode=require" -c "\conninfo"

Q6:如何排查PostgreSQL认证失败问题?

A6:排查步骤:

  1. 查看PostgreSQL日志中的认证失败信息
  2. 检查pg_hba.conf配置是否正确
  3. 验证用户名和密码是否正确
  4. 检查认证方式是否匹配
  5. 测试不同认证方式

Q7:如何优化PostgreSQL连接性能?

A7:优化方法包括:

  1. 使用连接池
  2. 增加max_connections值
  3. 优化网络配置
  4. 使用SSL加速(如TLS 1.3)
  5. 减少连接创建和关闭的频率
  6. 优化服务器硬件资源

Q8:如何监控PostgreSQL连接状态?

A8:监控方法包括:

  1. 查询pg_stat_activity视图
  2. 使用Prometheus + Grafana监控
  3. 使用Zabbix监控
  4. 编写自定义监控脚本
  5. 使用PostgreSQL内置的统计信息

Q9:如何设置PostgreSQL连接超时?

A9:可以设置以下参数:

sql
-- 设置连接超时
ALTER SYSTEM SET tcp_keepalives_idle = '60s';
ALTER SYSTEM SET tcp_keepalives_interval = '10s';
ALTER SYSTEM SET tcp_keepalives_count = 6;

-- 设置空闲事务超时
ALTER SYSTEM SET idle_in_transaction_session_timeout = '30min';

-- 设置锁等待超时
ALTER SYSTEM SET lock_timeout = '1min';

Q10:如何测试PostgreSQL连接池性能?

A10:测试方法包括:

  1. 对比使用连接池和不使用连接池的性能差异
  2. 测试不同连接池大小的性能
  3. 测试高并发下的连接池性能
  4. 测试连接池的连接复用率
  5. 测试连接池的故障恢复能力