Các giao thức tích hợp hệ thống phổ biến

Khi phát thiết kế hệ thống, để đảm bảo hệ thống thoả mãn Low Coupling và High Cohesion, người ta chia tách các thành phần của hệ thống thành nhiều Module nhỏ, hoặc chia 1 hệ thống ra thành nhiều dịch vụ nhỏ rồi kết hợp lại với nhau. Việc này còn có thể giúp chúng ra Scale hệ thống một cách dễ dàng, cũng như đảm bảo hệ thống có khả năng chịu lỗi.

Tuy nhiên, khi chia hệ thống như vậy sẽ phát sinh vấn đề tích hợp. Làm sao để các hệ thống có thể chạy chơn chu với nhau? Làm sao để chọn lựa cách tích hợp phù hợp? Tất cả sẽ có trong bài viết này.

1. Một vài ví dụ về cách tích hợp hệ thống hay gặp.

1.1 Kết hợp giữa PHP và MySQL.

PHP và MySQL là 2 công nghệ khác nhau (1 là ngôn ngữ lập trình, 1 là hệ quản trị cơ sở dữ liệu). Rõ ràng là khi làm việc ta cần phải kết nối PHP và MySQL với nhau. PHP cung cấp cho chúng ta 1 vài cách đê kết nối với MySQL như mysqli, PDO… Đây là các phần mở rộng cung cấp cách thức truy cập và xử lý Cơ sở dữ liệu.

Khi kết nối với MySQL, ta cần khai báo một vài tham số như host, port, username, password. Bỏ qua các thông số khác, ta để ý tới host và port. Tại sao khi kết nối MySQL lại cần host và port? Cách thức kết nối ở đây là gì?

MySQL cung cấp cách thức truy cập vào Server bằng tcp/socket. Đây là một giao thức phổ biến để truy cập và tích hợp hệ thống. Hầu hết ngôn ngữ lập trình và CSDL đều hỗ trợ giao thức này.

Khi một Server MySQL chạy, Socket server sẽ lắng nghe ở cổng 3306 (cổng mặc định của MySQL). Khi có bất cứ 1 truy cập nào tới cổng này (từ PHP chả hạn), tuỳ vào thông tin mà ở phía đầu kia Request, MySQL sẽ trở lại kết quả.

Socket cung cấp 2 cơ chế giao tiếp, 1 là sử dụng cổng ảo (port), ví dụ 3306. Thứ 2 là sử dụng hệ thống Socket File (Unix socket). File này làm nhiệm vụ giao tiếp nội bộ giữa các process (1 chương trình bao gồm nhiều process) trong hệ thống với nhau.

Lưu ý rằng, Unix socket file chỉ sử dụng được thì 2 process nằm trong cùng 1 máy chủ. Nếu PHP và MySQL nằm ở 2 máy chủ khác nhau, bạn chỉ có thể tích hợp sử dụng cổng ảo mà thôi.

1.2 Kết hợp giữa PHP và NGINX.

Như ta đã biết, NGINX có nhiều tác dụng trong hệ thống như làm Webserver, làm Proxy, làm Load Balancer… Về cơ bản cách thức NGINX và PHP làm việc với nhau cũng tương tự như PHP và MySQL. Chúng giao tiếp thông qua Socket.

Để làm việc với NGINX, ta cần 1 phiên bản PHP đặc biệt gọi là PHP-FPM. Bởi vì cơ chế quản lý Request của NGINX và Apache khác nhau, nên cần 1 bản PHP đáp ứng được vấn đề này.

PHP-FPM sẽ mở cổng 9000 hoặc Unix socket file cho cả 2 cách thức truy cập local và từ xa.

1.3 Docker Client và Docker Machine.

Trong Docker, khi tao làm việc với Command Line Interface (CLI) tức là ta đang theo tác trên Docker Client. Khi gõ lệnh, Docker Client sẽ gửi lệnh tới Docker Machine theo chuẩn RESTful. Tuy nhiên, cơ chế gửi không phải là HTTP và mà là Socket.

Từ đó, nếu muốn xây dựng 1 chương trình quản lý Docker, bạn có thể lập trình 1 Website có khả năng gửi Socket tới Docker Machine là xong.

