2013-02-14 17 views
15

Tôi có một ứng dụng Node truy cập cấu trúc dữ liệu tĩnh, lớn (> 100M), phức tạp, trong bộ nhớ, chấp nhận truy vấn và sau đó phân phát các lát nhỏ dữ liệu đó cho máy khách qua HTTP.Có cách nào để chia sẻ bộ nhớ giữa các công nhân/chủ đề/điều gì đó trong Node.JS không?

Hầu hết các truy vấn có thể được trả lời sau mười giây. Hoan hô cho Node!

Tuy nhiên, đối với một số truy vấn nhất định, việc tìm kiếm cấu trúc dữ liệu này sẽ mất vài giây. Điều này hút bởi vì mọi người khác phải chờ đợi.

Để phục vụ khách hàng hiệu quả hơn, tôi muốn sử dụng một số loại tính song song.

Nhưng, vì cấu trúc dữ liệu này quá lớn, tôi muốn chia sẻ nó giữa các công nhân hoặc chủ đề hoặc những gì có bạn, vì vậy tôi không ghi hàng trăm megabyte. Điều này sẽ hoàn toàn an toàn, bởi vì cấu trúc dữ liệu sẽ không được ghi vào. Một điển hình 'ngã ba()' trong bất kỳ ngôn ngữ khác sẽ làm điều đó.

Tuy nhiên, theo như tôi có thể nói, tất cả các cách tiêu chuẩn để thực hiện song song trong Node rõ ràng làm cho điều này là không thể. Vì sự an toàn, họ không muốn bạn chia sẻ bất cứ điều gì.

Nhưng có cách nào không?

Bối cảnh:

Đó là không thực tế để đặt cấu trúc dữ liệu này trong một cơ sở dữ liệu, hoặc sử dụng memcached, hoặc bất cứ điều gì như thế.

Thư viện API WebWorker và tương tự chỉ cho phép gửi các thông điệp tuần tự ngắn vào và ra khỏi công nhân.

Cụm nút của Node sử dụng một cuộc gọi có tên là 'ngã ba', nhưng nó không thực sự là một nhánh của quá trình hiện tại, nó tạo ra một cái mới. Vì vậy, một lần nữa, không có bộ nhớ chia sẻ.

Có lẽ câu trả lời thực sự đúng là sử dụng quyền truy cập giống như hệ thống tập tin vào bộ nhớ dùng chung, còn gọi là tmpfs hoặc mmap. Có một số thư viện nút mà làm cho mount() và mmap() có sẵn cho chính xác một cái gì đó như thế này. Thật không may sau đó người ta phải thực hiện truy cập cấu trúc dữ liệu phức tạp trên đầu trang của tìm kiếm đồng bộ và đọc. Ứng dụng của tôi sử dụng mảng mảng ma trận và vân vân. Nó sẽ là tốt đẹp để không phải reimplement tất cả những điều đó.

+0

Bạn không thể làm trống tìm kiếm của mình (sử dụng 'process.nextTick' có lẽ) để nó không chặn phần còn lại? – robertklep

+3

'Việc đặt cấu trúc dữ liệu này trong cơ sở dữ liệu là không thực tế, hoặc sử dụng memcached, hoặc bất cứ thứ gì như thế.' Cái gì ?? Kể từ khi? – freakish

+0

freakish: Chúng tôi đang kiểm tra xem mỗi mục là một tập con của truy vấn. Hãy tưởng tượng chúng ta có một chuỗi "fooquux", và chúng ta muốn kiểm tra xem "ox" có nằm trong chuỗi đó không. Không có cách nào mà tôi biết để làm điều đó một cách hiệu quả với các hoạt động cơ sở dữ liệu thông thường. Nhưng nó rất dễ dàng nếu bạn có quyền truy cập vào nó như một cấu trúc dữ liệu thông thường. Sau đó, một số lượng lớn trong số này được sắp xếp và xếp hạng và đây là "con trỏ" cho nhiều dữ liệu hơn, một lần nữa không thực tế trừ khi chúng ta có chúng trong một cấu trúc dữ liệu. – NeilK

Trả lời

0

tòa nhà có waf là kiểu cũ (nút 0,6 trở xuống), bản dựng mới là bằng gyp.

