[數據庫] 多線程連接數據庫報錯問題


用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!\n";
               exit(1);
          }
          if (!$pid) {
               $redis = PRedis::getInstance();
               // do something     
               exit;
          }
     }

在R的doParallel下,我對多線程的理解是,針對每一個i, 系統新建一個線程。

也就意味着,在for之前的環境,子線程是拷貝過來的,不同子線程的環境一致;for之后的環境,不同子線程是各自獨立的環境,調用$redis = PRedis:getInstance()應該生成的是不同的實例。

如果上面的作者說的是對的,即for之前和之后的環境,不同子線程的環境都是一致的,則多線程都是使用的同一個連接。所以會出錯。(????)

問題是,這時候不應該報 too many connections的錯誤啊,明明就只有一個connection。

不知道怎么回事....還是找時間回頭好好研究下多線程的執行原理算了。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM