2014-06-20 22 views
10

Tôi đang sử dụng Node.js - async & mô-đun yêu cầu để thu thập thông tin hơn 100 triệu trang web và tôi tiếp tục gặp phải lỗi ESOCKETTIMEDOUT & ETIMEDOUT sau vài phút.Node.js GET Yêu cầu ETIMEDOUT & ESOCKETTIMEDOUT

Nó hoạt động trở lại sau khi tôi khởi động lại tập lệnh. Nó không có vẻ là vấn đề giới hạn kết nối vì tôi vẫn có thể làm resolve4, resolveNs, resolveMx và cũng curl không chậm trễ.

Bạn có thấy bất kỳ sự cố nào với mã không? hoặc lời khuyên nào? Tôi muốn đẩy đồng thời async.queue() lên ít nhất là 1000. Cảm ơn bạn.

var request = require('request'), 
    async = require('async'), 
    mysql = require('mysql'), 
    dns = require('dns'), 
    url = require('url'), 
    cheerio = require('cheerio'), 
    iconv = require('iconv-lite'), 
    charset = require('charset'), 
    config = require('./spy.config'), 
    pool = mysql.createPool(config.db); 

iconv.skipDecodeWarning = true; 

var queue = async.queue(function (task, cb) { 
    dns.resolve4('www.' + task.domain, function (err, addresses) { 
     if (err) { 
      // 
      // Do something 
      // 
      setImmediate(function() { 
       cb() 
      }); 
     } else { 
      request({ 
       url: 'http://www.' + task.domain, 
       method: 'GET', 
       encoding:  'binary', 
       followRedirect: true, 
       pool:   false, 
       pool:   { maxSockets: 1000 }, 
       timeout:  15000 // 15 sec 
      }, function (error, response, body) { 

       //console.info(task); 

       if (!error) { 
        // If ok, do something 

       } else { 
        // If not ok, do these 

        console.log(error); 

        // It keeps erroring here after few minutes, resolve4, resolveNs, resolveMx still work here. 

        // { [Error: ETIMEDOUT] code: 'ETIMEDOUT' } 
        // { [Error: ESOCKETTIMEDOUT] code: 'ESOCKETTIMEDOUT' } 

        var ns = [], 
         ip = [], 
         mx = []; 
        async.parallel([ 
         function (callback) { 
          // Resolves the domain's name server records 
          dns.resolveNs(task.domain, function (err, addresses) { 
           if (!err) { 
            ns = addresses; 
           } 
           callback(); 
          }); 
         }, function (callback) { 
          // Resolves the domain's IPV4 addresses 
          dns.resolve4(task.domain, function (err, addresses) { 
           if (!err) { 
            ip = addresses; 
           } 
           callback(); 
          }); 
         }, function (callback) { 
          // Resolves the domain's MX records 
          dns.resolveMx(task.domain, function (err, addresses) { 
           if (!err) { 
            addresses.forEach(function (a) { 
             mx.push(a.exchange); 
            }); 
           } 
           callback(); 
          }); 
         } 
        ], function (err) { 
         if (err) return next(err); 

         // do something 
        }); 

       } 
       setImmediate(function() { 
        cb() 
       }); 
      }); 
     } 
    }); 
}, 200); 

// When the queue is emptied we want to check if we're done 
queue.drain = function() { 
    setImmediate(function() { 
     checkDone() 
    }); 
}; 
function consoleLog(msg) { 
    //console.info(msg); 
} 
function checkDone() { 
    if (queue.length() == 0) { 
     setImmediate(function() { 
      crawlQueue() 
     }); 
    } else { 
     console.log("checkDone() not zero"); 
    } 
} 

function query(sql) { 
    pool.getConnection(function (err, connection) { 
     if (!err) { 
      //console.log(sql); 
      connection.query(sql, function (err, results) { 
       connection.release(); 
      }); 
     } 
    }); 
} 

