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 ý đó:

gatewayviết thế nào
Envoyroute: { prefix_rewrite: "/" }
Kongstrip_path: true
OpenRestyproxy_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:

ý địnhcấu hìnhEnvoyKongOpenResty
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.

Hai dấu gạch chéo không phải chuyện thẩm mỹ Nhiều backend coi //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ì

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.