Xây dựng Microservices app: dùng API Gateway
Trong mô hình microservices, client sẽ phải tương tác với rất nhiều services. Vậy làm sao mà client có thể biết được cần gọi endpoint nào để gọi ? API gateway là gì ? API Gateway chịu trách nhiệm định tuyến các request, tổng hợp và chuyển đổi giao thức. Tất cả các request từ client sẽ đi qua ...
Trong mô hình microservices, client sẽ phải tương tác với rất nhiều services. Vậy làm sao mà client có thể biết được cần gọi endpoint nào để gọi ?
API gateway là gì ?
API Gateway chịu trách nhiệm định tuyến các request, tổng hợp và chuyển đổi giao thức. Tất cả các request từ client sẽ đi qua API Gateway trước tiên. Sau đó nó định tuyến các request tới các microservice thích hợp. Nó giống như một tổng đài để điều phối các request đến từ trình duyệt (dạng HTTP REST request hay request đến URL một trang web). Nếu chúng ta không sử dụng API Gateway thì clients sẽ phải gử i request trực tiếp tới service cụ thể nào đó. Nó sẽ dẫn đến một số vấn đề rắc rối với client:
- Phần code phía client sẽ trở nên phức tạp vì phải tracking nhiều endpoint
- Sẽ tạo sự kết nối giữa client và backend. Client cần biết được các services đó đc phân chia như thế nào -> rất khó cho việc maitain của client và refactor service.
- Mỗi một service sẽ phải handle nhiều vấn đề liên quan như authentiaction, SSL hay client rate limiting
Ưu và nhược điểm của API Gateway
Ưu điểm lớn nhất khi sử dụng API Gateway là nó che dấu đi cấu trúc bên trong của ứng dụng. Thay vì truy vấn đến các service cụ thể, client đơn giản sẽ chỉ cần call thông qua API Gateway (nó cung cấp API phù hợp với từng Client).
Nhược điểm: Nó sẽ trở thành nút thắt cổ chai khi phát triển hệ thống. Developer cần phải cập nhập API Gateway để cung cấp cho các endpoint của microservice. Quan trọng là phải làm cho quá trình cập nhật API Gateway càng nhẹ càng tốt.
API Gateway demo
Có nhiều lựa chọn để làm API Gateway chuyên dụng như: Kong API, Tik,... hay gần đây có traefik
Chúng ta sẽ sử dụng Nginx - một Reverse proxy server với load balancing, SSL,... Đầu tiên tạo 2 services như sau: mentor, mentee. Về cơ bản thì services thứ nhất sẽ trả về mentee và detail định nghĩa như sau:
const express = require('express'); const app = express(); app.get('/', (req,res) => { res.status(200).json({ data: { id: '1', type: 'mentee', attributes: { name: 'NamDV', } } }) }) app.get('/namdv', (req,res) => { res.status(200).json({ data: { id: '1', type: 'mentee', attributes: { name: 'NamDV', class: 'C13' } } }) }) app.listen(3000, () => { console.log('App is running at port 3000'); })
Và services còn lại sẽ trả về mentor định nghĩa như sau:
const express = require('express'); const app = express(); app.get('/', (req,res) => { res.status(200).json({ data: { id: '1', type: 'mentor', attributes: { name: 'HaiDV', } } }) }) app.listen(3001, () => { console.log('App is running at port 3001'); })
Nhiệm vụ của chúng ta giờ phải deploy một API gateway để gom và điều phối request từ client. Chúng ta config nginx cơ bản như sau:
upstream app1_upstream { # app: docker-compose.yml/app server app1:3000; } upstream app2_upstream { # app: docker-compose.yml/app server app2:3001; } server { listen 80; server_name uptodown.dev www.uptodown.dev; ... location /mentee { rewrite ^/mentee/(.*) /$1 break; proxy_pass http://app1_upstream/$1; } location /mentor { rewrite ^/mentor/(.*) /$1 break; proxy_pass http://app2_upstream/$1; } }
upstream định nghĩa một pool của các server mà NGINX sẽ gửi các request tới và định nghĩa tên để tham chiếu sau này. Có thể hiểu là mỗi upstream là một load balancer.
Ở đây mọi người cần chú ý phần location. Nginx sẽ phân tích URI của request để tìm ra hướng xử lí của request dựa vào các block location. Với những request có URI là /mentee hoặc /mentee/11 sẽ được sử lý trong location block đầu tiên và tương tự /mentor cũng vậy.
- rewrite option sẽ viết lại URI tới dựa trên một regular expression để location block có thể xử lý nó. Ở đây ví dụ như request URI là /mentee/namdv sẽ được regex bắt lại và nginx rewrite thành /namdv
- break flag ở cuối có thể hiểu là nó sẽ dừng hẳn process sau khi thay đổi URI và URI đã write sẽ ko tới các location khác trong file config.
- proxy_pass sẽ gửi request tới một proxy server cụ thể. Ở đây là http://app1_upstream/namdv chẳng hạn (routes do service đầu tiên đã định nghĩa