2016-11-24 24 views
5

Tôi muốn sử dụng giám sát OTP của erlang trong một ứng dụng được phân phối mà tôi đang xây dựng. Nhưng tôi đang gặp khó khăn trong việc tìm ra cách một người giám sát loại này có thể theo dõi một tiến trình đang chạy trên một Nút từ xa. Không giống như hàm start_link của erlang, start_child không có tham số nào để chỉ định Nút mà con sẽ được sinh ra.Người giám sát OTP có thể giám sát quy trình trên một nút từ xa không?

Có thể giám sát OTP theo dõi một đứa trẻ ở xa không, và nếu không, làm thế nào tôi có thể đạt được điều này trong erlang?

+1

Tôi nghĩ cách được khuyến nghị là có người giám sát trên mỗi nút. – Dogbert

+0

@Dogbert Thật vậy. Trên thực tế, không chỉ là người giám sát, mà thường là bản sao đầy đủ của bất kỳ hệ thống nào đang được phân phối sao cho các yêu cầu công việc có thể là nút chéo mà không yêu cầu bất kỳ thay đổi lớn nào đối với mã. – zxq9

Trả lời

3

supervisor:start_child/2 có thể được sử dụng trên các nút.

Lý do cho sự nhầm lẫn của bạn chỉ là sự kết hợp về bối cảnh thực hiện (đôi khi phải thừa nhận đôi chút khó khăn để giữ thẳng). Có ba quá trình tham gia vào bất kỳ đẻ trứng OTP:

  • Các Yêu Cầu
  • Các Supervisor
  • quá trình sinh ra

Bối cảnh của Người Yêu Cầu là một trong đó supervisor:start_child/2 được gọi là - không phải là ngữ cảnh của người giám sát. Bạn thường sẽ cung cấp một giao diện người giám sát bằng cách xuất một chức năng mà kết thúc tốt đẹp các cuộc gọi đến supervisor:spawn_child/2:

do_some_crashable_work(Data) -> 
    supervisor:start_child(sooper_dooper_sup, [Data]). 

Điều đó có thể được xác định và xuất khẩu từ các mô-đun giám sát, được định nghĩa trong nội bộ một "người quản lý" loại quá trình theo "service manager/supervisor/workers" idiom hoặc bất kỳ thứ gì. Tuy nhiên, trong mọi trường hợp, một số quy trình khác với người giám sát đang thực hiện cuộc gọi này.

Bây giờ, hãy xem kỹ tài liệu Erlang cho supervisor:start_child/2 một lần nữa (herean R19.1 doc mirror vì đôi khi erlang.org gặp khó khăn vì một số lý do). Lưu ý rằng loại sup_ref() có thể là tên đã đăng ký, pid(), một số {global, Name} hoặc {Name, Node}. Người yêu cầu có thể ở trên bất kỳ nút nào gọi cho người giám sát trên bất kỳ nút nào khác khi gọi bằng số pid(), {global, Name} hoặc một số {Name, Node} tuple.

Giám sát viên không chỉ ngẫu nhiên khởi động mọi thứ. Nó có một child_spec() nó sẽ tắt, và spec cho người giám sát biết phải gọi gì để bắt đầu quá trình mới đó. Cuộc gọi đầu tiên này vào mô-đun con được thực hiện trong ngữ cảnh của người giám sát và là một chức năng tùy chỉnh. Mặc dù chúng ta thường đặt tên nó là start_link/N, nhưng nó có thể làm bất cứ điều gì chúng ta muốn như một phần của khởi động, bao gồm khai báo một nút cụ thể để sinh ra. Vì vậy, bây giờ chúng tôi gió lên với một cái gì đó như thế này:

%% Usually defined in the requestor or supervisor module 
do_some_crashable_work(SupNode, WorkerNode, Data) -> 
    supervisor:start_child({sooper_dooper_sup, SupNode}, [WorkerNode, Data]). 

Với một spec con của một cái gì đó như:

%% Usually in the supervisor code 
SooperWorker = {sooper_worker, 
       {sooper_worker, start_link, []}, 
       temporary, 
       brutal_kill, 
       worker, 
       [sooper_worker]}, 

nào chỉ ra rằng cuộc gọi đầu tiên sẽ được sooper_worker:start_link/2:

%% The exported start_link function in the worker module 
%% Called in the context of the supervisor 
start_link(Node, Data) -> 
    Pid = proc_lib:spawn_link(Node, ?MODULE, init, [self(), Data]). 

%% The first thing the newly spawned process will execute 
%% in its own context, assuming here it is going to be a gen_server. 
init(Parent, Data) -> 
    Debug = sys:debug_options([]), 
    {ok, State} = initialize_some_state(Data) 
    gen_server:enter_loop(Parent, Debug, State). 

Bạn có thể tự hỏi tất cả những gì mucking về với proc_lib là dành cho.Nó chỉ ra rằng trong khi gọi cho một spawn từ bất cứ nơi nào trong một hệ thống multi-node để khởi tạo một spawn bất cứ nơi nào khác trong một hệ thống đa nút là có thể, nó không phải là một cách rất hữu ích để làm kinh doanh, và vì vậy gen_* hành vi và thậm chí proc_lib:start_link/N không có phương pháp khai báo nút để sinh ra một quy trình mới.

Điều bạn lý tưởng muốn là các nút biết cách tự khởi tạo và tham gia nhóm khi chúng đang chạy. Bất cứ dịch vụ nào mà hệ thống của bạn cung cấp thường được sao chép tốt nhất trên các nút khác trong cụm, và sau đó bạn chỉ phải viết một cách chọn một nút, cho phép bạn thực hiện công việc khởi nghiệp hoàn toàn vì bây giờ nó là nút cục bộ mọi trường hợp. Trong trường hợp này, bất kỳ mã quản lý/người giám sát/nhân viên bình thường nào của bạn không phải thay đổi - những thứ chỉ xảy ra, và không quan trọng là PID của người yêu cầu xảy ra trên một nút khác, ngay cả khi PID đó là địa chỉ kết quả nào phải được trả lại.

Nói cách khác, chúng ta không thực sự muốn đẻ trứng công nhân trên các nút tùy ý, những gì chúng ta thực sự muốn làm là bước lên đến một mức độ cao hơn và yêu cầu rằng một số công việc được thực hiện bởi nút khác và không thực sự quan tâm về điều đó xảy ra như thế nào. Hãy nhớ, để sinh ra một hàm cụ thể dựa trên một cuộc gọi {M,F,A} nút bạn đang gọi phải có quyền truy cập vào mô-đun và chức năng đích - nếu nó có bản sao mã, tại sao nó không phải là bản sao của nút gọi?

Hy vọng câu trả lời này được giải thích nhiều hơn nhầm lẫn.