Mục tiêu

  • Khái quát về ngôn ngữ Erlang, Elixir, framework phoenix
  • Giới thiệu về 1 vài sample code trong elixir
  • Demo đơn giản về phoenix

Lịch sử Erlang - Elixir

Erlang: tạo ra bởi Ericsson khoảng 1980 bởi một nhóm tại công ty Ericsson - Thụy Điển.

Đặc điểm:

Erlang được tạo riêng cho các hệ thống điện thoại. Điều đó có nghĩa là nó cần phải có một số tính năng nhất định:

  • Tính sẵn sàng cao
  • Khả năng xử lý đồng thời lớn
  • Khả năng chịu lỗi cao

Hãy thử nghĩ xem: lần cuối cùng điện thoại cố định không hoạt động là khi nào?

So sánh giữa Erlang/OTP - lập trình đồng thời với  mô hình không đồng thời

Đặc điểm/Mô hình

Erlang/OTP

Mô hình Không đồng thời

Kiến trúc

Tiến trình nhẹ, Actor Model

Luồng (Thread), Sequential Model

Giao tiếp

Tin nhắn

Chia sẻ biến, Gọi hàm

Tính chịu lỗi và đồng thời

Cao

Thấp

Sử dụng trong lĩnh vực

Hệ thống đồng thời, phân tán

Ứng dụng đơn nhiệm, đồng bộ

Quản lý tài nguyên

Nhẹ nhàng, quản lý tài nguyên tốt

Tăng overhead, quản lý khó khăn

Mô hình lập trình

Concurrent, Message-passing

Sequential, Procedural, Imperative

Ngôn ngữ Elixir

José Valim công bố lần đầu tiên vào tháng 4 năm 2011.

Elixir được thiết kế để chạy trên máy ảo Erlang (BEAM) và mang lại các lợi ích của Erlang như độ tin cậy cao và khả năng xử lý đồng thời trong môi trường phân tán.

Lợi ích bổ sung mà Erlang không có:

  • Đầu tiên, cú pháp đẹp hơn nhiều.
  • Được tạo ra bởi người đóng góp cốt lõi cho Rails, cú pháp Elixir giống với Ruby.
  • Elixir mang theo sự thân thiện và hòa nhập của cộng đồng Ruby. Công cụ cũng tốt hơn rất nhiều.

Framework thực sự tuyệt vời hỗ trợ rất nhiều cho việc lập trình tương tự như Ruby on Rails nhưng được viết bằng Elixir có tên là Phoenix.

Elixir có ưu điểm gì?

Elixir là một ngôn ngữ lập trình chạy trên máy ảo Erlang (BEAM), và nó được thiết kế để xây dựng các hệ thống phân tán, có khả năng mở rộng và có tính chất chống lỗi cao. Dưới đây là một số điểm đặc biệt của Elixir:

  1. Erlang VM (BEAM): Elixir chạy trên máy ảo Erlang, giúp nó kế thừa các đặc tính như chống lỗi, đồng thời, và khả năng mở rộng của Erlang. Điều này làm cho Elixir rất phù hợp cho việc xây dựng hệ thống đa luồng và phân tán.
  2. Ngôn ngữ hàm thuần túy: Elixir là một ngôn ngữ lập trình hàm thuần túy, điều này có nghĩa là nó thúc đẩy việc sử dụng hàm như một phương thức chính để xử lý dữ liệu và logic. Điều này giúp tạo ra mã nguồn rõ ràng, dễ đọc và dễ duy trì.
  3. OTP (Open Telecom Platform): Elixir tích hợp chặt chẽ với OTP, một bộ công cụ mạnh mẽ để xây dựng các hệ thống đa tiến trình và phân tán. OTP bao gồm mô hình actor, công cụ quản lý tiến trình, và các thư viện để xử lý lỗi và khôi phục.
  4. Cú pháp sáng tạo và dễ đọc: Elixir mượn cú pháp từ nhiều nguồn khác nhau như Ruby và Erlang, tạo ra một cú pháp rất sáng tạo và dễ đọc. Điều này giúp làm giảm độ phức tạp của mã nguồn và tăng tính tương tác.
  5. Tiến trình và Actor Model: Elixir sử dụng mô hình actor để xử lý đồng thời và phân tán. Các tiến trình nhẹ (lightweight processes) trong Elixir có thể được tạo ra với chi phí rất thấp, giúp xử lý hàng nghìn hoặc thậm chí hàng triệu tiến trình cùng một lúc.
  6. Đa luồng và phân tán: Elixir được thiết kế để xây dựng các hệ thống phân tán có khả năng mở rộng dễ dàng. Các tiến trình có thể chạy trên nhiều node khác nhau, giúp tạo ra hệ thống có khả năng chịu lỗi cao và có thể mở rộng theo nhu cầu.