1.4 Các Service trong hệ thống Docker Compose giao tiếp với nhau thế nào?

Trước tiên ta cần hiểu rằng, mỗi Service được chạy bởi Docker Compose là một máy chủ riêng biệt. Tức là các process trong Servie này không thể gọi các Process trong Service khác, chúng chỉ có thể giao tiếp với nhau thông qua các giao thức mạng khác

Để có thể giao tiếp được, các Service này phải nằm cùng 1 mạng (gọi là Overlay Network). Mạng này do Docker tự tạo ra và gán các Container vào mạng đó. Tên Service lúc này sẽ được gán là hostname.

Ví dụ ta có Service tên là php và mysql. Để Service PHP có thể gọi MySQL thông qua Socket port, ta cần phải khai báo hostname là mysql và cổng là 3306.

Ví dụ với NGINX và PHP, ta cần khai báo hostname là php và cổng socket sẽ là 9000.

2. Các cách tích hợp hệ thống phổ biến.

2.1 HTTP Protocol

Đây là giao thức thống trị thế giới hiện tại. Nó giúp cho chúng ta truy cập các tài nguyên mạng như Website, Video, Ảnh….

Đặc thù của HTTP là Stateless (phi trạng thái), có nghia là khi Client gửi Request lên Server lần thứ nhất, tới lần thứ 2 Server cũng không xác minh được Client đó đã gửi Request hay chưa.

Để khắc phục nhược điểm này, người ta nghĩ ra những thứ như Session, Cookie, LocalStorage, Json Webtoken… để HTTP có thể Stateful được (có trạng thái). Từ đó Server có thể phân biệt được các Client với nhau.

Từ HTTP, người ta nghĩ ra một số quy tắc tích hợp các hê thống, lúc này các hệ thống sẽ đóng vai trò là các dịch vụ. Từ đó ta có Web Service.

Trước đây, người ta sử dụng chuẩn giao tiếp là SOAP giữa các Service với nhau. SOAP chỉ là chuẩn, nó có thể sử dụng cho cả giao thức HTTP (Web) và STMP (Mail).

Tới sau này, năm 2000 trở đi, người ta phát minh ra 1 tiêu chuẩn nữa gọi là REST. Các hệ thông áp dụng tiêu chuẩn này thì được gọi là RESTful Service. Đây là tiêu chuẩn sử dụng phổ biến nhất cho các Web API bây giờ. Bản chất của REST là Stateless (đã nói ở trên), cho nên để Authenticate các Client, người ta sử dụng Webtoken.

2.2 TCP Socket Prototol.

Như đã nói ở trên về Socket, nó là một giao thức rất cổ điển, lâu đời tuy nhiên hiện nay vẫn còn sử dụng khá nhiều. Ở đây chúng ta chỉ xét tới TCP Socket mà thôi. Vì trong giao thức TCP, 2 máy muốn kết nối và gửi thông tin với nhau thì buộc phải tạo 1 connection liên tục. Còn một loại nữa là UDP, loại này nhanh hơn, không yêu cầu tạo sẵn Connection tuy nhiên độ tin cậy không cao vì gói tin được gửi đi không đảm bảo đã nhận được hay chưa.

Nếu đã đọc ví dụ ở phần 1 rồi, bạn có thể thấy Socket có ở khắp mọi nơi.

Sau này, khi Web phát triển người ta sinh ra một công nghệ gọi là Web Socket. Như ta đã biết, để truyền và gửi thông tin trên 1 trang web, ta cần phải thực hiện HTTP Protocol Method (GET, POST, PUT…). Nếu để làm 1 chương trình Chat giữa các Client, ta phải submit request liên tục bằng POST hoặc PUT. Tuy nhiên giờ là 2019 rồi, việc đó chỉ thời các cụ mới làm thôi. Websocket cung cấp cơ chế tương tự như Socket, đó là tạo Connection trực tiếp tới máy chủ. Kết nối này sẽ luôn luôn được duy trì cho tới khi 1 bên kết thúc (Close connection). Điều này đảm bảo giảm độ trễ của mỗi request (gần như realtime), cũng như giảm tải tài nguyên cho máy chủ khi phải xử lý các request từ Client.

