Nodejs cụm pm2

Có nhiều công cụ của bên thứ ba có sẵn để định hình Node. js, nhưng trong nhiều trường hợp, tùy chọn đơn giản nhất là sử dụng Node. js tích hợp hồ sơ. Trình cấu hình tích hợp sử dụng trình cấu hình bên trong V8 để lấy mẫu ngăn xếp theo các khoảng thời gian đều đặn trong quá trình thực thi chương trình. Nó ghi lại kết quả của các mẫu này, cùng với các sự kiện tối ưu hóa quan trọng như biên dịch jit, dưới dạng một loạt dấu tích

code-creation,LazyCompile,0,0x2d5000a337a0,396,"bp native array.js:1153:16",0x289f644df68,~
code-creation,LazyCompile,0,0x2d5000a33940,716,"hasOwnProperty native v8natives.js:198:30",0x289f64438d0,~
code-creation,LazyCompile,0,0x2d5000a33c20,284,"ToName native runtime.js:549:16",0x289f643bb28,~
code-creation,Stub,2,0x2d5000a33d40,182,"DoubleToIStub"
code-creation,Stub,2,0x2d5000a33e00,507,"NumberToStringStub"

Trước đây, bạn cần mã nguồn V8 để có thể giải thích các dấu tích. May mắn thay, các công cụ đã được giới thiệu kể từ Node. js 4. 4. 0 tạo điều kiện thuận lợi cho việc sử dụng thông tin này mà không cần xây dựng riêng V8 từ nguồn. Hãy xem cách trình cấu hình tích hợp có thể giúp cung cấp thông tin chi tiết về hiệu suất của ứng dụng

Để minh họa việc sử dụng trình hồ sơ đánh dấu, chúng tôi sẽ làm việc với một ứng dụng Express đơn giản. Ứng dụng của chúng tôi sẽ có hai trình xử lý, một trình xử lý để thêm người dùng mới vào hệ thống của chúng tôi

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];

và một cái khác để xác thực các nỗ lực xác thực người dùng

app.get['/auth', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || !users[username]] {
    return res.sendStatus[400];
  }

  const { salt, hash } = users[username];
  const encryptHash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  if [crypto.timingSafeEqual[hash, encryptHash]] {
    res.sendStatus[200];
  } else {
    res.sendStatus[401];
  }
}];

Xin lưu ý rằng đây KHÔNG phải là những trình xử lý được đề xuất để xác thực người dùng trong Nút của bạn. js và được sử dụng hoàn toàn cho mục đích minh họa. Nói chung, bạn không nên cố gắng thiết kế các cơ chế xác thực mật mã của riêng mình. Sẽ tốt hơn nhiều nếu sử dụng các giải pháp xác thực đã được chứng minh hiện có

Bây giờ, giả sử rằng chúng tôi đã triển khai ứng dụng của mình và người dùng đang phàn nàn về độ trễ cao đối với các yêu cầu. Chúng tôi có thể dễ dàng chạy ứng dụng với trình cấu hình tích hợp

NODE_ENV=production node --prof app.js

và đặt một số tải lên máy chủ bằng cách sử dụng

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
2 [ApacheBench]

curl -X GET "//localhost:8080/newUser?username=matt&password=password"
ab -k -c 20 -n 250 "//localhost:8080/auth?username=matt&password=password"

và nhận được một đầu ra ab của

