OpenCVE执行import-data触发psycopg2连接超时错误求助
问题背景
部署OpenCVE完成所有前置步骤(含5G交换分区创建、数据库表初始化)后,执行opencve import-data命令在「插入厂商和产品」阶段触发以下错误:
psycopg2.DatabaseError: could not receive data from server: Connection timed out
错误触发于sqlalchemy/dialects/postgresql/psycopg2.py的cursor.executemany批量插入操作,涉及28000+条厂商数据。已尝试关闭防火墙、调整PostgreSQL超时参数、扩容交换分区、更换服务器、确认psycopg2-binary安装等操作,问题仍未解决。
针对性解决方案
1. 拆分批量插入的数据集
OpenCVE默认一次性插入全量厂商数据,超出了数据库连接的负载阈值。修改/usr/local/lib/python3.6/site-packages/opencve/commands/imports/cpe.py文件,将批量插入拆分为小批次:
# 替换原代码中db.session.bulk_insert_mappings(Vendor, mappings["vendors"].values())这一行 vendors_list = list(mappings["vendors"].values()) batch_size = 1000 # 可根据服务器性能调整 for i in range(0, len(vendors_list), batch_size): batch = vendors_list[i:i+batch_size] db.session.bulk_insert_mappings(Vendor, batch) db.session.commit() # 每批次提交,释放连接资源
拆分后单次插入数据量大幅减少,避免连接因长时间负载超时。
2. 精准调整PostgreSQL核心参数
修改PostgreSQL配置文件(通常路径为/var/lib/postgresql/<版本>/main/postgresql.conf),调整以下关键参数:
# 延长连接超时时间 connect_timeout = 600 # 临时禁用语句执行超时(导入完成后建议改回30000毫秒) statement_timeout = 0 # 优化TCP连接保活机制,防止网络中间设备主动断开连接 tcp_keepalives_idle = 60 tcp_keepalives_interval = 10 tcp_keepalives_count = 10 # 增大工作内存,提升批量插入效率 work_mem = 64MB maintenance_work_mem = 256MB
修改后重启PostgreSQL服务:
systemctl restart postgresql
3. 排查网络与数据库连通性
- 用
mtr工具持续测试应用服务器到PostgreSQL服务器的网络路径,排查是否存在丢包或延迟波动:
mtr <PostgreSQL服务器IP>
- 确认
pg_hba.conf已允许应用服务器IP访问,并且postgresql.conf中listen_addresses设置为*或应用服务器IP:
# pg_hba.conf添加规则 host opencve opencve_user <应用服务器IP>/32 scram-sha-256 # postgresql.conf设置监听地址 listen_addresses = '*'
- 手动测试批量插入:在应用服务器用
psql连接数据库,执行模拟批量插入,验证是否超时:
INSERT INTO vendors (id, created_at, updated_at, name) SELECT gen_random_uuid(), now(), now(), 'test_vendor_' || generate_series(1, 10000);
4. 升级依赖版本
Python3.6与旧版sqlalchemy、psycopg2可能存在兼容性问题,尝试升级依赖:
pip install --upgrade psycopg2-binary sqlalchemy
若服务器环境允许,建议升级Python到3.8及以上版本,OpenCVE对高版本Python的兼容性和稳定性更好。
5. 应急手动导入方案
如果上述方法均无效,可绕过OpenCVE的批量插入逻辑,手动导入数据:
- 修改
cpe.py添加导出逻辑,将解析后的厂商数据保存为CSV:
import csv with open('/tmp/vendors.csv', 'w', newline='') as f: writer = csv.writer(f) writer.writerow(['id', 'name']) for vendor in mappings["vendors"].values(): writer.writerow([vendor['id'], vendor['name']])
- 执行
opencve import-data触发数据解析与导出,然后终止进程 - 用PostgreSQL的
COPY命令批量导入CSV:
COPY vendors (id, name) FROM '/tmp/vendors.csv' WITH (FORMAT csv, HEADER); UPDATE vendors SET created_at = now(), updated_at = now() WHERE created_at IS NULL;
COPY命令是PostgreSQL原生批量导入方式,效率远高于executemany,几乎不会触发超时。
内容的提问来源于stack exchange,提问作者Scouse_Bob

