2016-11-08 44 views
10

Bối cảnh: Tôi đến từ thế giới của Microsoft, trong đó tôi đã từng có các trang web được lưu trữ trên IIS. Kinh nghiệm đã dạy tôi để tái chế hồ bơi ứng dụng của tôi một lần một ngày để loại bỏ các vấn đề lạ do sự phân mảnh. Tái chế nhóm ứng dụng về cơ bản có nghĩa là khởi động lại ứng dụng của bạn mà không cần khởi động lại toàn bộ IIS. Tôi cũng đã xem một bài giảng giải thích cách Microsoft đã giảm phân mảnh rất nhiều trong .Net 4.5.Node.js và phân mảnh

Bây giờ, tôi đang triển khai một ứng dụng Node.js vào môi trường sản xuất và tôi phải đảm bảo rằng nó hoạt động hoàn hảo mọi lúc. Ban đầu tôi nghĩ để làm cho ứng dụng của tôi khởi động lại một lần một ngày. Sau đó, tôi đã thực hiện một số nghiên cứu để tìm ra một số manh mối về các vấn đề phân mảnh trong Node.js. Điều duy nhất tôi đã tìm thấy là một mảnh đoạn từ an article describing GC in V8:

Để đảm bảo phân bổ nhanh đối tượng, tạm dừng thu gom rác thải ngắn, và “không phân mảnh bộ nhớ V8” sử dụng một stop-the-thế giới, thế hệ, chính xác, thu gom rác thải.

Tuyên bố này thực sự không đủ để tôi từ bỏ việc xây dựng cơ chế khởi động lại cho ứng dụng của mình, nhưng mặt khác tôi không muốn thực hiện một số công việc nếu không có sự cố.

Vì vậy quesion của tôi là:

Nên hay không nên tôi khởi động lại ứng dụng của tôi tất cả bây giờ và sau đó để ngăn chặn sự phân mảnh?

Trả lời

11

Thực hiện khởi động lại máy chủ trước khi bạn biết rằng mức tiêu thụ bộ nhớ thực sự là một vấn đề là tối ưu hóa sớm. Như vậy, tôi không nghĩ bạn nên làm điều đó cho đến khi bạn thực sự thấy rằng đó là một vấn đề. Bạn có thể sẽ tìm thấy các vấn đề quan trọng hơn để tối ưu hóa thay vì mức tiêu thụ bộ nhớ.

Để tìm hiểu xem bạn cần phải khởi động lại máy chủ, tôi khuyên bạn nên làm như sau:

  1. Thiết lập một số công cụ giám sát như https://newrelic.com/ cho phép màn hình của bạn hiệu suất của bạn.
  2. Giám sát bộ nhớ của bạn liên tục. Hãy thử để xem nếu có sự gia tăng ổn định trong số lượng bộ nhớ tiêu thụ, hoặc nếu nó giảm.
  3. Quyết định ngưỡng chấp nhận được trước khi bạn cần hành động. Ví dụ: khi ứng dụng của bạn tiêu thụ 60% bộ nhớ hệ thống, bạn cần bắt đầu suy nghĩ về máy chủ khởi động lại và quyết định khoảng thời gian khởi động lại.
  4. Quyết định xem bạn có đồng ý "ngừng hoạt động" trong khi khởi động lại máy chủ hay không. Nếu bạn không muốn thời gian chết, bạn có thể cần phải xây dựng một lớp proxy để hướng lưu lượng truy cập.

Nói chung, tôi khuyên bạn nên khởi động lại máy chủ cho tất cả ngôn ngữ động, được thu thập rác. Điều này là khá phổ biến trong các loại ứng dụng lớn. Nó là gần như không thể tránh khỏi rằng một sai lầm nhỏ ở đâu đó trong cơ sở mã của bạn, hoặc một trong các thư viện mà bạn phụ thuộc vào sẽ bị rò rỉ bộ nhớ. Ngay cả khi bạn sửa chữa một rò rỉ, bạn sẽ nhận được một số cuối cùng. Điều này có thể làm hỏng nhóm của bạn, về cơ bản sẽ dẫn đến chính sách khởi động lại máy chủ và định nghĩa về những gì có thể chấp nhận được liên quan đến mức tiêu thụ bộ nhớ cho ứng dụng của bạn.

+1

phải rõ ràng, bạn nên khởi động lại máy chủ VỚI theo dõi, phải không? Tôi có trải nghiệm xấu với các ứng dụng khởi động lại ở cấp cao hơn có vấn đề mà không có bất kỳ loại thông tin nào về lý do tại sao họ có những vấn đề này để nó vẫn là trò chơi đoán. –

+1

@CorvusCrypto Tôi khuyên bạn nên theo dõi trước. Và sau đó quyết định xem có cần khởi động lại máy chủ hay không. – Parris

+0