Tất cả những đặc tính này làm cho Elixir là một ngôn ngữ lập trình mạnh mẽ cho việc xây dựng các hệ thống đa tiến trình, phân tán và có khả năng chịu lỗi cao.

Thông tin thêm: OTP - Open Telecom Platform

Open Telecom Platform (OTP) là một bộ công cụ và thư viện tích hợp trong Erlang và Elixir, được thiết kế để hỗ trợ việc phát triển và triển khai các hệ thống đa tiến trình, phân tán và có khả năng chịu lỗi cao. Dưới đây là một số điểm mạnh của OTP:

  1. Mô hình Actor: OTP triển khai mô hình Actor, giúp quản lý và tương tác giữa các tiến trình nhẹ (lightweight processes). Mỗi tiến trình nhẹ được xem xét như một "actor" có thể gửi và nhận các thông điệp.
  2. Supervision Trees: OTP cung cấp các công cụ để xây dựng cây giám sát (supervision tree), trong đó mỗi tiến trình có thể có một giám sát (supervisor) của nó. Nếu một tiến trình gặp lỗi, giám sát có thể quyết định cách xử lý lỗi, bao gồm việc khôi phục, khởi động lại, hoặc dừng toàn bộ hệ thống.
  3. OTP Behaviors: Behaviors là các mô hình tiêu biểu của các loại tiến trình trong Erlang/OTP. Các behaviors như gen_server, gen_fsm, và gen_event giúp giảm lặp lại mã nguồn và tăng tính tái sử dụng. Những behaviors này định nghĩa các giao diện chuẩn cho các loại tiến trình phổ biến, giúp việc phát triển và duy trì mã nguồn dễ dàng hơn.
  4. Hot Code Swapping: Erlang và OTP hỗ trợ khả năng thay đổi mã nguồn mà không cần dừng hệ thống (hot code swapping). Điều này rất hữu ích trong các hệ thống chạy liên tục và cần có khả năng nâng cấp mà không làm gián đoạn dịch vụ.
  5. Thư viện Standard: OTP đi kèm với nhiều thư viện chuẩn, bao gồm các công cụ cho giao tiếp mạng, xử lý lỗi, và quản lý tài nguyên. Điều này giúp giảm bớt công việc lặp lại và giúp phát triển ứng dụng một cách hiệu quả.
  6. Phân tán và Mở Rộng: OTP hỗ trợ mô hình phân tán, cho phép các tiến trình chạy trên nhiều node khác nhau. Điều này giúp tạo ra các hệ thống mở rộng được.

Những tính năng này làm cho OTP trở thành một bộ công cụ mạnh mẽ và linh hoạt, đặc biệt thích hợp cho việc xây dựng các hệ thống đòi hỏi tính chịu lỗi, độ tin cậy cao và có khả năng mở rộng.

So sánh Erlang/OTP với các mô hình lập trình đồng thời khác

Đặc điểm/Mô hình

Erlang/OTP

Thread-based Models (Java, C++)

Actor Model (Akka, Scala)

CSP (Go)

MapReduce Model (Hadoop)

Reactive Programming Model (RxJava, Reactor)

Kiến trúc

Tiến trình nhẹ, Actor Model

Luồng (Thread)

Actor Model

CSP

MapReduce

Reactive Programming

Giao tiếp

Tin nhắn

Chia sẻ tài nguyên, khóa

