2010-07-03 44 views
37

Phiên bản dài:Tin nhắn Erlang/OTP có đáng tin cậy không? Tin nhắn có thể được sao chép không?

Tôi mới làm quen và cân nhắc việc sử dụng nó cho kiến ​​trúc có thể mở rộng. Tôi đã tìm thấy nhiều người ủng hộ nền tảng chào hàng độ tin cậy và khả năng chịu lỗi của nó.

Tuy nhiên, tôi đang cố gắng để hiểu chính xác mức độ chịu lỗi được thực hiện trong hệ thống này khi thư được xếp hàng trong bộ nhớ thoáng qua. Tôi hiểu rằng một hệ thống phân cấp giám sát có thể được sắp xếp để hồi sinh các quá trình đã qua đời, nhưng tôi đã không thể tìm thấy nhiều cuộc thảo luận về các tác động của việc tuân theo các công việc đang được tiến hành. Điều gì xảy ra với thông báo trên máy bay và các đồ tạo tác của công việc được hoàn thành một phần đã bị mất trên một nút chết?

Tất cả các nhà sản xuất có tự động truyền lại các thông điệp không phải là ack'd khi các quy trình tiêu dùng chết không? Nếu không, làm thế nào điều này có thể được coi là chịu lỗi? Và nếu như vậy, điều gì ngăn cản một thông điệp đã được xử lý - nhưng không được thừa nhận - từ được truyền lại, và do đó tái xử lý không thích hợp?

(tôi nhận ra rằng những mối quan tâm không phải là duy nhất để erlang; mối quan tâm tương tự sẽ xảy ra trong bất kỳ hệ thống xử lý phân tán Nhưng những người đam mê erlang dường như khẳng định rằng nền tảng này làm cho điều này tất cả "dễ dàng" ...?)

Giả các thông điệp được truyền lại, tôi có thể dễ dàng hình dung ra một kịch bản mà các hiệu ứng hạ lưu của một chuỗi tin nhắn phức tạp có thể trở nên rất lộn xộn sau một lỗi. Nếu không có một số loại hệ thống giao dịch phân phối nặng, tôi không hiểu tính nhất quán và độ chính xác có thể được duy trì như thế nào mà không cần giải quyết trùng lặp trong mọi quá trình. Mã ứng dụng của tôi có phải luôn luôn thực thi các ràng buộc để ngăn chặn các giao dịch được thực hiện nhiều lần không?

phiên bản ngắn:

đang phân phối các quá trình erlang tùy thuộc vào thông điệp trùng lặp? Nếu vậy, là bảo vệ trùng lặp (tức là, idempotency) một trách nhiệm ứng dụng, hoặc không erlang/OTP bằng cách nào đó giúp chúng tôi với điều này?

+0

Sự hiểu biết của tôi là khi một quá trình chết, và được respawned, bất cứ điều gì nó đã làm mà không được thông qua trở lại cần phải được làm lại. –

+0

Rõ ràng là công việc chưa hoàn thành cần được làm lại ... Tôi nghĩ bạn đang đề xuất rằng trách nhiệm của ứng dụng là khởi động lại các tác vụ chưa hoàn thành (có thể là do hoàn thành theo dõi và gửi lại tin nhắn không thành công). Đó có phải là ý bạn không? Ai đó có thể xác nhận điều này từ kinh nghiệm? – joshng

Trả lời

100

Tôi sẽ chia thành các điểm mà tôi hy vọng sẽ có ý nghĩa. Tôi có thể đang băm nhỏ một chút về những gì tôi đã viết trong The Hitchhiker's Guide to Concurrency. Bạn có thể muốn đọc cái đó để biết chi tiết về lý do đằng sau cách truyền thông điệp được thực hiện trong Erlang.


1. truyền nhắn

nhắn qua trong Erlang được thực hiện thông qua các thông điệp không đồng bộ được gửi vào hộp thư (một loại hàng đợi để lưu trữ dữ liệu). Có hoàn toàn không giả định về việc liệu một tin nhắn đã được nhận hay chưa, hoặc thậm chí là nó đã được gửi đến một quá trình hợp lệ. Điều này là do có thể giả định [ở cấp độ ngôn ngữ] mà ai đó có thể muốn xử lý một tin nhắn trong có thể chỉ 4 ngày và thậm chí sẽ không thừa nhận sự tồn tại của nó cho đến khi nó đạt tới một trạng thái nhất định.

Một ví dụ ngẫu nhiên về điều này có thể là để tưởng tượng một quy trình chạy dài kéo dài dữ liệu trong 4 giờ. Nếu nó thực sự thừa nhận nó đã nhận được một tin nhắn nếu nó không thể đối xử với nó? Có lẽ nó nên, có lẽ không. Nó thực sự phụ thuộc vào ứng dụng của bạn. Như vậy, không có giả định được thực hiện. Bạn có thể có một nửa thư của mình không đồng bộ và chỉ một thư không phải là thư.

