该帖子有点长哈...不好意思
是这样,这是一个爬虫项目的主程序入口,下面代码里面的 mongo_cOnnection= mongo_connect( cOnnect= False, server_selection_timeoutMS = 60000 )
用来连接数据库,但我在服务器上测试的时候发现一直提示 timeout 报错(详见上面的报错信息)
我查了不少文章,看到不少说是要在多进程开启后再给每一个进程连接 mongoDB ,所以一开始我将连接数据库的代码放到了三个爬取程序的开头(就是下文那三个 parser() 函数),但依旧报同样的错; 然后我在 GitHub 上面看到了一个关于多进程下 Pymongo 提示 UserWarning 的解答,里面提到了可以添加 cOnnect= False 参数,但我试过还是不行,应该问题也不在这里; 然后我又修改了 serverSelectionTimeoutMS ,将时间改为 60 秒(嗯当然还是没用)
求大佬指点一下怎么在使用 concurrent.futures 开启多进程的情况下连接 mongoDB!谢谢!
下面贴了环境、报错信息和代码
CentOS 7.8.2003
python = 3.7.7
依赖包版本:
pymOngo== 4.0.1
concurrent:Python 自带
该信息来源于日志
ERROR: 192.168.1.202:27017: timed out, Timeout: 60.0s, Topology Description: <TopologyDescription id: 622086a8ea6efc1d07de056f, topology_type: Unknown, servers: [<ServerDescription ('192.168.1.202', 27017) server_type: Unknown, rtt: None, error=NetworkTimeout('192.168.1.202:27017: timed out')>]>
import pymongo from concurrent.futures import PoolProcessExecutor, as_completed # 导入外部自定义模块 import ... def run_spider(log_recorder, proxy): """ 主程序,可启动目标网页的爬取程序 :param log_recorder: 日志记录工具 :param proxy: 项目专用代理 :return: """ log_recorder.info( "Spider starts running! :)" ) try: # 连接数据库 mongo_cOnnection= mongo_connect( cOnnect= False, server_selection_timeoutMS = 60000 ) try: # 主程序运行 council_parser( mongo_connection, log_recorder, proxy ) gd_province_parser( mongo_connection, log_recorder, proxy ) market_supervisor_parser( mongo_connection, log_recorder, proxy ) log_recorder.info( "Spider ran over! :)" ) # 爬取结束后断开数据库连接 mongo_connection.close() except Exception as e: log_recorder.error(f"{e} :(") # 出现异常依然断开连接 mongo_connection.close() except Exception as e: log_recorder.error(f"{e}:(") if __name__ == "__main__": # 设置日志工具 regulation_logger = spiderLogger.get_logger('regulation') # 设置代理 proxy = get_proxy() # 多进程并发 with ProcessPoolExecutor(max_workers = 8) as executor: fs = [] futures = executor.submit(run_spider, regulation_logger, proxy) fs.append(futures) for future in as_completed(fs): result = future.result()
mongo_connent方法代码:
def mongo_connect(cOnnect= True, server_selection_timeoutMS: int = 60000): mongo_cOnnection= MongoClient( server = settings.DATABASES['mongodb']['HOST'], port = settings.DATABASES['mongodb']['PORT'], username = settings.DATABASES['mongodb']['USER'], password = settings.DATABASES['mongodb']['PASSWORD'], db = settings.DATABASES['mongodb']['db'], cOnnect= connect, serverSelectiOnTimeoutMS= server_selection_timeoutMS ) return mongo_connection
![]() | 1 fgwmlhdkkkw 2022-03-03 18:24:51 +08:00 ……你用命令行能连上数据库吗? |
![]() | 2 DesmondLeo OP @fgwmlhdkkkw 命令行可以 |
3 vvhhaaattt 2022-03-03 18:54:43 +08:00 via Android 我觉得先确认你不用多进程时,代码能正常连接不。 |
![]() | 4 ClericPy 2022-03-03 23:01:38 +08:00 1. mongo_connect 哪来的有点陌生, 这东西不好调试的话临时闭包到 run_spider 里测试一下? 怀疑有些变量传递到进程里面有地方不太对, 多进程类似于各种并行计算的一个特点就是: 尽量无状态无副作用, 里面的各种依赖 /参数 /上下文都尽量隔离干净 2. 本地调试可以运行但线上不行的话, 可能的地方特别多(难怪虚拟化和 go 那么火了) 2.1 最大可能是网络本身就不通(防火墙规则啊, 网卡 ip 不对啊, 非局域网啊, 非开放端口啊), 但是如果关了多进程会 ok, 网络应该不是问题. 可以临时把 PoolProcessExecutor 改成多线程那个, 反正接口一样的, 而且爬虫这玩意本来就没必要多进程 2.2 Python 版本有区别, 个别底层依赖有差异, 这个少见但也遇到过 2.3 第三方依赖的版本或者 C 依赖有差异, 尽量排除这种情况, 以前我遇到过类似情况, 换个版本居然就通了 2.4 检查是不是每个进程都超时, 有一定可能是程序里面或者 mongodb 那边有奇怪的死锁 |
![]() | 5 ch2 2022-03-03 23:30:34 +08:00 via iPhone 你都没有指定 host 跟 port ,让它去连啥啊 |
![]() | 6 dudu2017 2022-03-03 23:52:41 +08:00 mongo_connect 方法是你自己封装的吧,这里的代码是不是也应该贴一下? |
![]() | 7 DesmondLeo OP @vvhhaaattt 不用的时候可以 |
![]() | 8 DesmondLeo OP |
![]() | 9 DesmondLeo OP @ClericPy 啊好详细的回复,我昨天后来在排查的时候感觉应该是死锁(感觉),那个 ThreadProcessExecutor 昨天我也试过了,效果一样 2333 ,应该不是这个问题,我今天再看看怎么处理 |