Node JS sẽ chạy code như nào khi nhận nhiều request một lúc?

bạn có thể giải thích rõ. ở đây cái này là tác vụ IO? cái này là task? và cho task vào queue nghĩa là gì, có ý nghĩa gì? task khác ở đây là gì?

cách bạn giải thích cũng mơ hồ y như kiến thức của bạn

5 Likes

Mình nói là xử lý cùng lúc mà. :smiley:
Còn khi 100 cái request cùng đến server thì nó vẫn sẽ phải accept() từng cái một chứ. :kissing:

5 Likes

đoạn này bạn nói hơi rối, mình hơi khó hiểu

cảm ơn mọi người đã trả lời câu hỏi của mình

kiến thức mình hạn chế, mình chỉ biết vậy thôi, không thể giải thích sâu hơn, 2 câu hỏi mình hỏi cũng đã dc giải quyết, nhưng vấn đề phát sinh ở đây ko phải là run trên nhiều process nữa, mà ở 1 process thực sự node js sẽ giải quyết đồng thời nhiều request đến như nào, nếu bạn hiểu chi tiết kiến trúc node js xử lý đồng thời nhiều request theo từng bước như nào thì bạn có thể góp ý và chia sẻ, mình có search/research google vấn đề này, thì tài liệu họ giải thích không đầy đủ và tài liệu chính chủ không có đề cập.

Hi @iloveprogramming,

Disclaimer: tớ không phải chuyên gia về NodeJS.

Trong NodeJS, tất cả các event (các request gửi tới server NodeJS cũng là event) sẽ được đưa vào Event queue.
NodeJS có một đơn vị gọi là Event Loop (đơn vị này single-thread, và đây chính là “main thread” mà cậu nói tới). Event Loop sẽ check liên tục Event queue, và xử lý lần lượt từng event một một cách đồng bộ.
Dưới đây là lịch làm việc của event loop, trích từ câu trả lời này:

request ──> make database request
request ──> make database request
request ──> make database request
(callback) database request complete ──> send response
(callback) database request complete ──> send response
(callback) database request complete ──> send response

Database request là task đắt đỏ, nó sẽ được xử lý bởi 1 đơn vị khác, gọi là Worker pool (a.k.a thread pool). Vậy nên, khi ai đó nói NodeJS là single-thread, họ thực ra nói tới Event loop là single thread, chứ không nói tất cả chương trình NodeJS chỉ có 1 thread nhé! :smile:
Do đó, event loop không bị block ở Event loop (do nó chỉ nhận request, và xử lý khi response trả về, task bị block sẽ được 1 thread ở Worker pool làm hộ rồi), với 100 request event tới, Event loop có thể dễ dàng xử lý từng request một mà không ai phải chờ ai, dù nó chỉ có 1 thread. Khi đó, CPU sẽ được tận dụng tối đa.
Hiển nhiên, nếu bất cứ event nào cần tính toán phức tạp, Event Loop sẽ bị block khi xử lý event đó, dẫn tới các event còn lại bị dồn và phải chờ. Đó là vấn đề chính khiến NodeJS không thể được dùng để xử lý các business logic phức tạp (a.k.a mỗi request cần nhiều CPU để thực hiện logic tính toán), cần tính toán nhiều.

Về phần này:

Toàn bộ đoạn code dưới đây của cậu:

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

// Đăng ký logger
app.use(myLogger)

// Đăng ký handler callback, được thực thi khi có request tới / endpoint
app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

Cậu có thể thấy toàn bộ đoạn code này chỉ:

  • Đăng ký logger callback.
    Cậu muốn nói với app “Nếu có bất cứ thứ gì cần log trong app, gọi tới handler callback này nhé”
  • Đăng ký request handler callback.
    Cậu muốn nói với app “Nếu có bất cứ request gì tới / endpoint, gọi tới handler callback này nhé”
  • Bảo app lắng nghe ở port 3000.