function crawlQueue() { 
    pool.getConnection(function (err, connection) { 
     if (!err) { 
      var sql = "SELECT * FROM domain last_update < (UNIX_TIMESTAMP() - 2592000) LIMIT 500"; 
      connection.query(sql, function (err, results) { 
       if (!err) { 
        if (results.length) { 
         for (var i = 0, len = results.length; i < len; ++i) { 
          queue.push({"id": results[i]['id'], "domain": results[i]['domain'] }); 
         } 
        } else { 
         process.exit(); 
        } 
        connection.release(); 
       } else { 
        connection.release(); 
        setImmediate(function() { 
         crawlQueue() 
        }); 
       } 
      }); 
     } else { 
      setImmediate(function() { 
       crawlQueue() 
      }); 
     } 
    }); 
} 
setImmediate(function() { 
    crawlQueue() 
}); 

Và giới hạn hệ thống là khá cao.

Limit      Soft Limit   Hard Limit   Units 
    Max cpu time    unlimited   unlimited   seconds 
    Max file size    unlimited   unlimited   bytes 
    Max data size    unlimited   unlimited   bytes 
    Max stack size   8388608    unlimited   bytes 
    Max core file size  0     unlimited   bytes 
    Max resident set   unlimited   unlimited   bytes 
    Max processes    257645    257645    processes 
    Max open files   500000    500000    files 
    Max locked memory   65536    65536    bytes 
    Max address space   unlimited   unlimited   bytes 
    Max file locks   unlimited   unlimited   locks 
    Max pending signals  257645    257645    signals 
    Max msgqueue size   819200    819200    bytes 
    Max nice priority   0     0 
    Max realtime priority  0     0 
    Max realtime timeout  unlimited   unlimited   us 

sysctl

net.ipv4.ip_local_port_range = 10000 61000 
+0

lý do hồ bơi (theo yêu cầu) được đặt hai lần? – dandavis

+0

Nó là để vô hiệu hóa các hồ bơi. Tôi vẫn nhận được các lỗi, có hoặc không có hồ bơi và các maxSockets. –

+7

bạn có thể tìm ra nguyên nhân không? – Cmag

Trả lời

7

Theo mặc định, Node có 4 workers to resolve DNS queries. Nếu truy vấn DNS của bạn mất thời gian dài, yêu cầu sẽ chặn trên pha DNS và triệu chứng chính xác là ESOCKETTIMEDOUT hoặc ETIMEDOUT.

Hãy thử tăng uv kích thước hồ bơi thread của bạn:

export UV_THREADPOOL_SIZE=128 
node ... 

hoặc trong index.js (hoặc bất cứ nơi nào điểm vào của bạn là):

#!/usr/bin/env node 
process.env.UV_THREADPOOL_SIZE = 128; 

function main() { 
    ... 
} 

I reproduced this locally bằng cách làm chậm các phản hồi từ máy chủ DNS bằng tc.

+0

tôi có cùng một vấn đề, nhưng cách giải quyết này không làm việc cho tôi. Bất kỳ ý tưởng? –

+0

Không làm việc cho tôi. – 3zzy

2

Tôi gặp vấn đề tương tự. Nó được giải quyết bằng cách sử dụng "agent: false" trong tùy chọn yêu cầu sau khi đọc this discussion.

10/31/2017 Ở trên dường như không hoàn thành giải quyết được sự cố. Giải pháp cuối cùng mà chúng tôi tìm thấy là sử dụng tùy chọn keepAlive trong một tác nhân. Ví dụ:

var pool = new https.Agent({ keepAlive: true }); 

function getJsonOptions(_url) { 
    return { 
     url: _url, 
     method: 'GET', 
     agent: pool, 
     json: true 
    }; 
} 

Hồ bơi mặc định của nút có vẻ mặc định là keepAlive = false tạo kết nối mới trên mỗi yêu cầu. Khi quá nhiều kết nối được tạo trong một khoảng thời gian ngắn, lỗi trên sẽ xuất hiện. Tôi đoán là một hoặc nhiều bộ định tuyến dọc theo đường dẫn đến dịch vụ chặn yêu cầu kết nối, có thể là do nghi ngờ tấn công từ chối dịch vụ. Trong mọi trường hợp, mẫu mã trên hoàn toàn giải quyết được vấn đề của chúng tôi.

Các vấn đề liên quan