Tin nhắn

Kênh

MapReduce

Luồng dữ liệu (stream)

Tính chịu lỗi và đồng thời

Cao

Phụ thuộc vào triển khai cụ thể

Cao

Cao

Thấp

Thấp

Sử dụng trong lĩnh vực

Hệ thống đồng thời, phân tán

Ứng dụng đa nhiệm

Hệ thống phân tán

Hệ thống đồng thời

Xử lý lớn dữ liệu

Xử lý sự kiện trong giao diện người dùng

So sánh máy chủ Web server

Erlang/elixir khi so sánh máy chủ Web server khác như caddy(hiện đại), Nginx (cổ điển)

Đặc ĐiểmCaddyNginxCowboy
Ngôn NgữGoCErlang/Elixir
Hiệu SuấtTrung bìnhCaoCao (Đặc biệt trong môi trường Erlang)
Tính Năng SSL/TLSHỗ trợ tự động cài đặt Let's EncryptYêu cầu plugin hoặc cấu hình bổ sungCó hỗ trợ, tích hợp với Erlang/OTP
Cấu HìnhĐơn giản, dễ đọcPhức tạp, linh hoạtKhá linh hoạt, tùy chọn cấu hình cao
Tính Năng HTTP/2Hỗ trợ mặc địnhYêu cầu cấu hình thêmCó hỗ trợ
Reverse ProxyCó tích hợpCó tích hợpCó thể thực hiện thông qua ngôn ngữ lập trình (Elixir)
Load BalancingCó tích hợpCó tích hợpCó thể thực hiện thông qua ngôn ngữ lập trình (Elixir)
WebSocketsHỗ trợCó tích hợpCó tích hợp
Hỗ Trợ Đa Tiến TrìnhKhá tốtCó, nhưng không tận rội trong môi trường ErlangMạnh mẽ, được xây dựng trên Erlang/OTP
Khả Năng Mở RộngTrung bìnhCaoKhá mạnh trong môi trường Erlang

Lưu ý rằng lựa chọn giữa Caddy, Nginx và Cowboy phụ thuộc vào yêu cầu cụ thể của dự án, ngôn ngữ lập trình sử dụng và các tính năng cần thiết.

Một vài điểm thú vị khi lập trình với Elixir

Pattern matching (so khớp mẫu)

Hiểu đơn giản là: Cố gắng matching đầu vào (params) của hàm với các hàm đã được triển khai.

ví dụ về phép cộng 2 số:

Cách gọi:

MathOperations.add(0, 1) -> tự động gọi hàm MathOperations.add(0, y)

MathOperations.add(1, 0) -> tự động gọi hàm MathOperations.add(x, 0)

MathOperations.add(1, 1) -> tự động gọi hàm MathOperations.add(x, y)

Bình thường với ngôn ngữ như JAVA hoặc php thì chúng ta sẽ if x = 0 hoặc if y == 0 hoặc dùng switch case, nhưng trong elixir, với pattern matching thì trình biên dịch sẽ tự động chọn hàm sẽ chạy bằng cách matching params.

Lấy được phần đầu và phần sau của mảng với split_at

Enum.split_at([1, 2, 3, 4, 5], 2) -> {[1, 2], [3, 4, 5]}

Tách phần tử trong mảng

Lấy được phần đầu và phần sau của mảng: bằng cách viết như dưới đây bạn đã dễ dàng lấy được phần đầu và phần sau của mảng.

Còn nhiều điều thú vị về elixir nhưng chúng ta sẽ đi sâu ở các phần tiếp theo. Tiếp theo chúng ta sẽ tìm hiểu và học cách sử dụng framework phổ biến nhất khi dùng elixir: Phoenix.

Phoenix Web Framework

  • Được thiết kế với sự tận dụng từ Ruby on Rails.
  • Phoenix đặc biệt được đánh giá với hiệu suất cao,
  • Đo lường hiệu suất không bằng mili giây mà là bằng micro giây.
  • Ngôn ngữ: elixir
  • Các process tương tác với nhau bằng việc truyền thông điệp,
  • Channels trong Phoenix cho phép người gửi và người nhận tin nhắn có thể là bất cứ thứ gì, không chỉ là các tiến trình Elixir.
  • Phoenix cung cấp thư viện đầy đủ cho client JavaScript để kết nối với kênh và gửi/nhận tin nhắn trên kênh đó.