Đây chỉ là code setup (hay config) thuần túy, hẳn nhiên nó chỉ thực hiện lúc khởi tạo app thôi. Đó là ý mà @Sherly1001 đề cập :smile:
Nó cũng trả lời chính xác cho câu hỏi đầu tiên của cậu:

Khi request tới, do app đã biết khi có request tới / endpoint, nó sẽ gọi tới 1 handler xác định, nên chỉ handler code được gọi thôi.

Hope it helps!

See also:

10 Likes

nếu bạn hiểu, thì dù câu cú có không tốt, thì vẫn sẽ trả lời hay hơn, so với việc bạn chỉ trả lời chung chung, vô tưởng vô phạt như vậy
ở trên mình thấy bạn nói, cái gì bạn cũng đã học qua, làm qua và trông có vẻ như những cái đó khá phức tạp mà bạn vẫn hiểu
trong khi câu của mình chỉ có settimeout và console nhưng bạn lại không giải thích được
nếu bạn có kiến thức về asynchonous, event loop, job queue bla bla, mà vẫn vẫn trả lời theo cái cách như vậy, thì bạn mong đợi câu trả lời như thế nào cho topic của bạn
thâm chí là Sherly trả lời chi tiết hơn nhưng bạn lại không chấp nhận câu trả lời, cũng không chấp nhận là bạn thiếu kiến thức

Xin phép được quote lại câu này của @Sherly1001
Có thể là bạn có học, có đọc qua, nhưng bạn tự cho là mình hiểu (có thể là vì ví dụ lúc bạn học/đọc nó quá đơn giản)

Sau những câu xàm xàm trên thì mình trở lại câu hỏi mình đã đặt.
Với ở góc độ của người lập trình, đơn vị nhỏ nhất để thực thi chính là “statement (expression)”, hay mình còn gọi là câu lệnh.
Bài toán đặt ra là câu lệnh nào trước, câu lệnh nào sau, và vì sao một triệu dòng console đó nó chạy 1s mới xong, nhưng cái settimeout 0s nó không chen vào được

Ví dụ thực tế: Xếp hàng
Có 1000003 ông đứng xếp hàng để nộp hồ sơ

  • lượt ông đầu tiên, người nhận hồ sơ nói, hồ sơ của ông này chưa đủ điều kiện, về bổ sung, next
  • 500k ông tiếp theo được xử lý vì hợp lệ
  • thêm một ông giống với ông đầu tiên
  • 500k ông tiếp theo hợp lệ
  • ông cuối cùng lại không đủ điều kiện

câu hỏi đặt ra, mấy cái ông có hồ sơ không hợp lệ, cần bổ sung, họ có thể bổ sung trong vòng 0s luôn (giả sử họ là siêu nhân) thì sao?
ông tiếp tân nhận hồ sơ cũng nhanh y như vậy, chưa hợp lệ là chưa hợp lệ, ổng không muốn đợi, kể cả 0s, chỉ hợp lệ hay không, chỉ có yes/no, không có chờ gì cả
nên cái ông có hồ chưa hợp lệ đó bị đá ra khỏi hàng mà gọi người kế tiếp

dù ổng có thể cập nhật hồ sơ trong vòng 0s, nhưng ổng không thể chen vào cái hàng đang xếp (1 triệu lẻ 2 người còn lại trong hàng), có mà bị đấm chứ ở đó mà chen
nên dù cho ổng có nhanh cỡ nào, thì ổng cũng đã bị đưa vào cuối hàng đợi rồi
tương tự với 2 cái ông kia cũng bị reject và phải xếp hàng lại

đoạn code trên của mình cũng có cơ chế y như vậy
settimeout 0s hơi tào lao thật, nhưng nó vẫn có ý nghĩa, và trong thực tế, người ta vẫn sử dụng (mình ghét mấy câu hỏi không thực tế), mục đích là để đưa các lệnh của hàm callback trong settimeout đưa vào cuối hàng đợi (chờ mấy thứ khác xong hết mới chạy)

