Đây là một câu hỏi rất mở nhưng tôi sẽ cố gắng minh họa tại sao Elixir / Erlang có thể là nền tảng tốt nhất hiện có để phát triển các hệ thống phân tán (bất kể bạn có đang làm việc với microservices hay không).
Đầu tiên, hãy bắt đầu với một số nền tảng. Erlang VM và thư viện tiêu chuẩn của nó được thiết kế sẵn để xây dựng các hệ thống phân tán và điều này thực sự hiển thị. Theo như tôi biết, đó là thời gian chạy duy nhất và VM được sử dụng rộng rãi trong sản xuất được thiết kế trước cho trường hợp sử dụng này.
Các ứng dụng
Ví dụ, bạn đã gợi ý về "ứng dụng". Trong Erlang / Elixir, mã được đóng gói bên trong các ứng dụng:
- được bắt đầu và dừng lại như một đơn vị. Khởi động và dừng hệ thống của bạn là vấn đề khởi động tất cả các ứng dụng trong đó
- cung cấp cấu trúc thư mục thống nhất và API cấu hình (không phải là XML!). Nếu bạn đã làm việc và định cấu hình ứng dụng OTP, bạn biết cách làm việc với bất kỳ ứng dụng nào khác
- chứa cây giám sát ứng dụng của bạn, với tất cả các quy trình (theo quy trình, ý tôi là "các quy trình VM" là các luồng tính toán nhẹ) và trạng thái của chúng
Tác động của thiết kế này là rất lớn. Có nghĩa là các nhà phát triển Elixir, khi viết ứng dụng có cách tiếp cận rõ ràng hơn để:
- cách mã của họ được bắt đầu và dừng lại
- các quy trình tạo nên một phần của ứng dụng là gì và do đó trạng thái ứng dụng là gì
- quá trình đó sẽ phản ứng như thế nào và bị ảnh hưởng như thế nào trong trường hợp gặp sự cố hoặc khi có sự cố
Không chỉ vậy, công cụ xoay quanh sự trừu tượng này là rất tốt. Nếu bạn có Elixir cài đặt, mở ra "IEX" và gõ: :observer.start()
. Bên cạnh việc hiển thị thông tin và đồ thị về hệ thống trực tiếp của bạn, bạn có thể giết các quy trình ngẫu nhiên, xem trạng thái, mức sử dụng bộ nhớ của chúng và hơn thế nữa. Đây là một ví dụ về cách chạy này trong ứng dụng Phoenix:
Sự khác biệt ở đây là Ứng dụng và Quy trình cung cấp cho bạn một sự trừu tượng để lý luận về mã của bạn trong quá trình sản xuất . Nhiều ngôn ngữ cung cấp các gói, đối tượng và mô-đun chủ yếu để tổ chức mã mà không có phản ánh về hệ thống thời gian chạy. Nếu bạn có một thuộc tính lớp hoặc một đối tượng singleton: làm thế nào bạn có thể lập luận về các thực thể có thể thao túng nó? Nếu bạn bị rò rỉ bộ nhớ hoặc tắc nghẽn, làm thế nào bạn có thể tìm thấy tổ chức chịu trách nhiệm về nó?
Nếu bạn hỏi bất kỳ ai đang chạy một hệ thống phân tán, đó là loại thông tin chi tiết mà họ muốn và với Erlang / Elixir, bạn có đó là khối xây dựng.
Giao tiếp
Tất cả những điều này thực sự chỉ là bắt đầu. Khi xây dựng một hệ thống phân tán, bạn cần chọn một giao thức truyền thông và bộ tuần tự hóa dữ liệu. Rất nhiều người chọn HTTP và JSON, khi bạn nghĩ về nó, là một sự kết hợp rất dài dòng và tốn kém để thực hiện những gì thực sự là lệnh gọi RPC.
Với Erlang / Elixir, bạn đã có một giao thức truyền thông và một cơ chế tuần tự hóa. Nếu bạn muốn có hai máy liên lạc với nhau, bạn chỉ cần đặt tên cho chúng, đảm bảo chúng có cùng một bí mật và bạn đã hoàn tất.
Jamie đã nói về điều này tại Erlang Factory 2015 và cách họ có thể tận dụng điều này để xây dựng nền tảng trò chơi: https://www.youtube.com/watch?v=_i6n-eWiVn4
Nếu bạn muốn sử dụng HTTP và JSON, điều đó cũng tốt và các thư viện như Plug and framework như Phoenix sẽ đảm bảo rằng bạn cũng làm việc hiệu quả ở đây.
Microservices
Cho đến nay tôi vẫn chưa nói về microservices. Đó là bởi vì, cho đến thời điểm này, chúng không thực sự quan trọng. Bạn đang thiết kế hệ thống và các nút của mình xung quanh các quy trình rất nhỏ bị cô lập. Hãy gọi chúng là thiết bị nano nếu bạn muốn!
Không chỉ vậy, chúng còn được đóng gói thành các ứng dụng, nhóm chúng thành các thực thể có thể khởi động và dừng lại như một đơn vị. Nếu bạn có các ứng dụng A, B và C và sau đó bạn muốn triển khai chúng dưới dạng [A, B] + [C] hoặc [A] + [B] + [C], bạn sẽ gặp rất ít khó khăn khi thực hiện với thiết kế vốn có của chúng. Hoặc, thậm chí tốt hơn, nếu bạn muốn tránh thêm sự phức tạp của việc triển khai microservices vào hệ thống của mình từ trước, bạn chỉ có thể triển khai chúng hoàn toàn trong cùng một nút.
Và, vào cuối ngày, nếu bạn đang chạy tất cả những điều này bằng cách sử dụng Giao thức phân tán Erlang, bạn có thể chạy chúng ở các nút khác nhau và chúng sẽ có thể đến được với các nút khác miễn là bạn tham chiếu đến chúng {:node@network, :name}
thay vì :name
.
Tôi có thể đi xa hơn nhưng tôi hy vọng tôi đã thuyết phục được bạn vào thời điểm này. :)