Erlang hy vọng bạn gửi một thông báo xác nhận (và đợi nó bằng một khoảng thời gian chờ) nếu bạn cần. Các quy tắc phải thực hiện với định thời gian và định dạng trả lời được để lại cho người lập trình để chỉ định - Erlang không thể giả định bạn muốn xác nhận về việc nhận tin nhắn, khi công việc được hoàn thành, cho dù nó khớp hay không (thông báo có thể khớp trong 4 giờ khi một phiên bản mới của mã được tải nóng), v.v.

Để làm cho nó ngắn gọn, cho dù tin nhắn không được đọc, không nhận được hoặc bị gián đoạn bởi ai đó kéo phích cắm trong khi nó đang trong quá cảnh không quan trọng nếu bạn không muốn nó. Nếu bạn muốn nó quan trọng, bạn cần phải thiết kế một logic trên các quy trình.

Gánh nặng thực hiện giao thức thông báo mức cao giữa các quy trình Erlang được trao cho người lập trình.


2. giao thức nhắn

Như bạn nói, những tin nhắn được lưu trữ trong bộ nhớ tạm thời: nếu một quá trình chết, tất cả các tin nhắn nó đã không đọc chưa bị mất. Nếu bạn muốn nhiều hơn, có nhiều chiến lược khác nhau. Một vài trong số đó là:

  • Đọc tin nhắn nhanh nhất có thể và ghi vào đĩa nếu cần, gửi lại xác nhận và xử lý sau. So sánh điều này với phần mềm xếp hàng như RabbitMQ và ActiveMQ với hàng đợi liên tục.
  • Sử dụng các nhóm quy trình để sao chép các thư trên một nhóm quy trình trên nhiều nút. Tại thời điểm này, bạn có thể nhập ngữ nghĩa giao dịch.Cái này được sử dụng cho cơ sở dữ liệu mnesia cho các giao dịch cam kết;
  • Đừng cho rằng bất cứ điều gì đã hoạt động cho đến khi bạn nhận được xác nhận rằng mọi thứ đều ổn hoặc thông báo lỗi
  • Kết hợp các nhóm quá trình và thông báo lỗi. Nếu một quá trình đầu tiên không xử lý được một nhiệm vụ (vì nút bị hỏng), một thông báo sẽ được VM gửi tự động đến một quá trình không thành công để xử lý nó. Phương pháp này đôi khi được sử dụng với các ứng dụng đầy đủ để xử lý các lỗi phần cứng.

Tùy thuộc vào nhiệm vụ hiện tại, bạn có thể sử dụng một hoặc nhiều thao tác này. Tất cả chúng đều có thể thực hiện trong Erlang và trong nhiều trường hợp, các mô-đun đã được viết để thực hiện việc nâng hạng nặng cho bạn.

Vì vậy, điều này có thể trả lời câu hỏi của bạn. Bởi vì bạn tự mình thực hiện các giao thức, đó là lựa chọn của bạn cho dù thư được gửi nhiều lần hay không.


3. lỗi khoan nhượng

Chọn một trong những chiến lược trên không phụ thuộc vào những gì lỗi khoan nhượng có nghĩa là bạn là gì. Trong một số trường hợp, mọi người muốn nói rằng "không có dữ liệu nào bị mất, không có tác vụ nào bị lỗi". Những người khác sử dụng khả năng chịu lỗi để nói "người dùng không bao giờ thấy sự cố". Trong trường hợp hệ thống Erlang, ý nghĩa thông thường là giữ cho hệ thống hoạt động: có thể có một người dùng đơn lẻ bỏ cuộc gọi điện thoại thay vì để mọi người bỏ nó.

Ở đây ý tưởng là sau đó để cho những thứ thất bại, nhưng giữ phần còn lại chạy. Để đạt được điều này, có một vài điều VM cung cấp cho bạn:

  • Bạn có thể biết khi nào một quá trình chết và tại sao nó đã làm
  • Bạn có thể buộc các quá trình phụ thuộc vào nhau để cùng chết nếu một trong số họ đi sai
  • bạn có thể chạy một logger tự động đăng mỗi ngoại lệ còn tự do cho bạn, và thậm chí xác định riêng
  • Nodes của bạn có thể được theo dõi để bạn biết khi họ đi xuống (hoặc bị ngắt kết nối)
  • bạn có thể khởi động lại quá trình không thành công (hoặc gr oups của các quá trình thất bại)
  • Có toàn bộ các ứng dụng khởi động lại trên các nút khác nhau nếu một trong những thất bại
  • Và thứ hơn rất nhiều hơn với khuôn khổ OTP