bonus cho bạn thêm 1 câu đoạn code, thử đoán, chạy và giải thích

// hàm này trả về result sau thời gian wait milisecond
const runAfter1s = (result, wait) => new Promise(ff => setTimeout(() => ff(result), wait))

async function ahihi() {
    console.log('before');
    const result = await runAfter1s(1, 1000); // chờ 1s và trả về 1
    console.log(result);
    console.log('after');
}

console.log('start');
ahihi(); // trong thực tế, người ta vẫn khai báo async nhưng không có dùng kèm await nhé, để nó code trong hàm nó đẹp hơn, hoặc người ta có thể gọi hàm và .then
console.log('end');
9 Likes

@library @kisuluoibieng @Sherly1001
hi các Bạn
đêm qua mình đã research 2 bài viết về event loop , 1 thứ minh họa là code server lắng nghe request, còn 1 thứ là chỉ chạy 1 đoạn code nhỏ, nên mỗi bài viết lại nói event loop theo cách khác nhau nên phát sinh thắc mắc vì vậy mình sẽ đưa lên đây hỏi mọi người ạ
mình có 1 vài thắc mắc sau ạ:
bài viết 1 thì họ nói rằng


khi request tới sẽ đưa vào event queue, họ sẽ phân loại request , request nào có tác vụ đọc ghi db( gọi là task I/O) thì sẽ cho thread pool xử lý, còn request không có tác vụ blocking I/O thì đưa vào event loop xử lý.

1 bài viết thứ 2 mình đọc thì, ở đây họ minh họa 1 đoạn code nho nhỏ, chứ không phải code server.

const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");

bar();
foo();
baz();

.

mình có 6 thắc mắc sau ạ:
1. event queue ở ảnh 1 và task queue ở ảnh 2 có phải là 1 không? queue chứa event hay nó chứa hàm callback của event?
2. event loop khi thực thi code server ( tức lắng nghe request) và event loop khi thực thi 1 đoạn code giống hay khác nhau, nếu khác nhau thì ở điểm gì?

3. event loop bên trong nó gồm những thành phần gì:
theo như ảnh 2 thì khi thực 1 đoạn code thì nó gồm 3 phần: web API/System API ( các hàm setTimeOut(), SetInterval() thuộc về webAPi/SystemAPI ), callstack và queue, hay nếu nó chỉ là cái ký hiệu vòng xoáy (tracker) theo dõi callstack, queue thì ở ảnh 1 tại sao không có callstack?

4. Có 4 thread trong 1 thread pool theo mặc định, mỗi thread này bản thân nó có riêng 1 event loop cho nó không?
5. Các request chứa tác vụ đọc ghi db phải gửi qua thread tạm gọi là thread t1 trong thread pool xử lý, giả sử quá trình đọc ghi db kết thúc thì hàm callback của sự kiện đọc ghi, lúc này sẽ do main thread thực thi code hay do chính thread t1 ở thread pool thực thi?
6. các controller làm đa số đều có phải đọc ghi db, trường hợp có 5 request đều yêu cầu đọc ghi db, mà chỉ có 4 thread trong 1 thread pool, như vậy giả sử có 5 request cùng lúc thì request thứ 5 sẽ ở đâu?

hy vọng các Bạn có thể giúp mình trả lời 6 thắc mắc 1 cách chi tiết và trực tiếp ạ, mình cảm kích, cảm ơn và đánh giá cao các Bạn giúp mình trả lời 6 thắc mắc này!

lưu ý nhỏ, để clear thì mình nói rõ thêm câu từ mình viết : “thực thi” tức là excute đoạn code được được pop khỏi stack và run luôn.
https://www.journaldev.com/7462/node-js-architecture-single-threaded-event-loop
https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif

2 Likes

Quào :sweat_smile:

Disclaimer: tớ không phải chuyên gia về Node JS.

