Khi nào thì không tốt khi sử dụng diễn viên trong akka / erlang?


58

Tôi đã làm việc với akka được 7-8 tháng rồi. Khi tôi bắt đầu, tôi sẽ làm việc trên các ứng dụng và nhận thấy rằng các diễn viên sẽ được sử dụng cơ bản ở bất cứ đâu một lần trong hệ thống diễn viên để giao tiếp giữa hầu hết các đối tượng. Vì vậy, tôi đã làm như vậy - quay một diễn viên khác cho x / y / z.

Dường như với tôi rằng điều này có thể quá bừa bãi, làm tăng thêm sự phức tạp khi không cần thiết - nhưng tôi không thể tìm thấy bất kỳ cuộc thảo luận nào về việc nên sử dụng logic đồng bộ hoặc thậm chí không đồng bộ thông qua tương lai. Tôi bắt đầu suy nghĩ về lập trường của mình sau khi đồng nghiệp của tôi đề cập đến một cái gì đó tương tự. Tôi đã nhận ra một số trường hợp gần đây khi tôi đã suy nghĩ về một nhiệm vụ và sau đó tránh tạo ra một diễn viên khác bởi vì tôi có thể đạt được kết quả tương tự một cách an toàn trong một triển khai bất biến - ví dụ như một cái gì đó như nhận các giá trị cấu hình từ một db hoặc tệp ở đâu đó mà bạn truy cập rất thường xuyên và sẽ chờ kết quả là trường hợp sử dụng thực tế.

Đặc biệt, đối với tôi, dường như bất kỳ trường hợp nào bạn đang chơi với trạng thái bất biến, các diễn viên đều tạo ra sự phức tạp và giới hạn thông lượng - ví dụ, một hàm thuần túy trong một đối tượng có thể được gọi là không có rủi ro với bất kỳ mức độ đồng thời nào một diễn viên chỉ có thể xử lý một tin nhắn tại một thời điểm. Sự cân nhắc thay thế là bạn sẽ xử lý chuỗi nếu bạn cần chờ kết quả trừ khi bạn bắt đầu sử dụng tương lai nhưng trong trường hợp bạn không cần lo lắng về việc nhắn tin không đồng bộ hoặc mở rộng quy mô thì có vẻ như quá mức cần thiết để sử dụng một diễn viên.

Vì vậy, câu hỏi của tôi là - có một thời gian xấu để sử dụng các diễn viên? Tôi tò mò làm thế nào erlang trông và thực sự muốn cái nhìn sâu sắc của người khác. Hoặc nếu có một số nguyên tắc xung quanh diễn viên sử dụng.


Loại công việc nào mang lại cơ hội làm việc với Akka hàng ngày trong nhiều tháng?
Den

3
Những người tốt. :) Hoặc tự thay đổi.
JasonG

Tôi muốn biết cụ thể sự đánh đổi giữa askdiễn viên và chỉ sử dụng một cách đơn giản Future.
Max Heiber

2
Cuối cùng tôi đã viết một cuốn sách về Akka vài năm sau đó và tôi nghĩ rằng bạn có thể tóm tắt nó như thế này: Nếu bạn có một số trạng thái - ví dụ như một bộ đếm - nhiều chủ đề đọc và viết từ / đến giá trị đó sẽ kết thúc dẫm đạp lên nhau w / o đồng bộ hóa và khóa. Nếu bạn đặt trạng thái đó bên trong một diễn viên, đột nhiên bạn có thể chắc chắn rằng nó được truy cập một cách an toàn và bạn sẽ không bị rơi hoặc viết bị đọc. Các diễn viên trong erlang và akka cũng cho rằng trạng thái có thể trở nên tồi tệ và diễn viên có thể ném lỗi để bạn có một số đặc điểm hệ thống tự chữa lành. Tương lai đơn giản hơn nếu bạn không cần phải đột biến
JasonG

nhiều năm sau tôi là một lập trình viên erlang / elixir và tôi tiếp tục quay lại vấn đề này với những hiểu biết mới :) Elixir khá khác biệt vì không có đối tượng nào thay thế cho các quy trình nên các quy trình luôn được xây dựng khi bạn cần trạng thái . Nó chỉ xảy ra đồng thời. Đây là heuristic tốt nhất vẫn còn.
JasonG

Câu trả lời:


23