Concurrency Level:      20
Time taken for tests:   46.932 seconds
Complete requests:      250
Failed requests:        0
Keep-Alive requests:    250
Total transferred:      50250 bytes
HTML transferred:       500 bytes
Requests per second:    5.33 [#/sec] [mean]
Time per request:       3754.556 [ms] [mean]
Time per request:       187.728 [ms] [mean, across all concurrent requests]
Transfer rate:          1.05 [Kbytes/sec] received

...

Percentage of the requests served within a certain time [ms]
  50%   3755
  66%   3804
  75%   3818
  80%   3825
  90%   3845
  95%   3858
  98%   3874
  99%   3875
 100%   4225 [longest request]

Từ kết quả này, chúng tôi thấy rằng chúng tôi chỉ quản lý để phục vụ khoảng 5 yêu cầu mỗi giây và yêu cầu trung bình chỉ mất chưa đầy 4 giây cho chuyến đi khứ hồi. Trong một ví dụ thực tế, chúng ta có thể thực hiện nhiều công việc trong nhiều chức năng thay mặt cho yêu cầu của người dùng nhưng ngay cả trong ví dụ đơn giản của chúng ta, thời gian có thể bị mất khi biên dịch các biểu thức chính quy, tạo muối ngẫu nhiên, tạo các giá trị băm duy nhất từ ​​mật khẩu người dùng hoặc

Vì chúng tôi đã chạy ứng dụng của mình bằng cách sử dụng tùy chọn

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
3, một tệp đánh dấu đã được tạo trong cùng thư mục với lần chạy ứng dụng cục bộ của bạn. Nó phải có dạng
app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
4 [trong đó
app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
5 là một chữ số]

Để hiểu được tệp này, chúng ta cần sử dụng bộ xử lý tick đi kèm với Node. js nhị phân. Để chạy bộ xử lý, hãy sử dụng cờ

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
6

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
1

xử lý mở. txt trong trình soạn thảo văn bản yêu thích của bạn sẽ cung cấp cho bạn một số loại thông tin khác nhau. Tệp được chia thành các phần lại được chia theo ngôn ngữ. Đầu tiên, chúng ta nhìn vào phần tóm tắt và xem

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
2

Điều này cho chúng tôi biết rằng 97% tất cả các mẫu được thu thập xảy ra trong mã C++ và khi xem các phần khác của đầu ra được xử lý, chúng tôi nên chú ý nhất đến công việc được thực hiện trong C++ [trái ngược với JavaScript]. Lưu ý điều này, tiếp theo chúng ta tìm phần [C++] chứa thông tin về chức năng C++ nào đang chiếm nhiều thời gian của CPU nhất và xem

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
3

Chúng tôi thấy rằng 3 mục hàng đầu chiếm 72. 1% thời gian CPU của chương trình. Từ kết quả này, chúng tôi ngay lập tức thấy rằng ít nhất 51. 8% thời gian của CPU được sử dụng bởi một chức năng gọi là PBKDF2, tương ứng với việc tạo hàm băm của chúng tôi từ mật khẩu của người dùng. Tuy nhiên, có thể không rõ ràng ngay lập tức làm thế nào hai mục thấp hơn ảnh hưởng đến ứng dụng của chúng tôi [hoặc nếu có, chúng tôi sẽ giả vờ khác vì lợi ích của ví dụ]. Để hiểu rõ hơn về mối quan hệ giữa các chức năng này, tiếp theo chúng ta sẽ xem phần [Bottom up [heavy] profile] cung cấp thông tin về những người gọi chính của từng chức năng. Xem xét phần này, chúng tôi nhận thấy

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
4

Phân tích cú pháp phần này tốn nhiều công sức hơn một chút so với số lần đánh dấu thô ở trên. Trong mỗi "ngăn xếp cuộc gọi" ở trên, tỷ lệ phần trăm trong cột chính cho bạn biết tỷ lệ phần trăm mẫu mà hàm trong hàng ở trên được gọi bởi hàm trong hàng hiện tại. Ví dụ: trong "ngăn xếp cuộc gọi" ở giữa ở trên cho _sha1_block_data_order, chúng tôi thấy rằng

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
7 đã xảy ra trong 11. 9% mẫu mà chúng tôi biết từ số lượng thô ở trên. Tuy nhiên, ở đây, chúng ta cũng có thể nói rằng nó luôn được gọi bởi hàm pbkdf2 bên trong Nút. mô-đun mật mã js. Tương tự, chúng ta thấy rằng,
app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
8 hầu như chỉ được gọi bởi cùng hàm pbkdf2. Do đó, bằng cách sử dụng thông tin trong chế độ xem này, chúng tôi có thể nói rằng tính toán băm của chúng tôi từ các tài khoản mật khẩu của người dùng không chỉ cho 51. 8% từ trên xuống mà còn cho tất cả thời gian CPU trong 3 hàm được lấy mẫu nhiều nhất kể từ khi các lệnh gọi đến
app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
7 và
app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
8 được thực hiện thay mặt cho hàm pbkdf2

Tại thời điểm này, rất rõ ràng rằng việc tạo hàm băm dựa trên mật khẩu phải là mục tiêu tối ưu hóa của chúng tôi. Rất may, bạn đã tiếp thu đầy đủ các lợi ích của lập trình không đồng bộ và bạn nhận ra rằng công việc tạo hàm băm từ mật khẩu của người dùng đang được thực hiện theo cách đồng bộ và do đó thắt chặt vòng lặp sự kiện. Điều này ngăn chúng tôi làm việc với các yêu cầu đến khác trong khi tính toán hàm băm

Để khắc phục sự cố này, bạn thực hiện một sửa đổi nhỏ đối với các trình xử lý ở trên để sử dụng phiên bản không đồng bộ của hàm pbkdf2

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
0

Một lần chạy mới của điểm chuẩn ab ở trên với phiên bản không đồng bộ của ứng dụng của bạn mang lại

app.get['/newUser', [req, res] => {
  let username = req.query.username || '';
  const password = req.query.password || '';

  username = username.replace[/[[email protected]#$%^&*]/g, ''];

  if [!username || !password || users[username]] {
    return res.sendStatus[400];
  }

  const salt = crypto.randomBytes[128].toString['base64'];
  const hash = crypto.pbkdf2Sync[password, salt, 10000, 512, 'sha512'];

  users[username] = { salt, hash };

  res.sendStatus[200];
}];
1

vâng. Ứng dụng của bạn hiện đang phục vụ khoảng 20 yêu cầu mỗi giây, gấp khoảng 4 lần so với khi tạo hàm băm đồng bộ. Ngoài ra, độ trễ trung bình giảm từ 4 giây trước đó xuống chỉ còn hơn 1 giây

Hy vọng rằng thông qua việc điều tra hiệu suất của ví dụ [được thừa nhận là giả tạo] này, bạn đã thấy bộ xử lý đánh dấu V8 có thể giúp bạn hiểu rõ hơn về hiệu suất của Nút của mình như thế nào. ứng dụng js

Chủ Đề