kayx23 commented on code in PR #13936: URL: https://github.com/apache/apisix/pull/13936#discussion_r4017905881
########## docs/en/latest/plugins/limit-conn.md: ########## @@ -1567,3 +1567,153 @@ Response: 429 Response: 200 Response: 200 ``` + +### Apply Rate Limiting in Stream Proxy + +The `limit-conn` Plugin can also be used on a [stream Route](../stream-proxy.md) to limit the number of concurrent TCP connections. + +The following example demonstrates how to rate limit TCP connections by `remote_addr`, with example connection and burst thresholds. + +:::note + +When `key_type` is `var` (the default), `key` is resolved as an [NGINX stream module variable](https://nginx.org/en/docs/stream/ngx_stream_core_module.html). It is not limited to `remote_addr` or `server_addr`: any variable available in the stream context, such as `server_port`, can be used. + +::: + +Create a stream Route with `limit-conn` Plugin as such: + +<Tabs groupId="api"> +<TabItem value="admin-api" label="Admin API"> + +```shell +curl "http://127.0.0.1:9180/apisix/admin/stream_routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "limit-conn-stream-route", + "plugins": { + "limit-conn": { + "conn": 2, + "burst": 1, + "default_conn_delay": 0.1, + "key_type": "var", + "key": "remote_addr" + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1995": 1 Review Comment: The example is not runnable as written because it does not start a TCP service on `127.0.0.1:1995`. It also depends on stream mode and a TCP listener on port `9100`, but that prerequisite is only discoverable by leaving this section. Could you state the listener prerequisite here and provide a reachable upstream or the commands needed to create one? The Ingress example has the same issue because `tcp-echo.aic.svc` is not defined by the manifest. ########## docs/en/latest/plugins/limit-conn.md: ########## @@ -1567,3 +1567,153 @@ Response: 429 Response: 200 Response: 200 ``` + +### Apply Rate Limiting in Stream Proxy + +The `limit-conn` Plugin can also be used on a [stream Route](../stream-proxy.md) to limit the number of concurrent TCP connections. + +The following example demonstrates how to rate limit TCP connections by `remote_addr`, with example connection and burst thresholds. + +:::note + +When `key_type` is `var` (the default), `key` is resolved as an [NGINX stream module variable](https://nginx.org/en/docs/stream/ngx_stream_core_module.html). It is not limited to `remote_addr` or `server_addr`: any variable available in the stream context, such as `server_port`, can be used. + +::: + +Create a stream Route with `limit-conn` Plugin as such: + +<Tabs groupId="api"> +<TabItem value="admin-api" label="Admin API"> + +```shell +curl "http://127.0.0.1:9180/apisix/admin/stream_routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "limit-conn-stream-route", + "plugins": { + "limit-conn": { + "conn": 2, + "burst": 1, + "default_conn_delay": 0.1, + "key_type": "var", + "key": "remote_addr" + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1995": 1 + } + } + }' +``` + +</TabItem> +<TabItem value="adc" label="ADC"> + +```yaml title="adc.yaml" +services: + - name: tcp-echo-service + upstream: + name: default + scheme: tcp + nodes: + - host: 127.0.0.1 + port: 1995 + weight: 1 + stream_routes: + - name: limit-conn-stream-route + server_port: 9100 + plugins: + limit-conn: + conn: 2 + burst: 1 + default_conn_delay: 0.1 + key_type: var + key: remote_addr +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + +</TabItem> +<TabItem value="ingress" label="Ingress Controller"> + +<Tabs groupId="k8s-api"> +<TabItem value="gateway-api" label="Gateway API"> + +:::info + +Attaching L4 Plugins is currently not supported with Gateway API. This example cannot be completed with Gateway API. Review Comment: This is no longer accurate for the current released controller. APISIX Ingress Controller 2.2.0 introduced `apisix.apache.org/v1alpha1` `L4RoutePolicy`, which attaches stream plugins such as `limit-conn` to `TCPRoute`, `UDPRoute`, and `TLSRoute`. Please replace this callout with a `TCPRoute` plus `L4RoutePolicy` example, or qualify the limitation to controller versions before 2.2.0. ########## docs/en/latest/plugins/limit-conn.md: ########## @@ -1567,3 +1567,153 @@ Response: 429 Response: 200 Response: 200 ``` + +### Apply Rate Limiting in Stream Proxy + +The `limit-conn` Plugin can also be used on a [stream Route](../stream-proxy.md) to limit the number of concurrent TCP connections. + +The following example demonstrates how to rate limit TCP connections by `remote_addr`, with example connection and burst thresholds. + +:::note + +When `key_type` is `var` (the default), `key` is resolved as an [NGINX stream module variable](https://nginx.org/en/docs/stream/ngx_stream_core_module.html). It is not limited to `remote_addr` or `server_addr`: any variable available in the stream context, such as `server_port`, can be used. Review Comment: The stream plugin has a distinct, smaller schema: `conn`, `burst`, `default_conn_delay`, `only_use_default_delay`, `key`, and `key_type`; `conn` and `burst` are integers. The page’s existing Attributes table describes the HTTP plugin and includes HTTP-only fields such as Redis policies, `rules`, degradation, and custom HTTP rejection fields. Adding a stream example without separating or explicitly scoping those attributes can lead readers to apply unsupported fields to stream routes. Could this PR add a separate stream attribute table or clearly qualify the existing table? ########## docs/en/latest/plugins/limit-conn.md: ########## @@ -1567,3 +1567,153 @@ Response: 429 Response: 200 Response: 200 ``` + +### Apply Rate Limiting in Stream Proxy + +The `limit-conn` Plugin can also be used on a [stream Route](../stream-proxy.md) to limit the number of concurrent TCP connections. + +The following example demonstrates how to rate limit TCP connections by `remote_addr`, with example connection and burst thresholds. + +:::note + +When `key_type` is `var` (the default), `key` is resolved as an [NGINX stream module variable](https://nginx.org/en/docs/stream/ngx_stream_core_module.html). It is not limited to `remote_addr` or `server_addr`: any variable available in the stream context, such as `server_port`, can be used. + +::: + +Create a stream Route with `limit-conn` Plugin as such: + +<Tabs groupId="api"> +<TabItem value="admin-api" label="Admin API"> + +```shell +curl "http://127.0.0.1:9180/apisix/admin/stream_routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "limit-conn-stream-route", + "plugins": { + "limit-conn": { + "conn": 2, + "burst": 1, + "default_conn_delay": 0.1, + "key_type": "var", + "key": "remote_addr" + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1995": 1 + } + } + }' +``` + +</TabItem> +<TabItem value="adc" label="ADC"> + +```yaml title="adc.yaml" +services: + - name: tcp-echo-service + upstream: + name: default + scheme: tcp + nodes: + - host: 127.0.0.1 + port: 1995 + weight: 1 + stream_routes: + - name: limit-conn-stream-route + server_port: 9100 + plugins: + limit-conn: + conn: 2 + burst: 1 + default_conn_delay: 0.1 + key_type: var + key: remote_addr +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + +</TabItem> +<TabItem value="ingress" label="Ingress Controller"> + +<Tabs groupId="k8s-api"> +<TabItem value="gateway-api" label="Gateway API"> + +:::info + +Attaching L4 Plugins is currently not supported with Gateway API. This example cannot be completed with Gateway API. + +::: + +</TabItem> +<TabItem value="ingress" label="APISIX Ingress Controller"> + +```yaml title="limit-conn-stream-ic.yaml" +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: tcp-echo-service +spec: + type: ExternalName + externalName: tcp-echo.aic.svc + ports: + - name: tcp-echo + port: 1995 + targetPort: 1995 +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: limit-conn-stream-route +spec: + ingressClassName: apisix + stream: + - name: limit-conn-stream-route + protocol: TCP + match: + ingressPort: 9100 + backend: + serviceName: tcp-echo-service + servicePort: 1995 + plugins: + - name: limit-conn + enable: true + config: + conn: 2 + burst: 1 + default_conn_delay: 0.1 + key_type: var + key: remote_addr +``` + +Apply the configuration: + +```shell +kubectl apply -f limit-conn-stream-ic.yaml +``` + +</TabItem> +</Tabs> + +</TabItem> +</Tabs> + +❶ `key_type`: set to `var` to interpret `key` as a variable. + +❷ `key`: calculate rate limiting count by the connection's `remote_addr`. + +Open three concurrent TCP connections to the stream Route: + +```shell +seq 1 3 | xargs -n1 -P3 -I{} bash -c 'echo "hello" | nc -w 1 127.0.0.1 9100' Review Comment: With `conn: 2` and `burst: 1`, APISIX permits three concurrent connections; rejection starts with the fourth. This command opens only three, and the short `echo | nc -w 1` sessions may not overlap reliably, so it cannot verify the following rejection claim. Please use a deterministic test, such as `conn: 1`, `burst: 0`, holding one connection open while a second is reset, then retrying after the first closes. The documentation should also show the actual observed output. ########## t/stream-plugin/limit-conn.t: ########## @@ -339,3 +339,51 @@ GET /test_concurrency --- error_log The value of the configured key is empty, use client IP instead --- stream_enable + + + +=== TEST 11: key is a var other than remote_addr/server_addr +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/stream_routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "limit-conn": { + "conn": 2, + "burst": 1, + "default_conn_delay": 0.1, + "key": "server_port" + } + }, + "upstream_id": "1" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed + + + +=== TEST 12: exceeding the burst when keyed by a non-address var +--- request +GET /test_concurrency +--- response_body +200 +200 +200 Review Comment: This result does not prove that `server_port` was resolved and used as the limiter key. If lookup failed, the implementation would fall back to `remote_addr` and produce the same three-success/two-rejection pattern. Please assert that the logged limit key contains the expected listener port (the existing remote-address test uses this pattern) and assert that `The value of the configured key is empty` is absent. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
