Đừng lặp lại chính mình hoặc DRY là một nguyên tắc quan trọng trong phát triển phần mềm. Bài đăng này sẽ chỉ cho bạn cách áp dụng nó vào cấu hình Apache APISIX.
"Đừng lặp lại chính mình" (DRY) là một nguyên tắc phát triển phần mềm nhằm mục đích giảm sự lặp lại của thông tin có khả năng thay đổi, thay thế thông tin bằng các khái niệm trừu tượng ít có khả năng thay đổi hơn hoặc sử dụng chuẩn hóa dữ liệu để tránh trùng lặp ngay từ đầu.
Ý tưởng chính đằng sau DRY là nếu bạn lặp lại và thông tin thay đổi, thì bạn phải cập nhật thông tin đã thay đổi ở nhiều nơi. Không chỉ tốn thêm công sức; có khả năng bạn sẽ quên mất và có thông tin khác nhau ở nhiều nơi khác nhau. DRY tỏa sáng trong việc sửa lỗi.
Hãy tưởng tượng một đoạn mã có lỗi. Hãy tưởng tượng bây giờ bạn đã sao chép đoạn mã ở hai nơi khác nhau. Bây giờ, bạn phải sửa lỗi ở hai nơi này và đó là phần dễ; phần khó là phải biết về sự trùng lặp ngay từ đầu.
Có khả năng cao là người sao chép và người sửa lỗi là khác nhau. Nếu đoạn mã đã được cấu trúc lại để có thể chia sẻ và được gọi từ hai nơi thay vào đó, bạn chỉ cần sửa lỗi ở một nơi này.
Hầu hết mọi người liên tưởng DRY với mã. Tuy nhiên, nó có thể hạn chế hơn và trái ngược với ý tưởng ban đầu.
Nguyên tắc này đã được Andy Hunt và Dave Thomas xây dựng trong cuốn sách The Pragmatic Programmer của họ. Họ áp dụng nó khá rộng rãi để bao gồm các lược đồ cơ sở dữ liệu, kế hoạch kiểm tra, hệ thống xây dựng, thậm chí cả tài liệu.
Hệ thống cấu hình âm thanh cho phép DRY hoặc thậm chí khuyến khích nó.
Apache APISIX cung cấp cấu hình DRY ở hai nơi.
Trong bối cảnh thương mại điện tử, hành trình mới bắt đầu của bạn để xác định tuyến đường trên Apache APISIX có thể bắt đầu như sau:
routes: - id: 1 name: Catalog uri: /products* upstream: nodes: "catalog:8080": 1
Nếu bạn quen thuộc với APISIX, chúng tôi đã định nghĩa một tuyến đường đến danh mục theo URI /products
. Tuy nhiên, có một vấn đề: bạn có thể muốn khách hàng tiềm năng duyệt danh mục nhưng muốn ngăn mọi người tạo, xóa hoặc cập nhật sản phẩm. Tuy nhiên, tuyến đường này khớp với mọi phương thức HTTP theo mặc định.
Chúng ta chỉ nên cho phép người dùng đã xác thực quản lý danh mục để mọi người có thể tự do duyệt. Để triển khai phương pháp này, chúng ta cần chia tuyến đường thành hai:
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] #1 uri: /products* upstream: #2 nodes: "catalog:8080": 1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] #3 uri: /products* plugins: key-auth: ~ #4 upstream: #2 nodes: "catalog:8080": 1
key-auth
là plugin đơn giản nhất cho mục đích này
Chúng tôi đã khắc phục sự cố bảo mật theo cách đơn giản nhất có thể: bằng cách sao chép-dán. Bằng cách đó, chúng tôi đã sao chép phần upstream
. Nếu chúng tôi cần thay đổi cấu trúc, ví dụ , bằng cách thêm hoặc xóa các nút, chúng tôi phải thực hiện ở hai nơi. Điều này phá vỡ nguyên tắc DRY.
Trong các tình huống thực tế, đặc biệt là khi chúng liên quan đến container, bạn sẽ không triển khai upstream
bằng cách liệt kê nodes
. Thay vào đó, bạn nên triển khai khám phá dịch vụ động để thích ứng với các thay đổi về cấu trúc. Tuy nhiên, điểm vẫn đúng khi bạn cần thay đổi cấu hình hoặc triển khai khám phá dịch vụ. Do đó, quan điểm của tôi áp dụng như nhau cho các nút và khám phá dịch vụ.
Cùng với trừu tượng Route , APISIX cung cấp trừu tượng Upstream để triển khai DRY. Chúng ta có thể viết lại đoạn mã trên như sau:
upstreams: - id: 1 #1 name: Catalog nodes: "catalog:8080": 1 routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /products* upstream_id: 1 #2 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /products* upstream_id: 1 #2 plugins: key-auth: ~
1
Nếu có bất cứ điều gì xảy ra trong cấu trúc, chúng ta phải cập nhật thay đổi chỉ trong Upstream duy nhất.
Lưu ý rằng việc xác định nhúng upstream
và tham chiếu nó với upstream_id
là loại trừ lẫn nhau .
Một lĩnh vực khác mà APISIX có thể giúp bạn DRY cấu hình của mình với sự trừu tượng hóa Plugin . APISIX triển khai hầu hết các tính năng, nếu không muốn nói là tất cả, thông qua các plugin
Hãy triển khai phiên bản dựa trên đường dẫn trên API của chúng ta. Chúng ta cần viết lại URL trước khi chuyển tiếp nó.
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] #1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] #1
/v1
trước khi chuyển tiếp
Giống như upstream
ở trên, phần plugins
được sao chép. Chúng ta cũng có thể đưa cấu hình plugin vào đối tượng Plugin Config chuyên dụng. Đoạn mã sau có cùng hiệu ứng như đoạn mã trên:
plugin_configs: - id: 1 #1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 #2 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 #2
Những độc giả tinh ý có thể nhận thấy rằng tôi đã bỏ sót một phần cấu hình: auth-key
đã biến mất một cách bí ẩn! Thật vậy, tôi đã xóa nó vì mục đích làm rõ.
Không giống như upstream
và upstream_id
, plugins
và plugin_config_id
không loại trừ lẫn nhau . Chúng ta có thể khắc phục sự cố chỉ bằng cách thêm plugin
bị thiếu:
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 plugins: key-auth: ~ #1
Theo cách này, bạn có thể di chuyển cấu hình được chia sẻ đến đối tượng plugin_config
và giữ một cấu hình cụ thể ở nơi nó áp dụng. Nhưng nếu cùng một plugin với các cấu hình khác nhau được sử dụng trong plugin_config
và trực tiếp trong route
thì sao? Tài liệu khá rõ ràng về điều này:
Consumer
>Consumer Group
>Route
>Plugin Config
>Service
Tóm lại, cấu hình plugin
trong một route
sẽ ghi đè lên cấu hình trong plugin_config_id
. Nó cũng cho phép chúng ta cung cấp biến apikey
cho plugin key-auth
trong một consumer
và chỉ đặt nó trong một route. APISIX sẽ tìm và sử dụng khóa cho mỗi consumer
!
DRY không chỉ liên quan đến mã; mà còn liên quan đến quản lý dữ liệu nói chung. Cấu hình là dữ liệu và do đó nằm trong phạm vi chung này.
APISIX cung cấp hai tùy chọn DRY: một cho upstream
- upstream_id
và một cho plugin
- plugin_config_id
. Upstream là độc quyền; plugin cho phép ghi đè.
Cả hai cơ chế đều giúp bạn DRY cấu hình của mình và giúp cấu hình dễ bảo trì hơn trong thời gian dài.
Để đi xa hơn:
Được xuất bản lần đầu tại A Java Geek vào ngày 1 tháng 9 năm 2024