2 event queue đó là một.
Nếu cậu đọc tài liệu chính chủ tớ đã đưa cho cậu ở comment trước, cậu sẽ đọc được đoạn này:

In truth, the Event Loop does not actually maintain a queue. Instead, it has a collection of file descriptors that it asks the operating system to monitor, using a mechanism like epoll (Linux), kqueue (OSX), event ports (Solaris), or IOCP (Windows). These file descriptors correspond to network sockets, any files it is watching, and so on. When the operating system says that one of these file descriptors is ready, the Event Loop translates it to the appropriate event and invokes the callback(s) associated with that event. You can learn more about this process here.

Trong đó nói rõ: Event loop maintain một tập các file descriptor được theo dõi bởi hệ điều hành. Các file descriptor này có thể là network sockets, bất cứ file nào đang được theo dõi, v.v. Khi HĐH nói rằng file descriptor đó đã sẵn sàng, event loop sẽ dịch nó thành các event và gọi các hàm callback liên quan tới event đó.
Cậu có thể nghe thêm chi tiết về event loop ở đây.

Loằng ngoằng quá đúng không? :smile: Để cho đơn giản, cậu chỉ cần hiểu các event sẽ được đặt trong queue (thế nên nó được gọi là event queue, không phải mafia queue - queue chứa mafia, werewolf queue - queue chứa người sói). Các event đó được hiểu bao gồm cả các callback liên quan tới event đó.

Hử?
Đó là 2 trạng thái khác nhau của event loop đúng không? Trạng thái idle (khi queue empty) và trạng thái active (khi có task cần được thực thi)?

Hử?
Event loop chỉ là 1 vòng lặp mà cậu :smile: Giống như cách cậu code bất cứ hệ thống Event driven nào khác, cậu cần 1 vòng lặp vô hạn để xử lý event.
Theo như tài liệu chính chủ về event loop mà tớ đã cung cấp ở comment trước, cậu nên hiểu rõ Event loop là 1 vòng lặp có nhiều phase khác nhau.
Cái call stack kia là thành phần của runtime environment (a.k.a v8 engine), giống như tất cả các ngôn ngữ khác, ở runtime cậu có call stack để track hàm nào được gọi, với các parameter nào, và khi gọi xong thì quay lại hàm nào. Cậu có thể học thêm về compiler để hiểu thêm về call stack.
Queue ở ảnh 1 không có call stack, đơn giản vì article đó tập trung vào hoạt động của event loop ở mức high level. Ở ảnh 2, article đó muốn nói sâu hơn về những gì hoạt động trong runtime environment, đặc biệt là cách callback được gọi, nên call stack được liệt kê ở đây.

Nope. Worker pool là đơn vị khác, nó chỉ có queue riêng của nó thôi. Lại từ tài liệu chính chủ mà tớ đã đưa cho cậu:

In contrast, the Worker Pool uses a real queue whose entries are tasks to be processed. A Worker pops a task from this queue and works on it, and when finished the Worker raises an “At least one task is finished” event for the Event Loop.

Event loop (a.k.a main thread) sẽ thực thi callback đó. Nếu cậu đọc kỹ quote ở ngay trên của tớ về Worker Pool, cậu sẽ hiểu.

Request thứ 5 sẽ phải chờ trong worker’s pool queue, cho tới khi một worker được assign task thực hiện cho request thứ 5.

Hope it helps!

7 Likes

trước khi trả lời thì mình nói thêm về cái ví dụ về xếp hàng để nộp hồ sơ cho người tếp nhận ở trên
Mỗi request của bạn, sẽ có nhiều lệnh, mỗi lệnh tương ứng với một ông trong hàng đợi
Các ông này đi theo nhóm, có thể nhóm 1 người, 2 người hay n người, hiển nhiên các ông đi theo nhóm thì sẽ xếp hàng liên tục với nhau, như thế này