Bạn nên xem cụm nút (http://nodejs.org/api/cluster.html). Không rõ ràng điều này sẽ giúp bạn mà không có thêm chi tiết, nhưng điều này chạy nhiều quá trình nút trên cùng một máy bằng cách sử dụng ngã ba.

+1

Cụm không thực sự ngã ba - nó chỉ là sinh sản một quy trình mới. Lý do tại sao tôi muốn ngã ba là để chia sẻ bộ nhớ mà tôi biết là không thay đổi và sẽ không được thay đổi bởi các trẻ em. – NeilK

+2

Ngay từ mục bạn đã liên kết tới: "Các nút con này vẫn là phiên bản hoàn toàn mới của V8. Giả sử ít nhất 30ms khởi động và bộ nhớ 10mb cho mỗi Nút mới. Tức là, bạn không thể tạo hàng nghìn nút." Và trong trường hợp của tôi, tôi phải tải> 100MB vào mỗi. – NeilK

+0

@NeilK> 100MB không phải là một vấn đề lớn (trừ khi> 100MB bạn hiểu 10GB: D). Điều quan trọng hơn là giữ cho dữ liệu đó được đồng bộ giữa các phiên bản. Tôi khuyên bạn nên sử dụng máy chủ chuyên dụng để lưu dữ liệu đó. Xem câu trả lời của tôi. – freakish

0

Thực tế, Node không hỗ trợ quá trình sinh sản. Tôi không chắc chắn cách gần ngã ba Node là đến bàn ăn thật, nhưng bạn có thể thử nó:

http://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options

Bằng cách này: nó không phải là sự thật rằng Node là không phù hợp cho điều đó. Nó phù hợp với bất kỳ ngôn ngữ/máy chủ web nào khác. Bạn luôn có thể kích hoạt nhiều phiên bản máy chủ của mình trên các cổng khác nhau và đặt proxy ở phía trước.

Nếu bạn cần thêm bộ nhớ - hãy thêm bộ nhớ. :) Nó đơn giản như vậy. Ngoài ra, bạn nên suy nghĩ về việc đưa tất cả dữ liệu đó vào một cơ sở dữ liệu trong bộ nhớ chuyên dụng như Redis hoặc Memcached (hoặc thậm chí Couchbase nếu bạn cần các truy vấn phức tạp). Bạn sẽ không phải lo lắng về việc sao chép dữ liệu đó nữa.

+2

Đọc tài liệu bạn vừa liên kết với tôi đến. Tất cả các cách để kết thúc. :) Ngoài ra, mặc dù có thể có một số quy trình với bản sao của cấu trúc dữ liệu 100M ở mức ngân sách khiêm tốn, tôi đang thực hiện dự án này với dự án miễn phí Heroku dyno, có giới hạn 512 MB. Có hai công nhân thổi ngân sách bộ nhớ của tôi, và Heroku tắt nó đi. Nhưng quan trọng hơn, lãng phí bộ nhớ như thế này xúc phạm tôi. – NeilK

+0

Um và vì sợ bạn nghĩ rằng tôi không thể làm số học, trong thực tế cấu trúc dữ liệu là 208 MB - 100 MB là một ví dụ – NeilK

+0

@NeilK Nhưng giới hạn 512MB không xúc phạm bạn? : D Bên cạnh đó: ngay cả với quá trình con ngã ba cũng sao chép dữ liệu trừ khi nó chỉ đọc. – freakish

5

Tôi đã thử viết một ràng buộc C/C++ về quyền truy cập bộ nhớ chia sẻ từ nút. https://github.com/supipd/node-shm

Vẫn đang hoạt động (nhưng đang hoạt động cho tôi), có thể hữu ích, nếu có lỗi hoặc đề xuất, thông báo cho tôi.

+0

Đây là một ý tưởng tuyệt vời @supipd, nhưng bạn có thể làm việc này trên phiên bản hiện tại không? Tôi tin rằng 'node :: ObjectWrap' không được liên kết với' 'trong các phiên bản mới hơn. (người dùng sẽ nhận được lỗi khi biên dịch) Dù sao thì đây cũng là câu trả lời được chấp nhận. :) –

0

Hầu hết các ứng dụng web dành phần lớn thời gian chờ đợi bộ đệm mạng và đọc cơ sở dữ liệu. Node.js được thiết kế để vượt trội ở công việc io này. Nếu công việc của bạn thực sự bị ràng buộc bởi CPU, bạn có thể được phục vụ tốt hơn bởi một nền tảng khác.

Với điều đó ra khỏi con đường ...

  1. Sử dụng process.nextTick (thậm chí khối lồng nhau) để đảm bảo rằng công việc CPU đắt là đúng cách không đồng bộ và không được phép để chặn chủ đề của bạn. Điều này sẽ đảm bảo một khách hàng thực hiện các yêu cầu đắt tiền không ảnh hưởng tiêu cực đến tất cả các yêu cầu khác.

  2. Sử dụng cụm node.js để thêm quy trình công nhân cho từng CPU trong hệ thống. Quá trình công nhân tất cả có thể liên kết với một cổng HTTP duy nhất và sử dụng Memcached hoặc Redis để chia sẻ trạng thái bộ nhớ. Công nhân cũng có một API nhắn tin có thể được sử dụng để giữ một bộ nhớ cache trong bộ nhớ đồng bộ, tuy nhiên nó có một số hạn chế nhất quán.