Bài 2
Backend nhận được đường dẫn gì
Chọn xong route mới là nửa việc. Nửa còn lại là gateway ghép đường dẫn nào để gửi lên backend,
và ba gateway làm việc đó theo hai nguyên lý khác nhau. Hệ quả cụ thể: cùng ý định “bỏ tiền
tố”, Envoy và OpenResty gửi lên //x/y còn Kong gửi /x/y.
Câu hỏi
Khách gửi /c/x/y. Gateway đã chọn được route khớp đoạn /c. Người viết
cấu hình muốn backend nhận /x/y, nghĩa là bỏ tiền tố đi. Mỗi gateway có một cách
diễn đạt ý đó:
| gateway | viết thế nào |
|---|---|
| Envoy | route: { prefix_rewrite: "/" } |
| Kong | strip_path: true |
| OpenResty | proxy_pass http://backend:8080/; |
Backend là nginx trả về đúng đường dẫn nó nhận, nên kết quả đọc thẳng từ phản hồi.
Mười chín tổ hợp
Mọi hàng dưới đây đều là một lần curl thật, request luôn là /c/x/y:
| ý định | cấu hình | Envoy | Kong | OpenResty |
|---|---|---|---|---|
| không đổi gì | — / strip_path: false / proxy_pass không có URI | /c/x/y | /c/x/y | /c/x/y |
| bỏ tiền tố | "/" / strip_path: true / proxy_pass …:8080/ | //x/y | /x/y | //x/y |
| đổi sang /b | "/b" / service url …/b + strip_path / proxy_pass …:8080/b | /b/x/y | /b/x/y | /b/x/y |
| đích có gạch chéo cuối | "/b/" / service url …/b/ + strip_path / proxy_pass …:8080/b/ | /b//x/y | /b/x/y | /b//x/y |
| gạch chéo ở cả hai phía | mẫu "/c/" cộng đích "/b/" | /b/x/y | /b/x/y | /b/x/y |
| giữ tiền tố rồi thêm /b | Kong: service url …/b + strip_path: false | — | /b/c/x/y | — |
| dùng regex thay prefix | Envoy: regex_rewrite ^/c/(.*)$ → /b/$1 | /b/x/y | — | — |
Riêng với Kong còn ba lần curl nữa để thử xem dấu gạch chéo có làm nó lệch không: route
/c/ với service …/b/, với …/b, và với địa chỉ không có
path. Cả ba đều cho đường dẫn sạch — /b/x/y, /b/x/y và
/x/y. Kong không nhạy với dấu gạch chéo ở bất kỳ phía nào.
Vì sao có hai dấu gạch chéo
Bảng trên rút gọn lại thành một câu. Envoy và nginx thay thế thuần văn bản
đúng đoạn đã khớp: lấy đường dẫn, cắt bỏ phần đầu bằng độ dài của mẫu, rồi dán chuỗi đích vào
trước. Mẫu /c không gồm dấu gạch chéo tiếp theo, nên phần còn lại là
/x/y — vẫn mang dấu gạch chéo ở đầu. Dán / vào trước thì thành
//x/y.
Kong thì cắt theo đoạn đường dẫn rồi ghép lại bằng đúng một dấu gạch chéo, và
bỏ luôn dấu gạch chéo cuối của path trong địa chỉ service. Vì vậy bốn tổ hợp route
/c hay /c/ với service …/b hay …/b/ đều cho
cùng một kết quả /b/x/y.
//x/y khác hẳn /x/y: bộ định tuyến của framework
thấy một đoạn rỗng ở đầu và không khớp route nào; kho đối tượng coi đó là một khoá khác hẳn;
và bộ nhớ đệm coi đó là hai địa chỉ khác nhau nên lưu hai bản. Chuyện thường lộ ra rất muộn,
vì trang chủ /c thì vẫn chạy còn /c/x/y mới hỏng.
Cách sửa
Với Envoy và OpenResty, đặt dấu gạch chéo cuối ở cả hai phía: mẫu
/c/ cộng đích /b/. Lúc đó phần còn lại là x/y không có
gạch chéo đầu, dán vào /b/ ra /b/x/y sạch — đã đo, hàng thứ năm của
bảng.
Cái giá là mẫu /c/ không còn khớp chính /c nữa, nên thường phải thêm
một route riêng cho đường dẫn trần hoặc một lệnh chuyển hướng. Với Envoy còn một lối khác là
regex_rewrite, nơi bạn tự viết ra chính xác phần muốn giữ:
route:
cluster: backend
regex_rewrite:
pattern: { regex: '^/c/(.*)$' }
substitution: '/b/$1'
Tổ hợp đó cho /b/x/y — đúng như mong đợi và không phụ thuộc vào dấu gạch chéo của mẫu.
Một cái bẫy của Envoy gặp ngay khi dựng bộ đo
Cấu hình Envoy đầu tiên của bộ đo này thiếu khối http_filters với bộ lọc
router. Kết quả: Envoy khởi động sạch sẽ, không một dòng lỗi,
cổng 8000 nhận kết nối, request gửi đi trọn vẹn — rồi không bao giờ có phản hồi.
Log ở mức info vẫn in starting main dispatch loop và
all dependencies initialized như bình thường.
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
Triệu chứng giống hệt backend chết hoặc mạng hỏng, nên dễ đi tìm sai chỗ. Cách phân biệt:
curl -v cho thấy kết nối đã thiết lập và request đã gửi xong rồi
mới hết thời gian chờ — một backend không tới được sẽ hỏng sớm hơn thế.
Phòng thí nghiệm
Đặt đường dẫn, đoạn đã khớp và cách viết lại của từng gateway, rồi xem backend nhận được gì. Thuật toán là bản viết lại của cả ba và đã khớp 19/19 lần curl của bộ đo.
Cấu hình
Backend nhận được gì
Nhớ gì
- Envoy
prefix_rewritevà nginxproxy_passcó URI đều là thay thế thuần văn bản của đoạn đã khớp; dấu gạch chéo là việc của người viết cấu hình. - Kong
strip_pathcắt theo đoạn đường dẫn và ghép lại bằng đúng một dấu gạch chéo, nên không sinh ra hai gạch chéo ở bất kỳ tổ hợp nào. - Cùng ý định bỏ tiền tố: Envoy và OpenResty cho
//x/y, Kong cho/x/y. - Cách sửa cho Envoy và nginx là đặt gạch chéo cuối ở cả hai phía, hoặc dùng
regex_rewrite. - Envoy thiếu bộ lọc
routerthì khởi động sạch rồi treo mọi request, không báo lỗi gì.
Bài trước trả lời nửa còn lại: cùng một bộ route, ba gateway chọn khác nhau.