2013-06-16 47 views
18

Tôi biết rằng Nút không bị chặn nhưng tôi nhận ra rằng hành vi mặc định của http.listen(8000) có nghĩa là tất cả các yêu cầu HTTP được xử lý một lần. Tôi biết tôi không nên ngạc nhiên về điều này (đó là cách cổng làm việc), nhưng nó làm cho tôi nghiêm túc tự hỏi làm thế nào để viết mã của tôi để tôi có thể xử lý nhiều, yêu cầu HTTP song song.Xử lý nhiều yêu cầu HTTP song song trong Node.js

Vì vậy, cách tốt nhất để viết máy chủ để nó không hog cổng 80 và phản hồi dài hạn không dẫn đến hàng đợi yêu cầu dài là gì?

Để minh họa sự cố, hãy thử chạy mã bên dưới và tải nó lên trong hai tab trình duyệt cùng một lúc.

var http = require('http'); 
http.createServer(function (req, res) { 
    res.setHeader('Content-Type', 'text/html; charset=utf-8'); 
    res.write("<p>" + new Date().toString() + ": starting response"); 
    setTimeout(function() { 
     res.write("<p>" + new Date().toString() + ": completing response and closing connection</p>"); 
     res.end(); 
    }, 4000); 
}).listen(8080); 
+1

http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/ – Paul

Trả lời

14

Bạn hiểu nhầm cách thức hoạt động của nút. Đoạn mã trên có thể chấp nhận các kết nối TCP từ hàng trăm hoặc hàng ngàn máy khách, đọc các yêu cầu HTTP, và sau đó đợi thời gian chờ 4000 ms bạn đã nướng trong đó, và sau đó gửi các câu trả lời. Mỗi khách hàng sẽ nhận được phản hồi trong khoảng 4000 + một số lượng nhỏ mili giây. Trong thời gian đó setTimeout (và trong bất kỳ hoạt động I/O) nút có thể tiếp tục xử lý. Điều này bao gồm việc chấp nhận các kết nối TCP bổ sung. Tôi đã thử nghiệm mã của bạn và mỗi trình duyệt đều nhận được phản hồi trong 4 giây. Cái thứ hai KHÔNG mất 8s, nếu đó là cách bạn nghĩ nó hoạt động.

Tôi chạy curl -s localhost:8080 trong 4 tab càng nhanh như tôi có thể thông qua bàn phím và giây trong timestamps là:

  1. 54 để 58
  2. 54-58
  3. 55-59
  4. 56 đến 00

Không có vấn đề gì ở đây, mặc dù tôi có thể hiểu bạn có thể nghĩ như thế nào. Nút sẽ hoàn toàn bị hỏng nếu nó hoạt động như bài đăng của bạn được đề xuất.

Dưới đây là một cách khác để xác minh:

for i in 1 2 3 4 5 6 7 8 9 10; do curl -s localhost:8080 &;done                                          
+5

Bạn là chính xác. Chrome đang làm việc đó. Đối với tôi ít nhất, yêu cầu thứ hai sẽ không được ban hành cho đến khi yêu cầu đầu tiên được trả lại. – Andrew

+0

Thậm chí chrome thường cho phép tối đa 6 kết nối đồng thời trên mỗi gốc. –

+1

Tôi biết. Đó là lý do tại sao tôi đã rất ngạc nhiên và cho rằng đó là Node. – Andrew

3

Mã của bạn có thể chấp nhận nhiều kết nối vì công việc được thực hiện trong hàm callback của cuộc gọi setTimeout.

Nhưng nếu bạn thay vì setTimeout làm một công việc nặng nhọc ... thì đúng là node.js sẽ không chấp nhận nhiều kết nối khác! SetTimeout vô tình giải phóng quá trình để node.js có thể chấp nhận các công việc khác và mã của bạn được thực thi trong "chuỗi" khác.

Tôi không biết đó là cách chính xác để thực hiện việc này. Nhưng đây là cách nó hoạt động.

0

tôi đã sử dụng đoạn mã sau để kiểm tra yêu cầu xử lý

app.get('/', function(req, res) { 
    console.log('time', MOMENT()); 
    setTimeout(function() { 
    console.log(data, '   ', MOMENT()); 
    res.send(data); 
    data = 'changing'; 
    }, 50000); 
    var data = 'change first'; 
    console.log(data); 
}); 

Kể từ khi yêu cầu này không mất nhiều thời gian chế biến, trừ 50 giây của setTimeout và tất cả các time-out được xử lý với nhau như thường làm.

đáp ứng 3 yêu cầu together-

time moment("2017-05-22T16:47:28.893") 
change first 
time moment("2017-05-22T16:47:30.981") 
change first 
time moment("2017-05-22T16:47:33.463") 
change first 
change first   moment("2017-05-22T16:48:18.923") 
change first   moment("2017-05-22T16:48:20.988") 
change first   moment("2017-05-22T16:48:23.466") 

Sau này tôi chuyển sang giai đoạn thứ hai ... ví dụ, nếu yêu cầu của tôi phải mất rất nhiều thời gian để xử lý một tập tin đồng bộ hóa hoặc một số điều khác mà mất thời gian.

app.get('/second', function(req, res) { 
    console.log(data); 
    if(req.headers.data === '9') { 
     res.status(200); 
     res.send('response from api'); 
    } else { 
     console.log(MOMENT()); 
     for(i = 0; i<9999999999; i++){} 
     console.log('Second MOMENT', MOMENT()); 
     res.status(400); 
     res.send('wrong data'); 
    } 

    var data = 'second test'; 
}); 

Vì yêu cầu đầu tiên của tôi vẫn đang được xử lý nên lần thứ hai của tôi không được Node chấp nhận. Vì vậy tôi đã nhận sau phản ứng của 2 request-

undefined 
moment("2017-05-22T17:43:59.159") 
Second MOMENT moment("2017-05-22T17:44:40.609") 
undefined 
moment("2017-05-22T17:44:40.614") 
Second MOMENT moment("2017-05-22T17:45:24.643") 

Như vậy Đối với tất cả các chức năng Async theres a thread ảo trong Node và Node không chấp nhận yêu cầu khác trước khi hoàn tất yêu cầu trước async làm việc tương tự (fs, mysql, hoặc gọi API), tuy nhiên nó giữ nó tự như một sợi đơn và không xử lý yêu cầu khác cho đến khi tất cả các yêu cầu trước đó được hoàn tất.

1

Trình duyệt chặn các yêu cầu tương tự khác. Nếu bạn gọi nó từ các trình duyệt khác nhau thì điều này sẽ làm việc song song.

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