Cài đặt

Theo tôi bạn nên cài đặt elixir, phoenix trong WSL Ubuntu hoặc môi trường linux khác. Tất nhiên bạn có thể cài đặt trên Windows cũng có thể, tuy nhiên có thể bạn sẽ gặp phải vấn đề về các packet khi cài đặt và chạy các thư viện cần thêm vào.

Demo đơn giản về elixir với phoenix

New project command: mix phx.new chirp --live

Gen code CRUD

mix phx.gen.live Timeline Post posts username body likes_count:integer reposts_count:integer

Run server

mix phx.server

DB create: mix ecto.create

DB migration

Click to migrations DB or run migration command: mix ecto.migrate

Cài đặt và chạy project mới với phoenix

https://www.phoenixframework.org/

Chạy lệnh xong kết quả sẽ ra tương tự như thế này:

Tạo DB và chạy

sau đó ta thu được màn hình default

LiveView trong Phoenix

Tương tác thời gian thực:

  • LiveView cho phép cập nhật nội dung trang web mà không cần làm mới trang (real-time).
  • Khi có sự kiện xảy ra, như người dùng thực hiện hành động trên giao diện, LiveView có thể gửi các sự kiện đó đến máy chủ và cập nhật nội dung mà không cần tải lại toàn bộ trang.

Quản lý trạng thái trên máy chủ:

Elixir cho phép quản lý trạng thái một cách hiệu quả trên máy chủ. LiveView sử dụng cơ chế này để duy trì trạng thái của ứng dụng và đồng bộ hóa nó giữa máy chủ và máy khách

Khả năng tái sử dụng mã:

Với LiveView, bạn có thể tái sử dụng mã giữa phía máy chủ và phía máy khách, giảm thiểu sự phức tạp khi phát triển và bảo dưỡng ứng dụng.

Ít sử dụng JavaScript:

Mặc dù vẫn có thể sử dụng JavaScript khi cần thiết, nhưng LiveView giảm đáng kể sự phụ thuộc vào JavaScript so với các phương pháp phát triển web truyền thống.

LiveView là một phần của sự phát triển hiện đại trong lĩnh vực phát triển web, nơi mà sự tương tác thời gian thực và khả năng làm giảm bớt việc phải tải lại trang đang trở nên quan trọng.


mix phx.gen.live Timeline Post posts username body likes_count:integer reposts_count:integer

  • Nội dung 1 bài post gồm:
  • Username: người viết bài
  • Body: nội dung bài post
  • Likes_count: số like
  • Reposts_count: số lần repost

Thêm các tuyến đường trực tiếp vào phạm vi trình duyệt

copy kết quả câu lệnh vào router.ex để thêm đường dẫn cho file đã được generate ra.

Add the live routes to your browser scope in lib/chirp_web/router.ex:

live "/posts", PostLive.Index, :index

live "/posts/new", PostLive.Index, :new

live "/posts/:id/edit", PostLive.Index, :edit

live "/posts/:id", PostLive.Show, :show

live "/posts/:id/show/edit", PostLive.Show, :edit

Demo:

Bạn có thể tham khảo demo như video được cung cấp trên trang chủ của phoenixframework.

https://www.phoenixframework.org/
https://www.youtube.com/watch?v=MZvmYaFkNJI

Broadcast dữ liệu:

https://youtu.be/MZvmYaFkNJI?t=609

Đánh giá

Phoenix có khả năng hỗ trợ người dùng khá tốt.

  • Hỗ trợ gen DB
  • Hỗ trợ WebSocket nên đồng bộ dữ liệu tốt
  • Elixir code khó làm quen nhưng khi quen rồi thấy thực sự rất thú vị.
  • Version có thay đổi nhưng trang chủ của phoenix lại bị outdate, khá đáng tiếc.

Tham khảo