Nếu bạn đã hoặc đang làm công việc backend development chắc hẳn bạn đã từng nghe qua về hai thuật ngữ Forward Proxy & Reverse Proxy ở đâu đó.
Trong bài viết lần này (nối tiếp bài viết Tìm hiểu nhanh về nginx - Phần 1) tôi xin được trình bày cụ thể hơn về Forward Proxy & Reverse Proxy (khái niệm cũng như ứng dụng của chúng).
Forward Proxy
Forward Proxy hoặc có thể gọi tắt là Proxy là một "thực thể trung gian" nằm giữa client và internet. Bạn có thể tưởng tượng như dưới đây:
Nếu có server:
Lúc này thay vì kết nối trực tiếp tới server thì client sẽ "kết nối" tới server thông qua proxy và proxy sẽ "thay mặt" cho client để kết nối tới server.
Và ở chiều ngược lại thì server sẽ chỉ kết nối với proxy chứ không kết nối với client.
OK, vậy thì mục đích chính của proxy là gì ??? Nói một cách đơn giản đó là:
- Hạn chế truy cập đến các trang như facebook.com hoặc các trang có nội dung 18+, ...
- Chỉ có phép client truy cập đến một phần tài nguyên của site thay vì toàn bộ (restrict resource access)
- Log lại các hoạt động trên internet (If you know what I mean =)))))
- ...
Ở đây tôi có tóm tắt lại bằng một sơ đồ đơn giản để các bạn có thể tiện hình dung:
Reverse Proxy
Reverse Proxy là một "thực thể trung gian" nằm giữa internet và server, có thể minh hoạ như sau:
Reverse Proxy sẽ "đại diện" cho server, nhận mọi requests từ phía client, "gửi" chúng tới server và "nhận" response từ server sau đó "trả về" cho client.
Vì Reverse Proxy "đại diện" cho server nên CLIENT SẼ KHÔNG TƯƠNG TÁC TRỰC TIẾP VỚI SERVER thay vào đó CLIENT SẼ CHỈ BIẾT RẰNG NÓ ĐANG TƯƠNG TÁC VỚI REVERSE PROXY mà thôi.
OK, vậy thì mục đích của reverse proxy là gì ??? Ta có thể liệt kê ra như sau:
- Dùng để ẨN server khỏi client khi ta KHÔNG MUỐN PUBLIC SERVER
- Trong trường hợp hệ thống của bạn có nhiều hơn một server thì Reverse Proxy có thể hoặt động như một load balancer với một đích "phân tải" đến các servers trong hệ thống do Reverse Proxy nằm ngay phía trước server.
- ...
Tôi cũng tiến hành tóm tắt cho "Reverse Proxy" tương tự như với "Forward Proxy" để các bạn tiện hình dung như sau:
Demo
Nói lí thuyết vậy là đủ, giờ ta sẽ đi vào phần demo. Đầu tiên ta sẽ tiến hành một thử nghiệm "nho nhỏ" với Forward Proxy. Ở đây tôi tạo một client kết nối tới http://google.com
thông qua "Forward Proxy" giống như hình minh hoạ sau:
Tôi sẽ sử dụng thư viện request
của javascript đế gửi request tới địa chỉ http://google.com
thông qua proxy như sau:
const request = require('request'); request({ url: 'http://www.google.com/', method: 'GET', proxy: 'http://127.0.0.1:8888',
}, (err, response, body) => { if (!err && response.statusCode === 200) { console.log(body); }
});
Tôi sẽ thiết lập cấu hình cho nginx như sau:
events {} http { server { listen 8888 default_server; access_log log/access.log; error_log log/error.log debug; location / { resolver 8.8.8.8; proxy_pass https://$host$request_uri; } }
}
Nginx sẽ lắng nghe ở cổng 8888 của localhost. Request được gửi tới địa chỉ http://localhost:8888/
sẽ được chuyển tiếp (forward) tới https://$host$request_uri
, ở đây:
$host
là tên của host nằm trong request header (trong ví dụ lần nàyhost = google.com
$request_uri
là URI nằm sau hostname (VD: vớigoogle.com/status
thì$request_uri
sẽ bằng/status
)
Bây giờ hãy kiểm tra log của nginx:
Bạn có thể thấy rằng, client thay vì gửi trực tiếp request đến http://google.com
, nó sẽ gửi request "thông qua" proxy, proxy sẽ "thay mặt" cho client gửi request đến http://google.com
. Sau đó khi proxy nhận được response từ http://google.com
nó cũng sẽ trả về cho client như log dưới đây:
OK, vậy là ta xong phần demo cho "Forward Proxy".
Với Reverse Proxy tôi sẽ tạo ra 3 servers lần lượt lắng nghe ở các cổng 1111, 2222, 3333 bằng expressJS như sau:
Server1 - lắng nghe ở cổng 1111
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Server 1\n');
}); app.listen(1111, () => { console.log('Listening on port 1111');
});
Server2 - lắng nghe ở cổng 2222
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Server 2\n');
}); app.listen(2222, () => { console.log('Listening on port 2222');
});
Server3 - lắng nghe ở cổng 3333
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Server 3\n');
}); app.listen(3333, () => { console.log('Listening on port 3333');
});
Và cấu hình cho nginx như sau:
events {} http { upstream express_servers { server localhost:1111; server localhost:2222; server localhost:3333; } server { listen 8888; location / { proxy_pass http://express_servers; } }
}
Giải thích một chút về cấu hình nginx ở trên, nginx sẽ lắng nghe ở cổng 8888 của localhost, mọi request tới http://localhost:8888/
sẽ được chuyển tiếp (forward) tới một trong ba servers trong danh sách express_servers (Server1, Server2, Server3).
Giải thuật chuyển tiếp sử dụng ở đây là Roung Robin.
Nói qua thì đây là một giải thuật dùng để chuyển tiếp quay vòng các requests tới các servers dựa theo trong số tương ứng của từng server. Server với trọng số càng cao thì khả năng nhận được request càng cao và ngược lại. Mặc định thì trọng số của các servers là như nhau.
Để kiểm tra xem "Reverse Proxy" có hoạt động như mong muốn hay không, tôi sử dụng lệnh:
while sleep1; do curl http://localhost:8888; done
Lệnh trên sẽ thực thi curl http://localhost:8888 từng giây một. Và đây là kết quả thu được:
Các requests được phân bổ đều lên các Server1, Server2 và Server3.
OK, vậy là ta đã xong phần demo cho Reverse Proxy.
Hi vọng những chia sẻ trên đây của tôi sẽ giúp ích cho bạn đọc trong quá trình học hỏi cũng như hành nghề sau này. Hẹn gặp lại các bạn ở các bài viết tiếp theo.