1 1 1 1 2 2 3 4 4 4 4 4 5 6 7 7 8

4 ông nhóm 1, 2 ông nhóm 2, 1 ông nhóm 3
Mỗi request của bạn sẽ có thể thực hiện 1 hoặc nhiều lệnh tương ứng với các ông xếp hàng, ví dụ request 1 có 4 lệnh như trên

Ở đây ta chỉ có 1 ông tiếp tân, tiếp nhận yêu cầu (process here của cái hình 1)
khi tiếp nhận yêu cầu của mấy ông nhóm 1, thì có cái ông thứ 3 của nhóm (in đậm) chưa thể xử lý được cho ổng, thế là ông tiếp tân quăng cái yêu cầu của ông thứ 3 (lệnh thứ 3 của request 1) cho bộ phận khác giải quyết và tiếp nhận ông kế tiếp
còn cái ông thứ 3 bị đưa cho bên khác bổ sung hồ sở xong, thì ông thứ 3 qua lấy, lúc này thì ổng phải ra cuối hàng

nhưng mà 4 ông này có thể chơi rất thân nhau, nên ông thứ 4 muốn đợi ông thứ 3 luôn, tức là đang muốn 4 ông này đúng thứ tự, thì buộc lòng ông 4 phải đợi ông 3 xong (await ở lệnh 3, hoặc lệnh 3 rồi then lệnh 4…)
và hiển nhiên là tiếp tân mời ông kế tiếp là ông đầu tiên của nhóm 2 lên làm việc

hình số 2 không có ghi kèm chú thích rõ ràng, hơn nữa có web api thì cái này đang nói đến js của browser, nhưng về idea hay cơ chế thì đúng

Lắng nghe request thì không phải là thực thi, ít nhất nó không phải là cái cục bự “process here” ở hình 1
“event loop khi thực thi” ý bạn nói là thực thi event (handle event) ? nếu đúng là vậy thì cũng sai luôn, không phải thực thi, handle event nghĩa là pick up cái event để, sau đó xử lý từng lệnh theo phân loại (isBlocking ở trên)

pick up ở đây giống như mời 4 ông nhóm 1 của ví vụ bên trên,
ông 1.1 và 1.2 ok, tới ông 1.3 thì ổng cần bổ sung hồ sơ,
ông 1.4 thì không muốn làm trước ông 1.3 nên quyết định đợi, thể là 2 ông ra cuối hàng, ông 1.1 và 1.2 xong rồi nhưng cùng chưa về (request 1 chưa end)
nhưng tiếp tân thì không đợi, đành kêu ông 2.1 lên, và cứ thế

  1. Event loop chỉ là cái tên người ta gọi nó vì cái cơ chế của nó (thì cũng là do người ta code ra thôi)
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
    giờ bạn hỏi nó gồm cái gì thì cũng giống như bạn hỏi settimeout có gì ở trong đó, code như nào, cơ chế đếm ra sao…
    ảnh cũng chỉ là mô tả, cũng chỉ là cách mô tả khác nhau, ở ảnh 1 thì các nó nằm trong phần process here là cái nào tới process here chính là callstack

không, và không liên quan đến thread chính của node nữa
4 thread mà bạn nói ý có lẽ là thread được các thư viện của platfom nó gọi, lúc này thì nó không còn là gì nữa rồi
khi mà các thread này done nhiệm vụ, nó sẽ raise một cái event về cho node, mà khi node gọi nó đã đăng kí. ví dụ:

unlink('/tmp/hello', (err) => {
  if (err) throw err;
  console.log('successfully deleted /tmp/hello');
});

// ở đây, node gọi thư viện bên dưới (fs) để xóa file, và nó đăng kí một cái event handler, khi xóa xong thì thì bên dưới raise event mà chính cái handler lúc nãy handle

như trên, thực thi xong thì bắn cái event vô hàng đợi event queue (và mỗi event thì có handler của nó) (dù ông 1.3 chỉ cần 0s để hoàn thành, nhưng ổng cũng phải ra phía sau cuối hàng)