Cảm ơn bạn đã trả lời chi tiết. Tôi có hai câu hỏi: 1. Làm thế nào có thể rò rỉ bộ nhớ xảy ra trong một ngôn ngữ mã được quản lý? Afaik rò rỉ bộ nhớ xảy ra khi bạn không phát hành phân bổ bộ nhớ mà bạn không sử dụng nữa; nhưng trong một ứng dụng mã được quản lý, mọi đối tượng bạn không có tham chiếu đến nữa đều được GC giải phóng. (Câu hỏi thứ 2 nằm trong bình luận tiếp theo). – Alon

3

Tôi đồng ý với @Parris. Bạn có lẽ nên tìm hiểu xem bạn thực sự cần có một chính sách khởi động lại đầu tiên. Tôi sẽ đề nghị sử dụng pm2 docs here. Ngay cả khi bạn không muốn đăng ký keymetrics, nó là một trình quản lý quy trình khá tốt và thực sự nhanh chóng thiết lập.Bạn có thể nhận báo cáo sử dụng bộ nhớ từ dòng lệnh. Trông như thế này

pm2 output

Ngoài ra, nếu bạn bắt đầu trong chế độ cụm như trên, bạn có thể gọi pm2 restart my_app và là người đầu tiên có thể sẽ được lên một lần nữa trước khi người cuối cùng được thực hiện ẩn (đây là một lợi ích bổ sung, lý do thực để có 8 quy trình là sử dụng tất cả 8 lõi). Nếu bạn kiên quyết về thời gian chết, bạn có thể khởi động lại chúng 1 theo 1 theo id.

2

Tôi đồng ý với @Parris điều này có vẻ như một tối ưu hóa sớm. Ngoài ra, khởi động lại không phải là một giải pháp cho vấn đề cơ bản, đó là một điều trị cho các triệu chứng.

Nếu lỗi bộ nhớ là vấn đề phổ biến đối với ứng dụng nút của bạn thì tôi nghĩ rằng một số người nghĩ tại sao sự phân mảnh này xảy ra trong chương trình của bạn ngay từ đầu có thể là một nỗ lực quý giá. Hiểu được lý do tại sao lỗi bộ nhớ xảy ra sau khi chương trình đã chạy trong một thời gian dài, và tái cấu trúc kiến ​​trúc chương trình của bạn để giải quyết gốc rễ của vấn đề, là giải pháp tốt hơn trong mắt hơn là chỉ giải quyết các triệu chứng.

Tôi tin rằng hai điều sẽ mang lại lợi ích cho bạn.

  1. immutable objects sẽ giúp rất nhiều, họ có rất nhiều dự đoán hơn sử dụng đối tượng có thể thay đổi, và sẽ không bị ảnh hưởng bởi độ dài thời gian dự án đã được sống. Ngoài ra, vì các đối tượng bất biến chỉ đọc các khối bộ nhớ chúng nhanh hơn các đối tượng có thể thay đổi được nên máy chủ phải chi tiêu tài nguyên để quyết định có đọc hay ghi vào khối bộ nhớ lưu trữ đối tượng hay không. Tôi hiện đang sử dụng thư viện có tên là IMMUTABLE và nó hoạt động tốt cho tôi. Có một người khác cũng như Deep Freeze, tuy nhiên, tôi chưa bao giờ sử dụng nó.

  2. Đảm bảo quản lý đúng quy trình của ứng dụng, rò rỉ bộ nhớ là đóng góp lớn thứ hai cho vấn đề này mà tôi đã gặp phải. Một lần nữa, điều này được giải quyết bằng cách suy nghĩ về cách ứng dụng của bạn được cấu trúc và cách các sự kiện của người dùng được xử lý, đảm bảo một khi quá trình không được khách hàng sử dụng để xử lý đúng cách khỏi heap, nếu không phải là heap giữ phát triển cho đến khi tất cả bộ nhớ được tiêu thụ khiến ứng dụng gặp sự cố (tham khảo đồ họa bên dưới để xem Sơ đồ bộ nhớ của V8 và vị trí của heap). Node là một chương trình C++, và nó được điều khiển bởi V8 và Javascript của Google.

V8 memory Scheme

Bạn có thể sử dụng sử dụng bộ nhớ process.memoryUsage() theo dõi Node.js của. Khi bạn xác định làm thế nào để quản lý heap V8 của bạn cung cấp hai giải pháp, một là Scavenge đó là rất nhanh chóng, nhưng không đầy đủ. Khác là Mark-Sweep chậm và giải phóng tất cả bộ nhớ không tham chiếu.

Tham khảo this bài đăng blog để biết thêm về cách quản lý đống của bạn và quản lý bộ nhớ của bạn trên V8 chạy Node.js

Vì vậy, cách tiếp cận có trách nhiệm thực hiện của bạn là để giữ một mắt đóng trên quá trình mở, một sự hiểu biết sâu sắc về heap và cách giải phóng các khối bộ nhớ không tham chiếu. Tạo dự án của bạn với điều này trong tâm trí cũng làm cho dự án nhiều hơn nữa khả năng mở rộng là tốt.

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