Đây là một câu hỏi tôi quan tâm và tôi đã thực hiện một số nghiên cứu về. Đối với các quan điểm khác, hãy xem bài đăng trên blog này của Noel Walsh hoặc câu hỏi này trên Stack Overflow. Tôi có một số ý kiến ​​tôi muốn đưa ra:

  • Tôi nghĩ Akka, vì nó hoạt động với các thông điệp, khuyến khích một "tư duy đẩy". Thông thường, để đồng thời, tôi sẽ cho rằng đây không phải là điều bạn muốn. Kéo an toàn hơn nhiều. Ví dụ, một mẫu chung cho các hệ thống phân tán là có một tập hợp các công nhân xử lý thông tin trong hàng đợi . Rõ ràng điều này là có thể ở Akka nhưng dường như đó không phải là cách tiếp cận đầu tiên mà mọi người thử . Akka cũng cung cấp các hộp thư bền nhưng một lần nữa, nó phụ thuộc vào cách bạn sử dụng chúng - một hàng đợi được chia sẻ linh hoạt hơn rất nhiều so với hàng đợi công nhân để cân bằng / phân công lại công việc.
  • Thật dễ dàng để có được suy nghĩ về việc thay thế các lớp học của bạn bằng các diễn viên. Trong thực tế, một số người thậm chí dường như ủng hộ nó bằng cách nói các diễn viên chỉ nên làm một việc . Theo kết luận hợp lý, điều này làm tăng độ phức tạp của mã như Jason mô tả, bởi vì nếu mỗi lớp là một diễn viên, thì đó là rất nhiều tin nhắn bổ sung và các khối nhận / gửi. Nó cũng làm cho việc hiểu và kiểm tra mã khó khăn hơn vì bạn mất tính hình thức của giao diện - và tôi không tin rằng các bình luận là một giải pháp cho việc này . Ngoài ra, bất chấp hiệu quả huyền thoại của Akka , tôi nghi ngờ rằng sự phổ biến diễn viên không phải là một hiệu suất ý tưởng tốt khôn ngoan - khi chúng tôi sử dụng các luồng Java, chúng tôi biết rằng chúng rất quý giá và bảo tồn chúng theo đó.
  • Nó liên quan đến điểm trước, nhưng một điều khó chịu khác là việc mất thông tin loại mà Noel và Pino nêu bật, vì đối với nhiều người trong chúng ta đó là lý do tại sao chúng ta sử dụng Scala thay vì các ngôn ngữ khác như Python. Có một số cách xung quanh điều này nhưng chúng không phải là tiêu chuẩn , không được đề xuất hoặc thử nghiệm .
  • Cuối cùng, đồng thời, ngay cả khi bạn có suy nghĩ "hãy để nó sụp đổ" , thật khó. Các mô hình lập trình thay thế có thể giúp ích nhưng chúng không làm cho vấn đề biến mất - chúng thay đổi chúng - đó là lý do tại sao nên nghĩ về chúng một cách chính thức . Đó cũng là lý do tại sao nhà phát triển Joe Average tiếp cận các công cụ được xây dựng sẵn như cơ sở dữ liệu RabbitMQ, Storm, Hadoop, Spark, Kafka hoặc NoQuery. Akka có một số công cụ và thành phần dựng sẵn, rất tuyệt, nhưng nó cũng cảm thấy mức độ khá thấp, vì vậy các yếu tố phổ biến được xây dựng sẵn của các hệ thống phân tán sẽ giúp các nhà phát triển và đảm bảo các hệ thống được xây dựng đúng.

Giống như Jason, tôi rất muốn nghe những hiểu biết của người khác ở đây. Làm thế nào tôi có thể giải quyết một số vấn đề ở trên và sử dụng Akka tốt hơn?


1
Tôi tìm thấy bài đăng này về thử nghiệm tại Akka tại chỗ timgilbert.wordpress.com/2013/07/07/iêu
Mark Butler

"Thành phần trên thừa kế" vẫn hữu ích cho tiêm phụ thuộc. Ví dụ, vượt qua sự phụ thuộc trong làm đạo cụ (sử dụng tham số hàm tạo). Vấn đề sau đó sẽ là sự giám sát - diễn viên được tạo ra sẽ được giám sát ở một nơi khác ngoài diễn viên. Một bộ định tuyến có thể được sử dụng để bao bọc một chiến lược giám sát xung quanh các diễn viên được tạo ở cấp cao nhất nhưng hiện tại nó khá phức tạp! Tôi đoán bánh sẽ là một giải pháp tốt hơn - có một đặc điểm với việc tạo diễn viên cho một diễn viên dịch vụ db chẳng hạn. Sau đó, chỉ cần sử dụng một đặc điểm dịch vụ mock / stub thử nghiệm trong ngữ cảnh văn bản.
JasonG