không có cái gọi là controller ở đây
nếu nói về cơ chế thread pool thì lúc này đã vượt qua vấn đề của js, bạn nên học lại về os/ process/ thread
bạn không tự can thiệp được chuyện thread pool nó làm gì ở dưới đâu
bạn chỉ kếu nó chạy, chạy xong thì gọi lại cho bạn mà thôi

Ban đầu khi đối đáp với @Sherly1001 , bạn nói cái gì bạn cũng học qua, thậm chí làm qua, nhưng khi đọc 6 câu hỏi này của bạn, mình thấy có vẻ như bạn đang ngộ nhân kiến thức của mình giải thích được những ví dụ phổ thông (hoặc giống với ví dụ của những bài bạn đã đọc)

bạn nên dành nhiều thời gian hơn để thí nghiệm, và kiểm chứng kiến thức mà bạn cho rằng bạn đã thu được, mà nodejs là opensource, bạn có thể vào đọc source code để hiểu thêm

bài này mục đích không phải để vả vào mặt bạn, vì ai cũng sẽ có lúc như vậy, tưởng mình biết tất cả, nhưng chỉ là phần nổi của tảng băng
kiến thức của mình cũng từng có lúc giống bạn, trong quá trình làm việc, mình tự thí nghiệm để kết hợp với lý thuyết mà ra thôi

2 đoạn code ví dụ trên của mình, bạn sẽ không thể tìm thấy ở bất kì đâu vì đó là do mình trong quá trình làm việc mà nhận thấy vấn đề, nên mới viết ra để hỏi các bạn còn mơ hồ (hơi nổ tí =)), đoạn code cũng bình thường, nhưng có thể chọt đúng chỗ ngứa của nhiều bạn chưa vững)
nhưng có lẽ là bạn không hứng thú với những ví dụ đó, nên thôi, mình cũng chỉ chia sẻ tới đây mà thôi
kiến thức hàn lâm như bạn đã đọc thì search là ra thôi, nên bạn có thể search các trang khác, hoặc post câu hỏi lên stackoverflow, nơi đó sẽ có nhiều cao thủ hơn, hoặc có khi là contributor của nodejs giải đáp cho bạn

còn một điều nữa, là bạn đang học nodejs, bất đồng bộ của nodejs, không nên focus vào express hay framework khác thì cũng chỉ là code javascript/nodejs mà thôi

10 Likes

Nghe các cao nhân đàm đạo với nhau thích quá. Nhưng mình thấy ví dụ của bạn giống bài viết này của digitalOcean https://www.digitalocean.com/community/tutorials/understanding-the-event-loop-callbacks-promises-and-async-await-in-javascript.amp

Chỗ setTimeout 0

Đang xem youtube tình cờ gặp ngay ví dụ setTimeout bằng 0 của bác bên trên

P/S: sẵn tiện cho em hỏi có web hay nền tảng nào làm trắc nghiệm kiểu như này. Cảm ơn!

Các bác cho em hỏi, em đã học basic javascript rồi, em muốn tìm hiểu những cái basic, cốt lõi của nodejs thì học ở đâu ạ? Code expressJS, nestJS thì em code ra được sản phẩm chạy thực tế rồi mà không hiểu cách hoạt động bên trong nó.

Bắt đầu bằng việc đọc hiểu hết các comments bên trên, không hiểu chỗ nào r mới hỏi nhé.

4 Likes

Trong commnet trước em có nghe tới từ process. Đó có phải là process này không?

Một tiến trình có riêng một không gian địa chỉ, có ngăn xếp (stack) riêng rẽ, có bảng chứa các đặc tả tập tin (file descriptor)

Ý là đang nói đến việc mỗi process được một luồng xử lý riêng, được cấp cho một stack, heap riêng đúng không ạ? Như trong topic này:

Cho em hỏi vòng lặp này có gì khác với vòng lặp của cậu bé này trình bày ạ?

=>> Vậy đáp án cuối cùng của topic này là:
Server sẽ xử lý tuần tự 1000 request, có thể do CPU quá mạnh nên cảm giác 1000 request này xử lý song song nhưng thực ra request thứ 1000 xử lý cuối cùng. Nếu có tool đo thời gian thì request thứ 1000 được xử lý cách request thứ 1 một khoảng thời gian nào đó phải không? Ý em muốn hỏi về cách server tiếp nhận request thôi (lúc mới vừa đưa task vào bộ nhớ stack á) chứ chưa bàn đến chuyện xử lý request đó sau khi đã tiếp nhận và gọi callback khi đã có kết quả chuẩn bị response

Đúng là v, nhưng được đưa vào xử lý cuối cùng không có nghĩa là req thứ 1000 sẽ được xử lý xong cuối cùng. :kissing:

Đâu cần tool gì, bạn dựng 1 cái server trả về thới gian khi mà có req đến về cho client. Bên client gọi 1000 cái req liên tục, log ra kết quả của req 1 và req 1000 r tự so sánh được mà. :v :V

Ý bạn là làm sao mà server nhận được req từ client? Muốn tìm hiểu sâu hơn thì hãy đọc thử về TCP socket nhé.

4 Likes

Câu trả lời của bạn ở trong đây:

2 Likes

Chào quý anh chị,

  1. Theo em thì nodeJS xử lý C10K request cũng không khác gì xử lý 10K dòng console.log cả. Tất cả lần lượt được đưa vào bộ nhớ stack và thực thi tuần tự theo cơ chế LIFO. 10K dòng console.log sẽ in ra màn hình gần như đồng thời và ngay lập tức(có thể delay 0,0000…01s). Ví dụ in ra 10K dòng console có thể khiến CPU tốn thêm 20%, 30% sau đó quay về mức ban đầu, thì xử lý 10K request http cũng tương tự vậy.
  2. Nhưng tại sao lúc quý anh chị gửi 10K request mà server không response ngay lập tức như thực thi 10K dòng console.log? thực ra bên trong nodejs đã “xử lý xong bước đầu” 10K request này rồi, chỉ là nó đưa qua qua bộ phận khác xử lý tiếp - bộ phận này là queue (thường là micotask queue vì sử dụng promise) nên quý anh chị phải CHỜ ĐỢI server có kết quả sau đó server sẽ truyền kết quả này vào đối số của callback và response data về client cho quý anh chị. Còn việc server lấy kết quả ở đâu ra để trả về thì em sẽ giải thích sau. VD: khi quý anh chị nộp 10K đơn tố cáo - khiếu nại lên bộ phận một cửa của UBND phường. Cán bộ tiếp nhận 10K hồ sơ, đóng mộc, ký tên trong vòng 1 nốt nhạc là xong. Còn 10K hồ sơ đó có được thụ lý hay không, kết quả là gì thì anh chị phải CHỜ ĐỢI.
  3. Chúng ta cùng phân tích từ CHỜ ĐỢI: chờ đợi có 2 loại là chờ tốn CPU (lấy CPU đại diện cho tài nguyên, có thể tốn kém thêm GPU và linh kiện khác) và chờ đợi không tốn CPU.
    • Chờ đợi tốn CPU gồm các task: xử lý ảnh, render video, encrypt, decrypt, … những task này khiến máy tính bị lag, task nặng thì phải chờ, chờ vì CPU đang vất vả render, muốn không chờ thì scale máy chủ theo chiều dọc, mua CPU khác, mua thêm RAM, lắp thêm GPU. Golang xử lý được vấn đề này, còn nodeJS thì không.
    • Chờ đợi không tốn CPU - đây là cách nodeJS chờ đợi. Nghĩa là đã ủy quyền task đó cho bên khác làm thay. Có 2 ví dụ:
      – user request lấy dữ liệu trong database, mà nodejs và database là 2 thực thể khác nhau, nodejs yêu cầu database đưa data, nodejs không quan tâm database làm như thế nào, miễn sao có data trả về cho nodejs là được. Muốn database xử lý nhanh thì database phải thiết kế chạy đa luồng hay như nào đó, vậy nên nodeJS đã tận dụng được sức mạnh đa luồng của server database. Giả dụ như database cùng trả về 10K response ngay lập tức thì như nào? thì nó quay về bài toán xử lý 10K request, 10K console.log như ban đầu, nodejs response tuần tự về cho client 10K kết quả gần như ngay lập tức (dùng bộ nhớ stack và LIFO giải thích như trên)
      – Tương tự khi khi xử lý request thanh toán thì nodeJS tiếp tục call API tới ngân hàng và chờ ngân hàng response về. trong lúc này server nodeJS không làm gì cả. Mức tiêu thụ CPU là một đường ngang chứ không nhảy như đo điện tâm đồ (ECG) trong bênh viện.