2.3 RPC – Remote Produce Call.

Đây là cách gọi hàm từ xa. Hàm này không có trong chương trình hiện tại mà phải thực thi ở một chương trình khác hoặc máy chủ khác. Ví dụ bạn có 1 chương trình Chat nội bộ, để thực hiện đăng nhập cho User bạn phải xây dựng 1 Server để xác thực cho các máy Client. Khi 1 client yêu cầu xác thực, nó sẽ gửi 1 request tới Server của bạn. Request này có thể được xem như 1 Lời gọi thủ tục từ xa (RPC).

Nên khi thiết kế RESTful Service, các chức năng như Login, Logout sẽ được coi như RPC Service với vì ta không có định nghĩa nào về Resource có tên là Login cả, chỉ có 1 thủ tục là Login mà thôi.

RPC cơ bản là một chuẩn thiết kế giao tiếp như REST. Nên tao có thể Implement cơ chế này bằng HTTP Protocol hay TCP Socket đều được.

Hiện nay RPC đang được sử dụng rất nhiều trong các bài toán hiệu năng cao, do đòi hỏi việc gọi thủ tục, hàm từ rất nhiều Service với nhau. Trong đó có 2 RPC Framework nổi tiếng nhất là Thrift và gRPC. Đây là 2 Framework cho phép ngươi sử dụng xây dựng các Server và cơ chế để gọi thủ tục từ xa. Ví dụ, 1 chương trình bằng Python muốn gọi 1 hàm trong chương trình chạy bằng PHP thì sao? Có một cách ta đã biết là dùng TCP Socket, tuy nhiên Socket chỉ là Protocol, nó không quy định các tiêu chuẩn tích hợp hệ thống, cũng như chỉ hỗ trợ cấu trúc dữ liệu dạng chuỗi cơ bản, đã thế lại còn bị giới hạn dữ liệu cũng như ở mỗi ngôn ngữ lại có 1 cách viết khác nhau. Việc xây dựng 1 chương trình bằng lập trình Socket thực sự là ác mộng.

Thrift và gRPC cung cấp các Interface đơn giản để giúp việc thực hiện RPC đơn giản và khoẻ người hơn. Hiện giờ Thrift đang được sử dụng tại Facebook, còn gRPC được sử dụng ở Google cho việc tích hợp các dịch vụ.

2.4 Message Queue.

Đây là công nghệ xương sống của các hệ thống phân tán (Distributed System). Tại sao lại như vậy?

Hệ thống phân tán là hệ thống bao gồm nhiều máy chủ, nhiều dịch vụ, nhiều database hoạt động kết hợp với nhau. Một hệ thống phân tán tốt là hệ thống mà cần đảm bảo CAP Theorem. (Không thể đạt được cả 3).

Khi số lượng Service tăng lên, đồng nghĩa với việc giao tiếp giữa các Service với nhau trở lên hỗn loạn.

Message Queue đề xuất rằng, mỗi một lời gọi thủ tục hoặc 1 lời gọi resource ở 1 Service khác được coi là 1 Message. Như vậy, việc quản lý việc trao đổi giữa các Service được coi như việc quản lý các Message. Từ đó các Message Broker ra đời, làm nhiệm vụ trung gian trao đổi message giữa các Service với nhau.

Các Message Broker thường Implement AMQP Protocol, đây là 1 Protocol chuyên về việc truyền/nhận message trong hệ thống phân tán.

Các Message Broker phổ biến: RabbitMQ, ZeroMQ, ActiveMQ, Kafka, MSMQ, SQS…

Message Broker hiện nay có thể là 1 chương trình chạy trên máy chủ, cũng có thể là 1 dịch vụ được cài đặt sẵn (SQS hay MSMQ)…

Hiện tại DEHA Technologies đang áp dụng Kafka làm một Message Broker để tích hợp hệ thống. Tôi sẽ có bài viết chi tiết về công nghệ này ở bài viết sau.

Hy vọng những thông tin ở trên hữu ích với mọi người.

Leave a Reply

Your email address will not be published. Required fields are marked *