1
Có, chính xác - giám sát không hoạt động tốt với tiêm phụ thuộc. Ngoài ra, tôi đã có những trường hợp cần thiết phải tiêm một nhà máy chứ không phải lớp học, nếu không thì có vấn đề đóng cửa nghiêm trọng hơn - tôi đoán là do cách xử lý các chủ đề của Akka.
Mark Butler

Tôi nghĩ đó không phải là một ý tưởng tồi - cảm ơn đánh dấu - tôi thực sự có thể cố gắng viết về điều này một chút và xã hội hóa nó. Bạn có thể tiêm thứ gì đó cho Đạo cụ có thể? Một nhà máy diễn viên của các loại mà người tiêu dùng có thể khởi tạo diễn viên. ví dụ: def method (arg) = return props (new ActorWithArss (arg)) từ nhà máy đó (psuedo?) để bạn có thể tạo diễn viên trong bối cảnh phù hợp. Đây có vẻ là một ý tưởng tốt và một mục tiêu tốt cho các giải pháp bánh cho di quá.
JasonG

Tôi mới bắt đầu theo khóa học này: coursera.org/cference/posea Mặc dù nó chủ yếu nhắm vào những người lập trình Android, nhưng đây cũng là một tổng quan tốt về đồng thời trong Java. Vì vậy, một điều tôi băn khoăn là "Không phải Akka chỉ là một dạng vòng lặp sự kiện lạ mắt với một số chuông và còi (vì bạn có thể đặt các vòng lặp sự kiện trên các luồng khác nhau)?"
Mark Butler

21

Thật đáng để xem xét những gì mô hình diễn viên được sử dụng cho: mô hình diễn viên là

  1. một mô hình tương tranh
  2. tránh truy cập đồng thời vào trạng thái có thể thay đổi
  3. sử dụng các cơ chế truyền thông không đồng bộ để cung cấp đồng thời.

Điều này rất có giá trị vì việc sử dụng trạng thái chia sẻ từ nhiều luồng trở nên thực sự khó khăn, đặc biệt là khi có các mối quan hệ giữa các thành phần khác nhau của trạng thái chia sẻ phải được giữ đồng bộ hóa. Tuy nhiên, nếu bạn có các thành phần miền trong đó:

  • Bạn không cho phép đồng thời, HOẶC
  • Bạn không cho phép trạng thái có thể thay đổi (như trong lập trình chức năng), HOẶC
  • Bạn phải dựa vào một số cơ chế truyền thông đồng bộ,

sau đó mô hình diễn viên sẽ không cung cấp nhiều lợi ích (nếu có).

Mong rằng sẽ giúp.


Cảm ơn - Tôi đoán bạn thực sự phải đánh giá hai điều sau đó - trạng thái có thể thay đổi và đồng thời? Không có vấn đề để giải quyết nếu một lớp không trạng thái HOẶC không đồng thời. Thêm một cân nhắc - Tôi nghĩ khả năng chịu lỗi là một điểm khác? ví dụ: nếu bạn có một máy khách redis bất biến nhưng nó có thể bị lỗi trong khi chạy - đó có phải là một trường hợp sử dụng tốt không? rằng khởi động lại diễn viên đó có thể là cần thiết? Vì - mặc dù lớp có thể hoàn toàn bất biến - rất có thể có một trạng thái bị hỏng bên ngoài đối với diễn viên bất biến có thể khiến nó thất bại.
JasonG

Tôi đoán rằng diễn viên chịu trách nhiệm giao tiếp với redis sẽ có ngoại lệ và khởi động lại mặc dù.
JasonG

@JasonG Theo tôi, "khả năng chịu lỗi" không phải là một khía cạnh của mô hình diễn viên nói chung - đó là điều gì đó đi kèm với việc triển khai mô hình diễn viên trong Erlang (và có thể là Akka?). Tôi không thể nói chuyện với redis, mặc dù tôi phải thừa nhận, "khách hàng bất biến" nghe có vẻ lạ đối với tôi ... Nếu một thành phần phần mềm có thể thất bại, tôi không thấy làm thế nào nó có thể được coi là bất biến.
Aidan Cully

Khả năng chịu lỗi và giám sát tồn tại trong akka và nó rất giống với erlang. Tôi hiểu những gì bạn đang nói về khách hàng bất biến nhưng không thay đổi có nghĩa là trạng thái mã không thay đổi ở bất cứ đâu. Nếu tôi khởi tạo kết nối khi khởi động, có thể mã khách hàng có thể bất biến với chiến lược khởi động lại được sử dụng cho bất kỳ loại lỗi nào, chỉ cần khởi động lại diễn viên khi gặp sự cố.
JasonG