:arrow_right: Có thể hiểu vui như này: NodeJS tiếp nhận 10K request, xử lý như nào đó rồi ủy quyền nó cho bên khác (server database) xử lý tiếp. Trong lúc chờ thì có thể tắt server nodeJS, rút cắm điện, đóng cầu dao. Khi nào database gọi điện “Alo, có phải nodeJS không ạ, em đến giao 10K data, anh chị ra trước cổng nhận giúp”, thì lúc này ông devOps mới bật cầu dao lên, mở server lên nhận data của database đưa rồi response về cho client.

:writing_hand: Theo quan điểm cá nhân của em thì nodejs rất thích hợp làm backend cho app với lõi business bên trong là một nồi lẩu thập cẩm, call API tá lả, bên trong chả làm gì cả: thanh toán thì call API của ngân hàng, giao hàng thì call API cty chuyển phát, lưu trữ file thì call API dịch vụ Object storage (AWS, azure,…), eKYC thì API các cty AI,… tích hợp đủ các kiểu. NodeJS xử lý cơ bản rồi nằm đắp chăn, rung đùi chờ bên khác còng lưng xử lý mà không quên kèm theo thông báo “Khi nào làm xong thì alo cho anh, để anh chạy callback nhé”

Bản thân em không code nodejs nhiều, cũng đang có thắc mắc: Nếu một CPU 10 core chỉ chạy môi trường nodeJS, thì nodeJS có làm 9 core còn lại nhảy số như điện tâm đồ ECG không hay chỉ đè đầu 1 core mà bắt node làm 10K task khiến nó lúc nào cũng trong trạng thái 80%, 90%?

Quý anh chị nếu quan tâm có thể phản biện lại em, rất mong được quý anh chị chia sẻ kiến thức và quan điểm!

Trường hợp của bạn là 10k request diễn ra 1 lần, theo mình hiểu thì VD trong 1 mili giây server nhận một lượt 10K request, 10K request đưa vào stack, rồi 10K task đó được đưa qua queue chờ result (event loop chờ stack rỗng rồi mới thực thi kết quả của 10K task đó). Nhưng mình thấy phát sinh vấn đề: VD: client cứ gửi request liên tục khiến stack không bao giờ rỗng, event loop cứ chờ stack rỗng để thực thi các result của task đang chờ bên queue nhưng stack bận xử lý request của client rồi thì làm sao xử lý result của các task trước đó được.

Tại sao bạn lại cho rằng request được add vào stack nên event loop phải chờ stack rỗng thì mới thực thi kết quả. Bạn đang đồng nhất stack của JS (tầng ngôn ngữ) và stack của server (tầng ứng dụng).
Tại sao không phải là add request vào queue chờ xử lý. Khi đến lượt thì sẽ tiến hành xử lí, nếu cần đợi kq thì lại add vào queue chờ tiếp…

4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?