Với những công cụ này và một vài trong số các module thư viện chuẩn của xử lý khác nhau kịch bản cho bạn, bạn có thể thực hiện khá nhiều những gì bạn muốn trên các ngữ nghĩa không đồng bộ của Erlang, mặc dù nó thường trả tiền để có thể sử dụng định nghĩa của Erlang về khả năng chịu lỗi.


4. Một vài lưu ý

ý kiến ​​cá nhân của tôi ở đây là nó khá khó khăn để có giả định nhiều hơn những gì tồn tại trong Erlang trừ khi bạn muốn ngữ nghĩa giao dịch thuần túy. Một vấn đề bạn sẽ luôn gặp rắc rối là với các nút đi xuống.Bạn không bao giờ có thể biết được họ có đi xuống vì máy chủ thực sự bị lỗi hoặc do mạng không thành công.

Trong trường hợp xảy ra sự cố máy chủ, chỉ cần thực hiện lại các tác vụ thật dễ dàng. Tuy nhiên với một tách ròng, bạn phải chắc chắn rằng một số hoạt động quan trọng không được thực hiện hai lần, nhưng không bị mất một trong hai.

Nó thường sôi xuống CAP theorem mà về cơ bản cung cấp cho bạn 3 lựa chọn, trong đó bạn phải chọn hai:

  1. quán
  2. khoan dung Partition
  3. Availability

Tùy thuộc vào nơi bạn tự định vị, các phương pháp tiếp cận khác nhau sẽ là cần thiết. Định lý CAP thường được sử dụng để mô tả cơ sở dữ liệu, nhưng tôi tin rằng các câu hỏi tương tự sẽ được hỏi bất cứ khi nào bạn cần mức độ chịu lỗi khi xử lý dữ liệu.

+4

Chúng ta cần một cách để quyên góp một số điểm để bơm câu trả lời lên nhiều hơn +1. Nghiêm túc làm việc tốt ở đây. –

5

Hệ thống OTP erlang có khả năng chịu lỗi. Điều đó không làm giảm bạn về sự cần thiết phải xây dựng các ứng dụng chịu lỗi như nhau trong đó. Nếu bạn sử dụng erlang và OTP thì có một vài điều bạn có thể dựa vào.

  1. Khi quá trình này chết thì quá trình đó sẽ được khởi động lại.
  2. Đối với hầu hết các phần, quá trình gặp sự cố sẽ không làm giảm toàn bộ ứng dụng của bạn
  3. Khi nhận được tin nhắn, người nhận sẽ nhận được thông báo.

Theo như tôi biết thư trong erlang không bị trùng lặp. Nếu bạn gửi một tin nhắn và quá trình nhận được tin nhắn thì tin nhắn sẽ biến mất khỏi hàng đợi. Tuy nhiên nếu bạn gửi một tin nhắn và quá trình nhận được tin nhắn đó nhưng treo trong khi xử lý nó thì tin nhắn đó đã biến mất và không được giải quyết. Thực tế đó nên được xem xét trong thiết kế của hệ thống của bạn. OTP giúp bạn xử lý tất cả điều này bằng cách sử dụng các quy trình để tách biệt mã quan trọng của cơ sở hạ tầng (ví dụ: giám sát viên, gen_servers, ...) khỏi mã ứng dụng có thể bị lỗi.

Ví dụ: bạn có thể có máy gen_server gửi công việc tới một nhóm xử lý. Các quy trình trong hồ bơi có thể bị lỗi và được khởi động lại. Nhưng gen_server vẫn còn lên kể từ khi toàn bộ mục đích của nó chỉ là để nhận tin nhắn và gửi chúng đến hồ bơi để làm việc trên.Điều này cho phép toàn bộ hệ thống ở lại mặc dù lỗi và tai nạn trong hồ bơi và luôn luôn có một cái gì đó chờ đợi tin nhắn của bạn.

Chỉ vì hệ thống có khả năng chịu lỗi không có nghĩa là thuật toán của bạn.

1

Tôi nghĩ câu trả lời không liên quan gì đến Erlang cả. Nó nằm trong ngữ nghĩa của tương tác Client-Server, nơi bạn có thể chọn để thực hiện "ít nhất một lần", "nhiều nhất một lần" hoặc "chính xác một lần" đảm bảo vào giao thức máy khách-máy chủ của bạn. Tất cả các ngữ nghĩa gọi này có thể được thực hiện bằng cách kết hợp các thẻ duy nhất, thử lại và ghi lại các yêu cầu của máy khách trên cả máy khách và máy chủ trước khi gửi hoặc thực thi nó để nó có thể được máy chủ lấy sau khi gặp sự cố. Bên cạnh các bản sao, bạn có thể nhận tin nhắn bị mất, mồ côi hoặc bị trì hoãn.

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