zoukankan      html  css  js  c++  java
  • [数据库] 多线程连接数据库报错问题

    用R语言使用多线程对数据库进行批量插入操作。脚本在windows下运行正常,但是放到linux服务器上跑的时候,就出现了错误。

    错误信息如下:

     task 63246 failed - "Failed to connect to database: Error: Can't connect to MySQL server on '192.168.01.30' (107)

    有点懵逼。

    猜想可能是数据库连接数过大的原因。

    但并不清楚windows和linux下什么差异会导致一个正常,一个不正常的情况。

    如果是使用多线程造成的错误,想来这个问题,应该很多人会碰到。

    网上搜了一下,大致想到三个可能的方案:

    1. 增加数据库最大连接数量。

    这不一定奏效,具体看第三点。如果根本原因如第三点所说,那就不是数据库最大连接数的限制了。

    因为更改后可能要重启服务器,懒,所以没有实际验证。

    另外感觉这个问题应该是通过从代码角度去改善的,一味修改服务器的配置的话,随着任务数的增加,终究还是会碰到瓶颈。

    这里只是提出一个想法。尽管我认为非常low,不过万不得已的时候也可以试试。

    2. 在代码里增加错误控制。

      这个问题在其他语言下面应该是一个比较好实现的方式。

      只是在R语言下,让我有点无从下手。原因在于R语言的异常处理有点low? 例如如何判断连接是否存在,对R语言来说好像不知从何实现?

    3. 参考:【php爬虫】百万级别知乎用户数据爬取与分析 -> 使用PHP的pcntl扩展实现多进程 -> 多进程编程中Redis和MySQL连接问题

      看不太明白它的解决方案。只是感觉应该是跟我一样的问题。

      这里贴一下原文:

    根本原因是在各个子进程创建时,就已经继承了父进程一份完全一样的拷贝。对象可以拷贝,但是已创建的连接不能被拷贝成多个,由此产生的结果,就是各个进程都使用同一个redis连接,各干各的事,最终产生莫名其妙的冲突。
    
    解决方法:
    
    程序不能完全保证在fork进程之前,父进程不会创建redis连接实例。因此,要解决这个问题只能靠子进程本身了。试想一下,如果在子进程中获取的实例只与当前进程相关,那么这个问题就不存在了。于是解决方案就是稍微改造一下redis类实例化的静态方式,与当前进程ID绑定起来。

      具体代码可以跳转原文链接。

     ----------------------160510 17:21 更新--------------------------------

      关于方案3,仔细看了下他的代码。发现之前我对多线程包的执行方式或许理解有误。

      考虑如下代码:

    for ($i = 0; $i < 10; $i++) {
              $pid = pcntl_fork();
              if ($pid == -1) {
                   echo "Could not fork!
    ";
                   exit(1);
              }
              if (!$pid) {
                   $redis = PRedis::getInstance();
                   // do something     
                   exit;
              }
         }

    在R的doParallel下,我对多线程的理解是,针对每一个i, 系统新建一个线程。

    也就意味着,在for之前的环境,子线程是拷贝过来的,不同子线程的环境一致;for之后的环境,不同子线程是各自独立的环境,调用$redis = PRedis:getInstance()应该生成的是不同的实例。

    如果上面的作者说的是对的,即for之前和之后的环境,不同子线程的环境都是一致的,则多线程都是使用的同一个连接。所以会出错。(????)

    问题是,这时候不应该报 too many connections的错误啊,明明就只有一个connection。

    不知道怎么回事....还是找时间回头好好研究下多线程的执行原理算了。。。

  • 相关阅读:
    Java Arrays.asList注意事项
    从给定的N个正数中选取若干个数之和最接近M
    java 8 foreach获取索引
    更优雅地关闭资源
    idea 下获取路径下文件的方法
    IDEA类和方法注释模板设置(非常详细)
    503 Error: need EHLO and AUTH first
    fatal error C1083: Cannot open include file: 'openssl/opensslv.h'
    'pip' 不是内部或外部命令
    JS中every()和some()的用法
  • 原文地址:https://www.cnblogs.com/oDoraemon/p/5477836.html
Copyright © 2011-2022 走看看