12

Trực giác của bạn là chính xác, IMHO. Sử dụng diễn viên ở khắp mọi nơi giống như có búa hoạt ngôn và chỉ nhìn thấy móng tay.

Thực tiễn tốt nhất của Erlang là sử dụng các quy trình / tác nhân cho tất cả các hoạt động xảy ra đồng thời. Đó là, giống như trong cuộc sống thực. Đôi khi rất khó để tìm ra mức độ chi tiết phù hợp, nhưng hầu hết các lần bạn chỉ biết bằng cách nhìn vào miền được mô hình hóa và sử dụng một chút ý nghĩa thông thường. Tôi sợ rằng tôi không có một phương pháp tốt hơn thế, nhưng tôi hy vọng nó có ích.


Tuyệt thật, cảm ơn nhé. Tôi thực sự quan tâm để xem những gì xảy ra trong cuộc thảo luận này.
JasonG

0

Theo thứ tự nhắn tin đầu vào / đầu ra:

Gần đây tôi đã gặp một ứng dụng dựa trên akka nơi mô hình diễn viên thực sự gây ra vấn đề tương tranh, một mô hình đơn giản hơn sẽ có hiệu quả tốt hơn khi tải.

Vấn đề là các tin nhắn đến đang di chuyển theo các 'làn' khác nhau (thông qua các đường dẫn khác nhau) nhưng mã giả định rằng các tin nhắn sẽ đến đích cuối cùng theo thứ tự chúng đến. Miễn là dữ liệu đến với khoảng thời gian đủ lớn, điều này sẽ hoạt động vì sẽ chỉ có một thông điệp xung đột duy nhất chạy đến đích. Khi khoảng thời gian giảm, họ bắt đầu ra khỏi trật tự và gây ra hành vi kỳ lạ.

Vấn đề có thể đã được giải quyết chính xác với một ít diễn viên, nhưng đó là một lỗi dễ mắc phải khi lạm dụng chúng.


Đây là nền tảng và có liên quan rộng rãi. Bạn chỉ có thể đảm bảo đặt hàng giữa hai diễn viên. doc.akka.io/docs/akka/civerse/scala/general/ mẹo Bạn không thể đảm bảo giao hàng trong bất kỳ hệ thống nào mà bạn ra / vào. andreasohlund.net/2012/01/18/dont-assume-message-ordering
JasonG

-1

Theo tôi có hai trường hợp sử dụng cho Diễn viên. Tài nguyên được chia sẻ như cổng và tương tự, và trạng thái lớn. Đầu tiên đã được bao phủ tốt bởi các cuộc thảo luận cho đến nay, nhưng nhà nước lớn cũng là một lý do hợp lệ.

Một cấu trúc lớn được thông qua với mỗi lệnh gọi thủ tục có thể sử dụng rất nhiều ngăn xếp. Trạng thái này có thể được đưa vào một quy trình riêng biệt, cấu trúc được thay thế bằng id quy trình và quy trình đó được truy vấn trên cơ sở theo yêu cầu.

Các cơ sở dữ liệu như mnesia có thể được coi là lưu trữ trạng thái bên ngoài cho quá trình truy vấn.


1
Bạn có thể làm rõ? Bạn có nghĩa là nhà nước lớn trên mạng? Trong một quy trình cục bộ, việc chuyển tham chiếu đến một cấu trúc bất biến hầu như không mất phí và bạn không thể vượt qua các cấu trúc có thể thay đổi. Giả sử bạn đang nói về một cấu trúc có thể thay đổi lớn cần được sao chép để gửi? Vì vậy, về cơ bản điều tương tự một lần nữa - trạng thái chia sẻ. Kích thước không thực sự thay đổi bất cứ điều gì. Hãy cho tôi biết nếu tôi hiểu lầm.
JasonG

Vậy làm thế nào để bạn vượt qua bằng cách tham khảo? Chắc chắn cách để làm điều đó là đưa cấu trúc vào một quy trình và vượt qua tiến trình. Các cuộc gọi cục bộ sẽ đưa dữ liệu lên ngăn xếp và mọi cuộc gọi đệ quy sẽ thực hiện lại (ngoại trừ đệ quy đuôi). Xử lý đệ quy của cấu trúc có thể được thực hiện bằng cách sử dụng danh sách để chuyển trạng thái từ cuộc gọi này sang cuộc gọi khác, trạng thái này sau đó có thể tham chiếu cấu trúc trong quy trình khác.
tony wallace
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.