This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 71b4eb16d8 docs: refresh README and architecture diagram (#7209)
71b4eb16d8 is described below
commit 71b4eb16d87958adc5c8d109ef18100de429f1a0
Author: Liming Deng <[email protected]>
AuthorDate: Thu Sep 24 13:45:02 2026 +0800
docs: refresh README and architecture diagram (#7209)
Co-authored-by: aias00 <[email protected]>
---
README.md | 303 +++++++++-------------
docs/architecture/generate_shenyu_architecture.py | 239 +++++++++++++++++
docs/architecture/shenyu-architecture.png | Bin 0 -> 533728 bytes
docs/architecture/shenyu-architecture.svg | 148 +++++++++++
4 files changed, 503 insertions(+), 187 deletions(-)
diff --git a/README.md b/README.md
index d64b73598e..9c1f13d928 100644
--- a/README.md
+++ b/README.md
@@ -1,225 +1,154 @@
-
-
-
<p align="center">
- <strong>Scalable, High Performance, Responsive API Gateway Solution for all
MicroServices</strong>
+ <picture>
+ <source media="(prefers-color-scheme: dark)"
srcset="https://raw.githubusercontent.com/apache/shenyu-website/main/static/img/logo-light.svg">
+ <source media="(prefers-color-scheme: light)"
srcset="https://raw.githubusercontent.com/apache/shenyu-website/main/static/img/logo.svg">
+ <img alt="Apache ShenYu"
src="https://raw.githubusercontent.com/apache/shenyu-website/main/static/img/logo.svg"
width="260">
+ </picture>
</p>
+
<p align="center">
- <a href="https://shenyu.apache.org/">https://shenyu.apache.org/</a>
+ <a
href="https://search.maven.org/search?q=g:org.apache.shenyu%20AND%20a:shenyu"><img
src="https://img.shields.io/maven-central/v/org.apache.shenyu/shenyu.svg?label=maven%20central"
alt="Maven Central release" /></a>
+ <a href="LICENSE"><img
src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="Apache
2.0 license" /></a>
+ <a href="https://github.com/apache/shenyu/actions/workflows/ci.yml"><img
src="https://github.com/apache/shenyu/actions/workflows/ci.yml/badge.svg"
alt="CI status" /></a>
+ <a href="https://codecov.io/gh/apache/shenyu"><img
src="https://codecov.io/gh/apache/shenyu/branch/master/graph/badge.svg"
alt="Codecov coverage" /></a>
+ <a href="https://hub.docker.com/r/apache/shenyu-bootstrap/tags"><img
src="https://img.shields.io/docker/pulls/apache/shenyu-bootstrap" alt="Docker
pulls" /></a>
+ <a href="https://gitpod.io/#https://github.com/apache/shenyu"><img
src="https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green"
alt="Contribute with Gitpod" /></a>
+ <a href="https://deepwiki.com/apache/shenyu"><img
src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki" /></a>
</p>
<p align="center">
- <a href="https://shenyu.apache.org/docs/">
- <img src="https://img.shields.io/badge/document-English-blue.svg" alt="EN
docs" />
- </a>
- <a href="https://shenyu.apache.org/zh/docs/">
- <img src="https://img.shields.io/badge/文档-简体中文-blue.svg" alt="简体中文文档" />
- </a>
+ <a href="https://shenyu.apache.org/"><img
src="https://img.shields.io/badge/Official_Website-Explore-13c46a?style=for-the-badge"
alt="Official website" /></a>
+ <a href="https://shenyu.apache.org/download/"><img
src="https://img.shields.io/badge/QUICK%20DOWNLOAD-393af8?style=for-the-badge"
alt="Quick download" /></a>
</p>
<p align="center">
- <a target="_blank"
href="https://search.maven.org/search?q=g:org.apache.shenyu%20AND%20a:shenyu">
- <img
src="https://img.shields.io/maven-central/v/org.apache.shenyu/shenyu.svg?label=maven%20central"
/>
- </a>
- <a target="_blank"
href="https://github.com/apache/shenyu/blob/master/LICENSE">
- <img
src="https://img.shields.io/badge/License-Apache%202.0-blue.svg?label=license"
/>
- </a>
- <a target="_blank"
href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
- <img src="https://img.shields.io/badge/JDK-17+-green.svg" />
- </a>
- <a target="_blank" href="https://github.com/apache/shenyu/actions">
- <img src="https://github.com/apache/shenyu/workflows/ci/badge.svg" />
- </a>
- <a target="_blank" href='https://github.com/apache/shenyu'>
- <img src="https://img.shields.io/github/forks/apache/shenyu.svg"
alt="github forks"/>
- </a>
- <a target="_blank" href='https://github.com/apache/shenyu'>
- <img src="https://img.shields.io/github/stars/apache/shenyu.svg"
alt="github stars"/>
- </a>
- <a target="_blank" href='https://github.com/apache/shenyu'>
- <img
src="https://img.shields.io/github/contributors/apache/shenyu.svg" alt="github
contributors"/>
- </a>
- <a target="_blank" href="https://codecov.io/gh/apache/shenyu">
- <img
src="https://codecov.io/gh/apache/shenyu/branch/master/graph/badge.svg" />
- </a>
- <a target="_blank"
href="https://hub.docker.com/r/apache/shenyu-bootstrap/tags">
- <image src="https://img.shields.io/docker/pulls/apache/shenyu-bootstrap"
alt="Docker Pulls"/>
- </a>
- <a target="_blank"
href="https://gitpod.io/#https://github.com/apache/shenyu">
- <image
src="https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green"/>
- </a>
- <a target="_blank" href="https://deepwiki.com/apache/shenyu">
- <img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki">
- </a>
+ <a href="https://trendshift.io/repositories/3415"><img
src="https://trendshift.io/api/badge/repositories/3415" alt="apache/shenyu on
Trendshift" width="250" height="55" /></a>
</p>
-<br/>
----
+## Overview
-# Architecture
-
- 
-
-----
+Apache ShenYu is a Java-based gateway for service proxying, protocol
conversion, and API governance. An extensible plugin chain processes requests,
while ShenYu Admin manages and distributes configuration to gateway replicas.
-# Why named Apache ShenYu
+## Core Capabilities
-ShenYu (神禹) is the honorific name of Chinese ancient monarch Xia Yu (also
known in later times as Da Yu),
-who left behind the touching story of the three times he crossed the Yellow
River for the benefit of the people and successfully managed the flooding of
the river.
-He is known as one of the three greatest kings of ancient China, along with
Yao and Shun.
+| Area | What ShenYu provides |
+| --- | --- |
+| Plugin routing and extensions | An ordered plugin chain for HTTP requests,
with selector and rule matching where applicable. Spring Boot starters select
plugins; [custom Java
plugins](https://shenyu.apache.org/docs/developer/custom-plugin/), SPI
implementations, and WASM plugin APIs extend the gateway. |
+| Protocols and upstreams | HTTP and Spring Cloud services, WebSocket
connections, and Apache Dubbo, gRPC, SOFA, and Tars backends. Optional TCP and
MQTT listeners provide additional ingress. |
+| Registration and discovery | Client SDKs register service addresses and API
metadata with Admin. Registry integrations support discovery; an optional
Kubernetes controller reconciles Ingress and Endpoints resources. |
+| Security and traffic control | WAF, signing, authentication plugins, load
balancing, rate limiting, and fault tolerance through Hystrix, Resilience4j,
and Sentinel. |
+| Caching and transformation | In-memory or Redis-backed response caching, URL
rewriting, redirection, and request/response transformation. |
+| Dynamic configuration | Admin persists plugins, selectors, rules, metadata,
and authentication data. WebSocket sync is the default; HTTP long polling,
ZooKeeper, Nacos, etcd, Consul, Apollo, and Polaris are available. Gateway
replicas apply updates to their local caches. |
+| Observability | Metrics and logging plugins, including Kafka, Pulsar,
Elasticsearch, and ClickHouse destinations; email and DingTalk alerts from
Admin. |
+| AI and MCP | AI proxy, prompt processing, token limits, sensitive-word
filtering, AI request/response transformation, and an MCP server plugin with
SSE and Streamable HTTP. |
- * Firstly, the name ShenYu is to promote the traditional virtues of our
Chinese civilisation.
+## Architecture
- * Secondly, the most important thing about the gateway is the governance of
the traffic.
+
- * Finally, the community will do things in a fair, just, open and
meritocratic way, paying tribute to ShenYu while also conforming to the Apache
Way.
+## Get Started
----
+Start with the [English documentation](https://shenyu.apache.org/docs/),
[中文文档](https://shenyu.apache.org/zh/docs/), or the [official
downloads](https://shenyu.apache.org/download/).
-# Features
+### Docker quick start
-* Proxy: Support for Apache® Dubbo™, Spring Cloud, gRPC, SOFA, TARS,
WebSocket, MQTT
-* Security: Sign, OAuth 2.0, JSON Web Tokens, WAF plugin
-* API governance: Request, response, parameter mapping, Hystrix, RateLimiter
plugin
-* Observability: Tracing, metrics, logging plugin
-* Dashboard: Dynamic traffic control, visual backend for user menu permissions
-* Extensions: Plugin hot-swapping, dynamic loading
-* Cluster: NGINX, Docker, Kubernetes
-* Language: provides .NET, Python, Go, Java client for API register
-
----
+Use Docker and OpenSSL to start ShenYu Admin, a gateway, and an example HTTP
service. Run the commands below in the same shell.
-# Quick Start (docker)
+#### Start the services
-### Create network for Shenyu
+```bash
+docker network create shenyu
-```
-> docker network create shenyu
-```
+export SHENYU_JWT_SECRETKEY="$(openssl rand -hex 32)"
+export SHENYU_SYNC_WEBSOCKET_TOKEN="$(openssl rand -hex 32)"
+export SHENYU_LOCAL_KEY="$(openssl rand -hex 24)"
+export SHENYU_LOCAL_SHA512KEY="$(printf %s "$SHENYU_LOCAL_KEY" | openssl dgst
-sha512 -r | awk '{print $1}')"
-### Run Apache ShenYu Admin
-
-```
-> docker pull apache/shenyu-admin
-> docker run -d --name shenyu-admin-quickstart -p 9095:9095 --net shenyu
apache/shenyu-admin
-```
+docker run -d --name shenyu-admin --network shenyu -p 127.0.0.1:9095:9095 \
+ -e SHENYU_JWT_SECRETKEY -e SHENYU_SYNC_WEBSOCKET_TOKEN \
+ apache/shenyu-admin:latest
-### Run Apache ShenYu Bootstrap
+docker run -d --name shenyu-demo --network shenyu nginx:stable-alpine
+docker run -d --name shenyu-bootstrap --network shenyu -p 127.0.0.1:9195:9195 \
+ -e SHENYU_SYNC_WEBSOCKET_URLS=ws://shenyu-admin:9095/websocket \
+ -e SHENYU_SYNC_WEBSOCKET_TOKEN \
+ -e SHENYU_HEARTBEAT_SERVERLISTS=http://shenyu-admin:9095 \
+ -e SHENYU_LOCAL_ENABLED=true -e SHENYU_LOCAL_SHA512KEY \
+ apache/shenyu-bootstrap:latest
```
-> docker pull apache/shenyu-bootstrap
-> docker run -d --name shenyu-quickstart -p 9195:9195 -e
"shenyu.local.enabled=true" -e
SHENYU_SYNC_WEBSOCKET_URLS=ws://shenyu-admin-quickstart:9095/websocket --net
shenyu apache/shenyu-bootstrap
-```
-### Set router
+Admin listens on `http://localhost:9095`; the gateway listens on
`http://localhost:9195`. Wait for both services to start, then check their
health endpoints:
-* Real request :http://127.0.0.1:8080/helloworld,
-
-```json
-{
- "name" : "Shenyu",
- "data" : "hello world"
-}
+```bash
+curl -fsS http://localhost:9095/actuator/health
+curl -fsS http://localhost:9195/actuator/health
```
-* Set routing rules (Standalone)
+#### Configure a sample route
-Add `localKey: 123456` to Headers. If you need to customize the localKey, you
can use the sha512 tool to generate the key based on plaintext and update the
`shenyu.local.sha512Key` property.
+The following request configures the `divide` plugin on this gateway to
forward `/index.html` to the example service:
-```
-curl --location --request POST
'http://localhost:9195/shenyu/plugin/selectorAndRules' \
---header 'Content-Type: application/json' \
---header 'localKey: 123456' \
---data-raw '{
+```bash
+curl -fsS http://localhost:9195/shenyu/plugin/selectorAndRules \
+ -H 'Content-Type: application/json' \
+ -H "localKey: ${SHENYU_LOCAL_KEY}" \
+ -d '{
"pluginName": "divide",
- "selectorHandler": "[{\"upstreamUrl\":\"127.0.0.1:8080\"}]",
- "conditionDataList": [{
- "paramType": "uri",
- "operator": "match",
- "paramValue": "/**"
- }],
+ "selectorHandler":
"[{\"upstreamUrl\":\"shenyu-demo:80\",\"protocol\":\"http\",\"weight\":100}]",
+ "conditionDataList": [
+ {"paramType": "uri", "operator": "match", "paramValue": "/index.html"}
+ ],
"ruleDataList": [{
- "ruleHandler": "{\"loadBalance\":\"random\"}",
- "conditionDataList": [{
- "paramType": "uri",
- "operator": "match",
- "paramValue": "/**"
- }]
+ "ruleHandler": "{\"loadBalance\":\"random\"}",
+ "conditionDataList": [
+ {"paramType": "uri", "operator": "match", "paramValue": "/index.html"}
+ ]
}]
-}'
+ }'
```
-> If the backend service handling the request is running on your host machine,
please set `upstreamUrl` to `host.docker.internal:8080` or specify IP address
if reachable from the container in the above command.
->
-> Add `--network host` to docker run command instead of `--net shenyu` also
works correctly.
-* Proxy request :http://localhost:9195/helloworld
-
-```json
-{
- "name" : "Shenyu",
- "data" : "hello world"
-}
+
+This request updates only this gateway instance; it does not write the route
to Admin. For centrally managed, durable routes, configure them in Admin with a
persistent database instead of the default in-memory H2 database.
+
+#### Verify the route
+
+```bash
+curl -i http://localhost:9195/index.html
```
----
-
-# Plugin
-
- Whenever a request comes in, Apache ShenYu will execute it by all enabled
plugins through the chain of responsibility.
-
- As the heart of Apache ShenYu, plugins are extensible and hot-pluggable.
-
- Different plugins do different things.
-
- Of course, users can also customize plugins to meet their own needs.
-
- If you want to customize, see
[custom-plugin](https://shenyu.apache.org/docs/developer/custom-plugin/) .
-
----
-
-# Selector & Rule
-
- According to your HTTP request headers, selectors and rules are used to
route your requests.
-
- Selector is your first route, It is coarser grained, for example, at the
module level.
-
- Rule is your second route and what do you think your request should do. For
example a method level in a module.
-
- The selector and the rule match only once, and the match is returned. So the
coarsest granularity should be sorted last.
-
----
-
-# Data Caching & Data Sync
-
- Since all data have been cached using ConcurrentHashMap in the JVM, it's
very fast.
-
- Apache ShenYu dynamically updates the cache by listening to the ZooKeeper
node (or WebSocket push, HTTP long polling) when the user changes configuration
information in the background management.
-
-

-
-

-
----
-
-# Prerequisite
-
- * JDK 17+
-
----
-
-# Stargazers over time
-
-[](https://starchart.cc/apache/shenyu.svg)
-
----
-
-# Contributor and Support
-
-* [How to Contribute](https://shenyu.apache.org/community/contributor-guide)
-* [Mailing Lists](mailto:[email protected])
-
----
-
-# Known Users
-
-In order of registration, More access companies are welcome to register at
[https://github.com/apache/shenyu/issues/68](https://github.com/apache/shenyu/issues/68)
(For open source users only) .
-
-All Users : [Known
Users](https://shenyu.apache.org/community/user-registration)
+
+The response should contain the NGINX welcome page served through ShenYu.
+
+## Why Apache ShenYu?
+
+ShenYu (神禹) is an honorific name for Xia Yu, an ancient Chinese ruler also
known as Da Yu. He is remembered for crossing the Yellow River three times for
the benefit of the people and successfully controlling its floods. Alongside
Yao and Shun, he is regarded as one of ancient China's three greatest kings.
+
+The name reflects three ideas:
+
+* It promotes the traditional virtues of Chinese civilization.
+* It echoes a gateway's central role in governing traffic.
+* It expresses the community's commitment to being fair, just, open, and
meritocratic, in tribute to ShenYu and in keeping with the Apache Way.
+
+## Community and Support
+
+* [Contribute to ShenYu](https://shenyu.apache.org/community/contributor-guide)
+* [Join the development mailing list](mailto:[email protected])
+
+## Known Users
+
+The [Known Users page](https://shenyu.apache.org/community/user-registration)
lists registered users in registration order.
+
+Organizations using Apache ShenYu are welcome to [register through GitHub
issue #68](https://github.com/apache/shenyu/issues/68). Registration is for
open source users only.
+
+## Star History
+
+<a href="https://www.star-history.com/?repos=apache%2Fshenyu&type=date">
+ <picture>
+ <source media="(prefers-color-scheme: dark)"
srcset="https://api.star-history.com/chart?repos=apache/shenyu&type=date&theme=dark"
/>
+ <source media="(prefers-color-scheme: light)"
srcset="https://api.star-history.com/chart?repos=apache/shenyu&type=date" />
+ <img alt="Apache ShenYu star history"
src="https://api.star-history.com/chart?repos=apache/shenyu&type=date" />
+ </picture>
+</a>
+
+## License
+
+Apache ShenYu is licensed under the [Apache License, Version 2.0](LICENSE).
diff --git a/docs/architecture/generate_shenyu_architecture.py
b/docs/architecture/generate_shenyu_architecture.py
new file mode 100644
index 0000000000..22ad187356
--- /dev/null
+++ b/docs/architecture/generate_shenyu_architecture.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Generate the README architecture diagram as a standalone SVG."""
+
+from pathlib import Path
+import sys
+from xml.etree import ElementTree as ET
+
+W, H = 1680, 1008
+TOP = 112
+NS = "http://www.w3.org/2000/svg"
+ET.register_namespace("", NS)
+SVG = ET.Element("{%s}svg" % NS, nsmap={None: NS})
+SVG.set("viewBox", f"0 {TOP} {W} {H}")
+SVG.set("width", str(W))
+SVG.set("height", str(H))
+SVG.set("role", "img")
+SVG.set("aria-label", "Apache ShenYu architecture: control plane configuration
sync, gateway request path, upstream services, and observability")
+SVG.append(ET.Comment("Licensed to the Apache Software Foundation (ASF) under
one or more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership. The
ASF licenses this file to You under the Apache License, Version 2.0.
http://www.apache.org/licenses/LICENSE-2.0"))
+
+def el(tag, **attrs):
+ return ET.SubElement(SVG, "{%s}%s" % (NS, tag), {k.replace("_", "-"):
str(v) for k, v in attrs.items()})
+
+def rect(x, y, w, h, fill, stroke="none", radius=0, sw=1, **kw):
+ return el("rect", x=x, y=y, width=w, height=h, rx=radius, fill=fill,
stroke=stroke, stroke_width=sw, **kw)
+
+def line(x1, y1, x2, y2, color, width=2, dash=None, marker=None):
+ a = dict(x1=x1, y1=y1, x2=x2, y2=y2, stroke=color, stroke_width=width,
stroke_linecap="round")
+ if dash: a["stroke_dasharray"] = dash
+ if marker: a["marker_end"] = f"url(#{marker})"
+ return el("line", **a)
+
+def path(d, color, width=2, dash=None, marker=None, fill="none"):
+ a = dict(d=d, stroke=color, stroke_width=width, stroke_linecap="round",
stroke_linejoin="round", fill=fill)
+ if dash: a["stroke_dasharray"] = dash
+ if marker: a["marker_end"] = f"url(#{marker})"
+ return el("path", **a)
+
+def txt(x, y, s, size=20, color="#12213A", weight=400, anchor="start",
spacing=None):
+ a = dict(x=x, y=y, fill=color, font_size=size, font_weight=weight,
text_anchor=anchor,
+ font_family="Inter, -apple-system, BlinkMacSystemFont, Segoe UI,
Arial, sans-serif")
+ if spacing: a["letter_spacing"] = spacing
+ t = el("text", **a)
+ t.text = s
+ return t
+
+def pill(x, y, w, label, fill, color, stroke="none", h=36, size=17):
+ rect(x, y, w, h, fill, stroke, h / 2)
+ txt(x + w/2, y + h/2 + size * .34, label, size, color, 650, "middle")
+
+def dot(x, y, r, color):
+ el("circle", cx=x, cy=y, r=r, fill=color)
+
+def arrow_marker(name, color):
+ defs = SVG.find("{%s}defs" % NS)
+ marker = ET.SubElement(defs, "{%s}marker" % NS, id=name, viewBox="0 0 10
10",
+ refX="9", refY="5", markerWidth="8",
markerHeight="8", orient="auto-start-reverse")
+ ET.SubElement(marker, "{%s}path" % NS, d="M 0 1 L 9 5 L 0 9 z", fill=color)
+
+ET.SubElement(SVG, "{%s}defs" % NS)
+arrow_marker("flow", "#E56A2F")
+arrow_marker("sync", "#2874CE")
+arrow_marker("register", "#128279")
+arrow_marker("telemetry", "#7B5BC7")
+
+# The README already has a project header; start the diagram at the control
plane.
+rect(0, TOP, W, H, "#F5F7FB")
+
+# Control plane panel.
+rect(50, 140, 1580, 268, "#EEF5FF", "#C9DDF8", 22, 2)
+pill(78, 157, 160, "01 CONTROL", "#D9E9FF", "#1D5CA5", h=39, size=17)
+txt(260, 184, "Admin owns configuration; sync updates gateway replicas", 22,
"#274366", 550)
+
+# Dashboard and client registration sources.
+rect(78, 219, 230, 68, "#FFFFFF", "#B9CBE1", 13, 2)
+rect(96, 239, 26, 22, "none", "#3673B8", 3, 2)
+line(99, 245, 119, 245, "#3673B8", 2)
+txt(139, 260, "Dashboard / API", 19, "#173556", 650)
+
+rect(78, 310, 230, 68, "#FFFFFF", "#A7D6D0", 13, 2)
+dot(108, 344, 12, "#D7F1ED")
+txt(108, 350, "S", 15, "#0B766F", 750, "middle")
+txt(139, 350, "Service SDK", 19, "#174C49", 650)
+
+# Admin and its database are an explicit bounded context.
+rect(370, 218, 365, 160, "#FFFFFF", "#8FB9EB", 16, 2)
+rect(370, 218, 365, 48, "#DCEBFF", radius=16)
+rect(370, 249, 365, 17, "#DCEBFF")
+txt(390, 250, "ShenYu Admin", 22, "#174A84", 750)
+txt(392, 294, "Config API · users · registration", 18, "#334E6C", 500)
+rect(392, 313, 320, 48, "#F7FAFE", "#CDDDEF", 9, 1.5)
+el("ellipse", cx="417", cy="328", rx="11", ry="4", fill="#D5E3F4",
stroke="#5080BB", stroke_width="1.5")
+path("M406 328 v15 c0 6 22 6 22 0 v-15", "#5080BB", 1.5)
+txt(443, 343, "Database · persisted config", 17, "#36516F", 600)
+
+# Sync channel.
+rect(812, 231, 483, 135, "#FFFFFF", "#8FB9EB", 16, 2)
+txt(838, 264, "Data sync", 22, "#174A84", 750)
+txt(838, 291, "Admin listener → gateway subscriber", 17, "#45617E", 500)
+pill(838, 309, 173, "WebSocket · default", "#E2F0FF", "#1F64A7", h=35, size=16)
+pill(1022, 309, 246, "HTTP · ZK · Nacos · etc.", "#F0F5FB", "#45617E", h=35,
size=16)
+
+# Config payload callout.
+rect(1374, 231, 229, 135, "#FFFFFF", "#C5D8ED", 16, 2)
+txt(1394, 264, "Synced data", 20, "#2D506F", 700)
+txt(1394, 293, "Plugin · Selector · Rule", 15.5, "#45617E", 500)
+txt(1394, 319, "Metadata · Auth", 16, "#45617E", 500)
+txt(1394, 345, "Upstream · AI keys", 16, "#45617E", 500)
+line(308, 253, 365, 253, "#2874CE", 3, marker="sync")
+line(308, 344, 365, 344, "#128279", 3, dash="7 6", marker="register")
+line(735, 298, 805, 298, "#2874CE", 3, marker="sync")
+line(1295, 298, 1367, 298, "#2874CE", 3, marker="sync")
+txt(335, 237, "edit", 14, "#386DA9", 600, "middle")
+txt(337, 332, "register", 14, "#0B766F", 600, "middle")
+
+# Data plane panel and left edge.
+rect(50, 438, 1580, 568, "#FFF8F2", "#F3D5BF", 22, 2)
+pill(78, 455, 132, "02 DATA", "#FFE5D3", "#A8491C", h=39, size=17)
+txt(230, 482, "HTTP request path · each gateway replica runs its own chain and
cache", 22, "#75482F", 550)
+
+rect(78, 702, 124, 105, "#FFFFFF", "#EAC4A9", 16, 2)
+rect(111, 726, 58, 39, "none", "#CF6E39", 5, 2.5)
+line(137, 767, 143, 767, "#CF6E39", 2.5)
+line(127, 774, 154, 774, "#CF6E39", 2.5)
+txt(140, 796, "Clients", 19, "#7D3D20", 700, "middle")
+
+rect(258, 702, 150, 105, "#FFFFFF", "#EAC4A9", 16, 2)
+path("M 315 745 l 19 -16 19 16 -19 17 z", "#CF6E39", 2, fill="#FFF0E3")
+line(334, 761, 334, 774, "#CF6E39", 2)
+txt(333, 796, "Proxy / LB", 19, "#7D3D20", 700, "middle")
+
+# Gateway cluster: slight stacked offset conveys replicas without drawing a
fake shared cache.
+rect(462, 523, 700, 463, "#EAD7C9", "#EBC4A9", 18, 1.5)
+rect(452, 513, 700, 463, "#F6E9DD", "#E7C3A7", 18, 1.5)
+rect(442, 503, 700, 463, "#FFFFFF", "#E6B58F", 18, 2.5)
+rect(442, 503, 700, 57, "#FFE3CF", radius=18)
+rect(442, 542, 700, 18, "#FFE3CF")
+txt(466, 540, "ShenYu gateway cluster", 23, "#96431F", 750)
+pill(765, 515, 157, "N replicas", "#FFFFFF", "#A65027", "#E7B48F", h=33,
size=16)
+
+# TCP and MQTT use protocol bootstrap servers alongside the WebFlux request
path.
+rect(474, 581, 180, 67, "#F0FAF8", "#9CD5CD", 12, 2)
+txt(492, 610, "TCP / MQTT", 18, "#15776F", 700)
+txt(492, 638, "dedicated listeners", 15, "#3B7772", 500)
+
+# Each replica's local config cache, fed from admin sync.
+rect(718, 581, 398, 67, "#EFF6FF", "#9ABFE8", 12, 2)
+txt(741, 610, "Local config cache", 19, "#225B98", 700)
+txt(741, 638, "Plugin · Selector · Rule · Metadata", 16, "#3D648C", 500)
+path("M 1054 366 V 578", "#2874CE", 3, marker="sync")
+rect(1110, 425, 180, 31, "#F5F7FB", radius=9)
+txt(1200, 446, "config change", 15, "#2366AB", 650, "middle")
+
+# Request handler.
+rect(474, 694, 180, 126, "#FFF7F0", "#DCA77F", 13, 2)
+txt(493, 733, "Spring WebFlux", 18, "#8D441F", 700)
+txt(493, 762, "ShenyuWebHandler", 15, "#75482F", 600)
+txt(493, 790, "entry point", 16, "#A26C4E", 450)
+
+# Plugin chain; category placement is explicitly examples, not an implied
fixed order.
+rect(718, 698, 398, 259, "#FFFFFF", "#E3A77A", 14, 2)
+txt(740, 726, "Ordered ShenyuPlugin chain", 20, "#913F1C", 750)
+txt(740, 751, "Configured order · dynamic plugin updates", 15, "#8D624D", 450)
+pill(740, 763, 172, "Security / traffic", "#FFF0E3", "#A94F22", h=31,
size=14.5)
+pill(923, 763, 169, "Cache / resilience", "#E9F4F1", "#33756B", h=31,
size=14.5)
+pill(740, 800, 172, "Transform / AI / MCP", "#EAF2FF", "#3465A3", h=31,
size=14)
+pill(923, 800, 169, "Metrics / logging", "#EFE8FF", "#6846A3", h=31, size=14.5)
+rect(740, 838, 352, 65, "#FFF5EC", "#F0C9AB", 9, 1.5)
+txt(755, 858, "Proxy / RPC plugins", 16, "#A84C20", 700)
+txt(755, 879, "Divide · Dubbo · SOFA · gRPC · Tars", 15, "#714A36", 500)
+txt(755, 898, "WebSocket · RPC context / transform", 14.5, "#714A36", 500)
+rect(740, 910, 352, 30, "#F5F7FB", radius=8)
+txt(916, 930, "Selector / Rule: parameter + predicate matching", 14.5,
"#3F536D", 550, "middle")
+path("M 917 649 V 694", "#2874CE", 2.5, marker="sync")
+
+# External request flow. Keep control and traffic arrows separate.
+line(202, 755, 252, 755, "#E56A2F", 3.5, marker="flow")
+line(408, 755, 468, 755, "#E56A2F", 3.5, marker="flow")
+line(654, 755, 712, 755, "#E56A2F", 3.5, marker="flow")
+line(1116, 755, 1194, 755, "#E56A2F", 3.5, marker="flow")
+txt(434, 739, "HTTP", 15, "#B1552B", 650, "middle")
+
+# Service landscape (actual protocol families in this checkout).
+rect(1200, 545, 402, 348, "#FFFFFF", "#DFB18F", 16, 2)
+rect(1200, 545, 402, 56, "#FFE8D8", radius=16)
+rect(1200, 583, 402, 18, "#FFE8D8")
+txt(1224, 582, "Upstream services", 22, "#914624", 750)
+txt(1224, 629, "HTTP / Spring Cloud", 19, "#6B432F", 650)
+line(1224, 647, 1578, 647, "#EDE2D8", 1.5)
+txt(1224, 681, "RPC", 16, "#A66342", 750)
+txt(1224, 708, "Dubbo · SOFA · gRPC · Tars", 18, "#6B432F", 550)
+line(1224, 729, 1578, 729, "#EDE2D8", 1.5)
+txt(1224, 761, "Streaming", 16, "#A66342", 750)
+txt(1224, 788, "WebSocket services", 18, "#6B432F", 550)
+rect(1224, 817, 354, 48, "#FFF8F2", radius=8)
+txt(1401, 846, "Backend apps own their APIs", 16, "#8D624D", 500, "middle")
+
+# Observability output is sourced from the gateway's plugins/agent hooks.
+rect(1200, 912, 402, 70, "#F4EFFD", "#CBB8EB", 13, 2)
+txt(1224, 941, "Observability sinks", 19, "#6746A0", 700)
+txt(1224, 967, "Metrics · logs · trace IDs", 17, "#70578D", 500)
+path("M 1116 884 H 1165 Q 1175 884 1175 894 V 947 H 1193", "#7B5BC7", 2.5,
dash="6 5", marker="telemetry")
+
+# Deployment artifact is called out without pretending it is in the request
chain.
+rect(78, 873, 330, 104, "#FFFFFF", "#D4C7BA", 13, 1.5)
+pill(96, 889, 118, "DEPLOY", "#F1EBE5", "#71594A", h=30, size=15)
+txt(96, 945, "shenyu-bootstrap image", 18, "#654D3F", 650)
+txt(96, 966, "Docker / Kubernetes replicas", 14, "#917767", 450)
+
+# Footer legend and concise architectural invariant.
+line(62, 1040, 1618, 1040, "#DCE4ED", 1.5)
+txt(68, 1077, "Flows", 17, "#51637A", 700)
+line(137, 1071, 185, 1071, "#E56A2F", 3, marker="flow")
+txt(199, 1077, "request", 17, "#51637A", 500)
+line(337, 1071, 385, 1071, "#2874CE", 3, marker="sync")
+txt(399, 1077, "config sync", 17, "#51637A", 500)
+line(565, 1071, 613, 1071, "#128279", 3, dash="7 6", marker="register")
+txt(627, 1077, "registration", 17, "#51637A", 500)
+line(817, 1071, 865, 1071, "#7B5BC7", 3, dash="6 5", marker="telemetry")
+txt(879, 1077, "telemetry", 17, "#51637A", 500)
+txt(1599, 1077, "Each replica reads its own local cache", 17, "#51637A", 550,
"end")
+
+output = sys.argv[1] if len(sys.argv) > 1 else
str(Path(__file__).with_name("shenyu-architecture.svg"))
+ET.indent(SVG, space=" ")
+ET.ElementTree(SVG).write(output, encoding="utf-8", xml_declaration=True)
+print(output)
diff --git a/docs/architecture/shenyu-architecture.png
b/docs/architecture/shenyu-architecture.png
new file mode 100644
index 0000000000..04f62ce474
Binary files /dev/null and b/docs/architecture/shenyu-architecture.png differ
diff --git a/docs/architecture/shenyu-architecture.svg
b/docs/architecture/shenyu-architecture.svg
new file mode 100644
index 0000000000..34eccff2d2
--- /dev/null
+++ b/docs/architecture/shenyu-architecture.svg
@@ -0,0 +1,148 @@
+<?xml version='1.0' encoding='utf-8'?>
+<svg xmlns="http://www.w3.org/2000/svg" nsmap="{None:
'http://www.w3.org/2000/svg'}" viewBox="0 112 1680 1008" width="1680"
height="1008" role="img" aria-label="Apache ShenYu architecture: control plane
configuration sync, gateway request path, upstream services, and observability">
+ <!--Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership. The ASF licenses this
file to You under the Apache License, Version 2.0.
http://www.apache.org/licenses/LICENSE-2.0-->
+ <defs>
+ <marker id="flow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8"
markerHeight="8" orient="auto-start-reverse">
+ <path d="M 0 1 L 9 5 L 0 9 z" fill="#E56A2F" />
+ </marker>
+ <marker id="sync" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8"
markerHeight="8" orient="auto-start-reverse">
+ <path d="M 0 1 L 9 5 L 0 9 z" fill="#2874CE" />
+ </marker>
+ <marker id="register" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="8" markerHeight="8" orient="auto-start-reverse">
+ <path d="M 0 1 L 9 5 L 0 9 z" fill="#128279" />
+ </marker>
+ <marker id="telemetry" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="8" markerHeight="8" orient="auto-start-reverse">
+ <path d="M 0 1 L 9 5 L 0 9 z" fill="#7B5BC7" />
+ </marker>
+ </defs>
+ <rect x="0" y="112" width="1680" height="1008" rx="0" fill="#F5F7FB"
stroke="none" stroke-width="1" />
+ <rect x="50" y="140" width="1580" height="268" rx="22" fill="#EEF5FF"
stroke="#C9DDF8" stroke-width="2" />
+ <rect x="78" y="157" width="160" height="39" rx="19.5" fill="#D9E9FF"
stroke="none" stroke-width="1" />
+ <text x="158.0" y="182.28" fill="#1D5CA5" font-size="17" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">01 CONTROL</text>
+ <text x="260" y="184" fill="#274366" font-size="22" font-weight="550"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Admin owns configuration; sync updates gateway
replicas</text>
+ <rect x="78" y="219" width="230" height="68" rx="13" fill="#FFFFFF"
stroke="#B9CBE1" stroke-width="2" />
+ <rect x="96" y="239" width="26" height="22" rx="3" fill="none"
stroke="#3673B8" stroke-width="2" />
+ <line x1="99" y1="245" x2="119" y2="245" stroke="#3673B8" stroke-width="2"
stroke-linecap="round" />
+ <text x="139" y="260" fill="#173556" font-size="19" font-weight="650"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Dashboard / API</text>
+ <rect x="78" y="310" width="230" height="68" rx="13" fill="#FFFFFF"
stroke="#A7D6D0" stroke-width="2" />
+ <circle cx="108" cy="344" r="12" fill="#D7F1ED" />
+ <text x="108" y="350" fill="#0B766F" font-size="15" font-weight="750"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">S</text>
+ <text x="139" y="350" fill="#174C49" font-size="19" font-weight="650"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Service SDK</text>
+ <rect x="370" y="218" width="365" height="160" rx="16" fill="#FFFFFF"
stroke="#8FB9EB" stroke-width="2" />
+ <rect x="370" y="218" width="365" height="48" rx="16" fill="#DCEBFF"
stroke="none" stroke-width="1" />
+ <rect x="370" y="249" width="365" height="17" rx="0" fill="#DCEBFF"
stroke="none" stroke-width="1" />
+ <text x="390" y="250" fill="#174A84" font-size="22" font-weight="750"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">ShenYu Admin</text>
+ <text x="392" y="294" fill="#334E6C" font-size="18" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Config API · users · registration</text>
+ <rect x="392" y="313" width="320" height="48" rx="9" fill="#F7FAFE"
stroke="#CDDDEF" stroke-width="1.5" />
+ <ellipse cx="417" cy="328" rx="11" ry="4" fill="#D5E3F4" stroke="#5080BB"
stroke-width="1.5" />
+ <path d="M406 328 v15 c0 6 22 6 22 0 v-15" stroke="#5080BB"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none" />
+ <text x="443" y="343" fill="#36516F" font-size="17" font-weight="600"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Database · persisted config</text>
+ <rect x="812" y="231" width="483" height="135" rx="16" fill="#FFFFFF"
stroke="#8FB9EB" stroke-width="2" />
+ <text x="838" y="264" fill="#174A84" font-size="22" font-weight="750"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Data sync</text>
+ <text x="838" y="291" fill="#45617E" font-size="17" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Admin listener → gateway subscriber</text>
+ <rect x="838" y="309" width="173" height="35" rx="17.5" fill="#E2F0FF"
stroke="none" stroke-width="1" />
+ <text x="924.5" y="331.94" fill="#1F64A7" font-size="16" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">WebSocket · default</text>
+ <rect x="1022" y="309" width="246" height="35" rx="17.5" fill="#F0F5FB"
stroke="none" stroke-width="1" />
+ <text x="1145.0" y="331.94" fill="#45617E" font-size="16" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">HTTP · ZK · Nacos · etc.</text>
+ <rect x="1374" y="231" width="229" height="135" rx="16" fill="#FFFFFF"
stroke="#C5D8ED" stroke-width="2" />
+ <text x="1394" y="264" fill="#2D506F" font-size="20" font-weight="700"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Synced data</text>
+ <text x="1394" y="293" fill="#45617E" font-size="15.5" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Plugin · Selector · Rule</text>
+ <text x="1394" y="319" fill="#45617E" font-size="16" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Metadata · Auth</text>
+ <text x="1394" y="345" fill="#45617E" font-size="16" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Upstream · AI keys</text>
+ <line x1="308" y1="253" x2="365" y2="253" stroke="#2874CE" stroke-width="3"
stroke-linecap="round" marker-end="url(#sync)" />
+ <line x1="308" y1="344" x2="365" y2="344" stroke="#128279" stroke-width="3"
stroke-linecap="round" stroke-dasharray="7 6" marker-end="url(#register)" />
+ <line x1="735" y1="298" x2="805" y2="298" stroke="#2874CE" stroke-width="3"
stroke-linecap="round" marker-end="url(#sync)" />
+ <line x1="1295" y1="298" x2="1367" y2="298" stroke="#2874CE"
stroke-width="3" stroke-linecap="round" marker-end="url(#sync)" />
+ <text x="335" y="237" fill="#386DA9" font-size="14" font-weight="600"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">edit</text>
+ <text x="337" y="332" fill="#0B766F" font-size="14" font-weight="600"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">register</text>
+ <rect x="50" y="438" width="1580" height="568" rx="22" fill="#FFF8F2"
stroke="#F3D5BF" stroke-width="2" />
+ <rect x="78" y="455" width="132" height="39" rx="19.5" fill="#FFE5D3"
stroke="none" stroke-width="1" />
+ <text x="144.0" y="480.28" fill="#A8491C" font-size="17" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">02 DATA</text>
+ <text x="230" y="482" fill="#75482F" font-size="22" font-weight="550"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">HTTP request path · each gateway replica runs its
own chain and cache</text>
+ <rect x="78" y="702" width="124" height="105" rx="16" fill="#FFFFFF"
stroke="#EAC4A9" stroke-width="2" />
+ <rect x="111" y="726" width="58" height="39" rx="5" fill="none"
stroke="#CF6E39" stroke-width="2.5" />
+ <line x1="137" y1="767" x2="143" y2="767" stroke="#CF6E39"
stroke-width="2.5" stroke-linecap="round" />
+ <line x1="127" y1="774" x2="154" y2="774" stroke="#CF6E39"
stroke-width="2.5" stroke-linecap="round" />
+ <text x="140" y="796" fill="#7D3D20" font-size="19" font-weight="700"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Clients</text>
+ <rect x="258" y="702" width="150" height="105" rx="16" fill="#FFFFFF"
stroke="#EAC4A9" stroke-width="2" />
+ <path d="M 315 745 l 19 -16 19 16 -19 17 z" stroke="#CF6E39"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="#FFF0E3"
/>
+ <line x1="334" y1="761" x2="334" y2="774" stroke="#CF6E39" stroke-width="2"
stroke-linecap="round" />
+ <text x="333" y="796" fill="#7D3D20" font-size="19" font-weight="700"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Proxy / LB</text>
+ <rect x="462" y="523" width="700" height="463" rx="18" fill="#EAD7C9"
stroke="#EBC4A9" stroke-width="1.5" />
+ <rect x="452" y="513" width="700" height="463" rx="18" fill="#F6E9DD"
stroke="#E7C3A7" stroke-width="1.5" />
+ <rect x="442" y="503" width="700" height="463" rx="18" fill="#FFFFFF"
stroke="#E6B58F" stroke-width="2.5" />
+ <rect x="442" y="503" width="700" height="57" rx="18" fill="#FFE3CF"
stroke="none" stroke-width="1" />
+ <rect x="442" y="542" width="700" height="18" rx="0" fill="#FFE3CF"
stroke="none" stroke-width="1" />
+ <text x="466" y="540" fill="#96431F" font-size="23" font-weight="750"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">ShenYu gateway cluster</text>
+ <rect x="765" y="515" width="157" height="33" rx="16.5" fill="#FFFFFF"
stroke="#E7B48F" stroke-width="1" />
+ <text x="843.5" y="536.94" fill="#A65027" font-size="16" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">N replicas</text>
+ <rect x="474" y="581" width="180" height="67" rx="12" fill="#F0FAF8"
stroke="#9CD5CD" stroke-width="2" />
+ <text x="492" y="610" fill="#15776F" font-size="18" font-weight="700"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">TCP / MQTT</text>
+ <text x="492" y="638" fill="#3B7772" font-size="15" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">dedicated listeners</text>
+ <rect x="718" y="581" width="398" height="67" rx="12" fill="#EFF6FF"
stroke="#9ABFE8" stroke-width="2" />
+ <text x="741" y="610" fill="#225B98" font-size="19" font-weight="700"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Local config cache</text>
+ <text x="741" y="638" fill="#3D648C" font-size="16" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Plugin · Selector · Rule · Metadata</text>
+ <path d="M 1054 366 V 578" stroke="#2874CE" stroke-width="3"
stroke-linecap="round" stroke-linejoin="round" fill="none"
marker-end="url(#sync)" />
+ <rect x="1110" y="425" width="180" height="31" rx="9" fill="#F5F7FB"
stroke="none" stroke-width="1" />
+ <text x="1200" y="446" fill="#2366AB" font-size="15" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">config change</text>
+ <rect x="474" y="694" width="180" height="126" rx="13" fill="#FFF7F0"
stroke="#DCA77F" stroke-width="2" />
+ <text x="493" y="733" fill="#8D441F" font-size="18" font-weight="700"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Spring WebFlux</text>
+ <text x="493" y="762" fill="#75482F" font-size="15" font-weight="600"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">ShenyuWebHandler</text>
+ <text x="493" y="790" fill="#A26C4E" font-size="16" font-weight="450"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">entry point</text>
+ <rect x="718" y="698" width="398" height="259" rx="14" fill="#FFFFFF"
stroke="#E3A77A" stroke-width="2" />
+ <text x="740" y="726" fill="#913F1C" font-size="20" font-weight="750"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Ordered ShenyuPlugin chain</text>
+ <text x="740" y="751" fill="#8D624D" font-size="15" font-weight="450"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Configured order · dynamic plugin updates</text>
+ <rect x="740" y="763" width="172" height="31" rx="15.5" fill="#FFF0E3"
stroke="none" stroke-width="1" />
+ <text x="826.0" y="783.43" fill="#A94F22" font-size="14.5" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Security / traffic</text>
+ <rect x="923" y="763" width="169" height="31" rx="15.5" fill="#E9F4F1"
stroke="none" stroke-width="1" />
+ <text x="1007.5" y="783.43" fill="#33756B" font-size="14.5"
font-weight="650" text-anchor="middle" font-family="Inter, -apple-system,
BlinkMacSystemFont, Segoe UI, Arial, sans-serif">Cache / resilience</text>
+ <rect x="740" y="800" width="172" height="31" rx="15.5" fill="#EAF2FF"
stroke="none" stroke-width="1" />
+ <text x="826.0" y="820.26" fill="#3465A3" font-size="14" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Transform / AI / MCP</text>
+ <rect x="923" y="800" width="169" height="31" rx="15.5" fill="#EFE8FF"
stroke="none" stroke-width="1" />
+ <text x="1007.5" y="820.43" fill="#6846A3" font-size="14.5"
font-weight="650" text-anchor="middle" font-family="Inter, -apple-system,
BlinkMacSystemFont, Segoe UI, Arial, sans-serif">Metrics / logging</text>
+ <rect x="740" y="838" width="352" height="65" rx="9" fill="#FFF5EC"
stroke="#F0C9AB" stroke-width="1.5" />
+ <text x="755" y="858" fill="#A84C20" font-size="16" font-weight="700"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Proxy / RPC plugins</text>
+ <text x="755" y="879" fill="#714A36" font-size="15" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Divide · Dubbo · SOFA · gRPC · Tars</text>
+ <text x="755" y="898" fill="#714A36" font-size="14.5" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">WebSocket · RPC context / transform</text>
+ <rect x="740" y="910" width="352" height="30" rx="8" fill="#F5F7FB"
stroke="none" stroke-width="1" />
+ <text x="916" y="930" fill="#3F536D" font-size="14.5" font-weight="550"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Selector / Rule: parameter + predicate
matching</text>
+ <path d="M 917 649 V 694" stroke="#2874CE" stroke-width="2.5"
stroke-linecap="round" stroke-linejoin="round" fill="none"
marker-end="url(#sync)" />
+ <line x1="202" y1="755" x2="252" y2="755" stroke="#E56A2F"
stroke-width="3.5" stroke-linecap="round" marker-end="url(#flow)" />
+ <line x1="408" y1="755" x2="468" y2="755" stroke="#E56A2F"
stroke-width="3.5" stroke-linecap="round" marker-end="url(#flow)" />
+ <line x1="654" y1="755" x2="712" y2="755" stroke="#E56A2F"
stroke-width="3.5" stroke-linecap="round" marker-end="url(#flow)" />
+ <line x1="1116" y1="755" x2="1194" y2="755" stroke="#E56A2F"
stroke-width="3.5" stroke-linecap="round" marker-end="url(#flow)" />
+ <text x="434" y="739" fill="#B1552B" font-size="15" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">HTTP</text>
+ <rect x="1200" y="545" width="402" height="348" rx="16" fill="#FFFFFF"
stroke="#DFB18F" stroke-width="2" />
+ <rect x="1200" y="545" width="402" height="56" rx="16" fill="#FFE8D8"
stroke="none" stroke-width="1" />
+ <rect x="1200" y="583" width="402" height="18" rx="0" fill="#FFE8D8"
stroke="none" stroke-width="1" />
+ <text x="1224" y="582" fill="#914624" font-size="22" font-weight="750"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Upstream services</text>
+ <text x="1224" y="629" fill="#6B432F" font-size="19" font-weight="650"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">HTTP / Spring Cloud</text>
+ <line x1="1224" y1="647" x2="1578" y2="647" stroke="#EDE2D8"
stroke-width="1.5" stroke-linecap="round" />
+ <text x="1224" y="681" fill="#A66342" font-size="16" font-weight="750"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">RPC</text>
+ <text x="1224" y="708" fill="#6B432F" font-size="18" font-weight="550"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Dubbo · SOFA · gRPC · Tars</text>
+ <line x1="1224" y1="729" x2="1578" y2="729" stroke="#EDE2D8"
stroke-width="1.5" stroke-linecap="round" />
+ <text x="1224" y="761" fill="#A66342" font-size="16" font-weight="750"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Streaming</text>
+ <text x="1224" y="788" fill="#6B432F" font-size="18" font-weight="550"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">WebSocket services</text>
+ <rect x="1224" y="817" width="354" height="48" rx="8" fill="#FFF8F2"
stroke="none" stroke-width="1" />
+ <text x="1401" y="846" fill="#8D624D" font-size="16" font-weight="500"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Backend apps own their APIs</text>
+ <rect x="1200" y="912" width="402" height="70" rx="13" fill="#F4EFFD"
stroke="#CBB8EB" stroke-width="2" />
+ <text x="1224" y="941" fill="#6746A0" font-size="19" font-weight="700"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Observability sinks</text>
+ <text x="1224" y="967" fill="#70578D" font-size="17" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Metrics · logs · trace IDs</text>
+ <path d="M 1116 884 H 1165 Q 1175 884 1175 894 V 947 H 1193"
stroke="#7B5BC7" stroke-width="2.5" stroke-linecap="round"
stroke-linejoin="round" fill="none" stroke-dasharray="6 5"
marker-end="url(#telemetry)" />
+ <rect x="78" y="873" width="330" height="104" rx="13" fill="#FFFFFF"
stroke="#D4C7BA" stroke-width="1.5" />
+ <rect x="96" y="889" width="118" height="30" rx="15.0" fill="#F1EBE5"
stroke="none" stroke-width="1" />
+ <text x="155.0" y="909.1" fill="#71594A" font-size="15" font-weight="650"
text-anchor="middle" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">DEPLOY</text>
+ <text x="96" y="945" fill="#654D3F" font-size="18" font-weight="650"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">shenyu-bootstrap image</text>
+ <text x="96" y="966" fill="#917767" font-size="14" font-weight="450"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Docker / Kubernetes replicas</text>
+ <line x1="62" y1="1040" x2="1618" y2="1040" stroke="#DCE4ED"
stroke-width="1.5" stroke-linecap="round" />
+ <text x="68" y="1077" fill="#51637A" font-size="17" font-weight="700"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">Flows</text>
+ <line x1="137" y1="1071" x2="185" y2="1071" stroke="#E56A2F"
stroke-width="3" stroke-linecap="round" marker-end="url(#flow)" />
+ <text x="199" y="1077" fill="#51637A" font-size="17" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">request</text>
+ <line x1="337" y1="1071" x2="385" y2="1071" stroke="#2874CE"
stroke-width="3" stroke-linecap="round" marker-end="url(#sync)" />
+ <text x="399" y="1077" fill="#51637A" font-size="17" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">config sync</text>
+ <line x1="565" y1="1071" x2="613" y2="1071" stroke="#128279"
stroke-width="3" stroke-linecap="round" stroke-dasharray="7 6"
marker-end="url(#register)" />
+ <text x="627" y="1077" fill="#51637A" font-size="17" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">registration</text>
+ <line x1="817" y1="1071" x2="865" y2="1071" stroke="#7B5BC7"
stroke-width="3" stroke-linecap="round" stroke-dasharray="6 5"
marker-end="url(#telemetry)" />
+ <text x="879" y="1077" fill="#51637A" font-size="17" font-weight="500"
text-anchor="start" font-family="Inter, -apple-system, BlinkMacSystemFont,
Segoe UI, Arial, sans-serif">telemetry</text>
+ <text x="1599" y="1077" fill="#51637A" font-size="17" font-weight="550"
text-anchor="end" font-family="Inter, -apple-system, BlinkMacSystemFont, Segoe
UI, Arial, sans-serif">Each replica reads its own local cache</text>
+</svg>
\ No newline at end of file