This article is more than one year old. Older articles may contain outdated content. Check that the information in the page has not become incorrect since its publication.
Dubbo
services through the Apache ShenYu
gateway, covering the main content from simple examples to core calling process analysis, and summarizing design principles.Apache ShenYu(Incubating) is an asynchronous, high-performance, cross-language, and responsive API
gateway. Compatible with various mainstream framework systems, it supports hot swapping, and users can customize development to meet various current and future needs through large-scale scenario testing.
In May 2021, ShenYu
was donated to the Apache
Software Foundation, which was fully approved by the Apache Foundation and successfully entered the incubator.
Apache Dubbo
is a microservices development framework that provides two key capabilities: RPC
communication and microservice governance. This means that microservices developed using Dubbo
will have remote discovery and communication capabilities among themselves, while utilizing the rich service governance capabilities provided by Dubbo to implement service governance requirements such as service discovery, load balancing, and traffic scheduling. Additionally, Dubbo
is highly extensible, allowing users to customize their implementations at almost any function point to change the default behavior of the framework to meet their business needs.
This section introduces how to integrate Dubbo
services into the ShenYu
gateway. You can find the example code for this section directly under the project.
shenyu-admin
is the backend management system for Apache ShenYu
. There are various ways to start it; this article will start it via [local deployment](https://shenyu.apache.org/docs/deployment/deployment-local)
. Once successfully started, you need to enable the dubbo
plugin in the basic configuration ->
plugin management, and set your registration address. Please ensure that the registration center is already running.
Here we start it through the source code, running ShenyuBootstrapApplication
in shenyu-bootstrap
directly.
Before starting, please ensure that the gateway has relevant dependencies introduced. If the client is apache dubbo
, and the registration center uses zookeeper
, please refer to the following configuration:
<!-- apache shenyu apache dubbo plugin start-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-plugin-apache-dubbo</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.5</version>
</dependency>
<!-- Dubbo zookeeper registry dependency start -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.0.1</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<!-- Dubbo zookeeper registry dependency end -->
<!-- apache dubbo plugin end-->
Taking the example provided by the official website shenyu-examples-dubbo as an example. Suppose the dubbo
service is defined as follows:
<beans /* ...... * />
<dubbo:application name="test-dubbo-service"/>
<dubbo:registry address="${dubbo.registry.address}"/>
<dubbo:protocol name="dubbo" port="20888"/>
<dubbo:service timeout="10000" interface="org.apache.shenyu.examples.dubbo.api.service.DubboTestService" ref="dubboTestService"/>
</beans>
Declare the application service name, registration center address, use the dubbo
protocol, and declare the service interface corresponding to the implementation class:
/**
* DubboTestServiceImpl.
*/
@Service("dubboTestService")
public class DubboTestServiceImpl implements DubboTestService {
@Override
@ShenyuDubboClient(path = "/findById", desc = "Query by Id")
public DubboTest findById(final String id) {
return new DubboTest(id, "hello world shenyu Apache, findById");
}
//......
}
In the interface implementation class, use the annotation @ShenyuDubboClient
to register the service in shenyu-admin
.
In the configuration file application.yml
:
server:
port: 8011
address: 0.0.0.0
servlet:
context-path: /
spring:
main:
allow-bean-definition-overriding: true
dubbo:
registry:
address: zookeeper://localhost:2181 # dubbo registration center
shenyu:
register:
registerType: http # Registration method
serverLists: http://localhost:9095 # Registration address
props:
username: admin
password: 123456
client:
dubbo:
props:
contextPath: /dubbo
appName: dubbo
In the configuration file, declare the registration center address used by dubbo
, register the dubbo
service with shenyu-admin
, using the method http
, and the registration address is http://localhost:9095
.
For information on registration methods, please refer to [Application Client Access](https://shenyu.apache.org/docs/design/register-center-design/)
.
Once the shenyu-examples-dubbo
project starts successfully, the interfaces with the @ShenyuDubboClient
annotation will automatically register with the gateway.
Open Plugin List -> Proxy -> dubbo
to view the plugin rule configuration list:
Successfully registered selector information:
Successfully registered rule information:
Selectors and rules are the essence of the
Apache ShenYu
gateway. Mastering them allows you to manage any traffic. The corresponding selector and rule matching conditions (conditions) can handle various complex scenarios based on different traffic filtering rules. Traffic filtering can retrieve data fromHeader
,URI
,Query
,Cookie
, etc. in the HTTP request.You can then use matching methods such as
Match
,=
,Regex
,Groovy
, andExclude
to match your expected data. Multiple matching conditions can be added withAnd/Or
strategies.For specific introductions and usage, please see:
[Selector and Rule Management](https://shenyu.apache.org/docs/user-guide/admin-usage/selector-and-rule)
.
Initiate a GET
request to call dubbo
service through ShenYu
gateway:
GET http://localhost:9195/dubbo/findById?id=100
Accept: application/json
After a successful response, the result is as follows:
{
"name": "hello world shenyu Apache, findById",
"id": "100"
}
Thus, the dubbo
service has been accessed successfully through the http
request, and the ShenYu
gateway has converted the http
protocol into the dubbo
protocol through the shenyu-plugin-dubbo
module.
During the running of the above demo
, you may have some questions:
dubbo
service registered to shenyu-admin
?shenyu-admin
synchronize data to the ShenYu
gateway?DubboPlugin
convert the http
protocol to the dubbo protocol?With these questions, let’s dive into understanding the dubbo
plugin.
Application client access refers to integrating microservices into the Apache ShenYu
gateway, currently supporting protocols like Http
, Dubbo
, Spring Cloud
, gRPC
, Motan
, Sofa
, and Tars
.
Integrating the application client into the Apache ShenYu
gateway is achieved through a registration center, involving client registration and server data synchronization. The registration center supports Http
, Zookeeper
, Etcd
, Consul
, and Nacos
, with the default being Http
for registration.
For related configuration on client access, please refer to [Client Access Configuration](https://shenyu.apache.org/docs/user-guide/register-center-access)
.
In your microservice configuration, declare the registration center client type, such as Http
or Zookeeper
.
When the application starts, it loads and initializes the corresponding registration center client using SPI
, implementing the Spring Bean-related post-processor interface, fetching service interface information to register, and placing the information into Disruptor
.
The registration center client reads data from Disruptor
and registers the interface information to shenyu-admin
, where Disruptor
decouples data from operations, facilitating extension.
In shenyu-admin
, declare the registration center server type, such as Http
or Zookeeper
. When shenyu-admin
starts, it reads the configuration type, loads and initializes the corresponding registration center server. Once the registration center server receives interface information registered by shenyu-client
, it places it in Disruptor
, triggering registration logic to update and publish synchronization events.
Disruptor
decouples data from operations for better extension. If there are too many registration requests causing registration exceptions, it provides data buffering.
Data synchronization refers to how data is synchronized from the shenyu-admin
backend to the Apache ShenYu
gateway after operating the data. The Apache ShenYu
gateway currently supports ZooKeeper
, WebSocket
, Http long polling
, Nacos
, Etcd
, and Consul
for data synchronization, with the default being through WebSocket
.
For related configuration on data synchronization, please refer to [Data Synchronization Configuration](https://shenyu.apache.org/docs/user-guide/use-data-sync)
.
The gateway is the entry point for traffic requests, playing a crucial role in the microservice architecture. The importance of the gateway’s high availability is self-evident. During the use of the gateway, to meet business demands, configurations often need to change, such as flow control rules and routing rules. Therefore, dynamic configuration of the gateway is a significant factor in ensuring its high availability.
Current data synchronization features include:
Apache ShenYu
gateway memory, utilizing local caches for each request, providing very fast speeds.shenyu-admin
backend at will, and immediately synchronize it to the gateway memory.Apache ShenYu
.Zookeeper
, Http long polling
, Websocket
, Nacos
, Etcd
, and Consul
.The diagram below illustrates the data synchronization process of Apache ShenYu
. When the Apache ShenYu
gateway starts, it synchronizes configuration data from the configuration service and supports push-pull modes to receive configuration change information, then updates the local cache. Administrators can modify user permissions, rules, plugins, traffic configurations in the management background (shenyu-admin
), and synchronize this information to the Apache ShenYu
gateway using either push
or pull
mode, depending on the synchronization method used.
In earlier versions, the configuration service depended on Zookeeper
for realization, pushing change notifications to the gateway from the management backend. Now it supports WebSocket
, Http long polling
, Zookeeper
, Nacos
, Etcd
, and Consul
, allowing configuration of shenyu.sync.${strategy}
to specify the corresponding synchronization strategy, with the default using the webosocket
synchronization strategy for sub-second data synchronization. However, it is crucial that the Apache ShenYu
gateway and shenyu-admin
use the same synchronization strategy.
As shown in the diagram below, after a configuration change occurs in the management backend (shenyu-admin
), it issues a change notification through EventPublisher
. The EventDispatcher
processes this change notification, and according to the specified synchronization strategy (http, websocket, zookeeper, naocs, etcd, consul
), sends the configuration to the corresponding event processor.
websocket
, the altered data is actively pushed to shenyu-web
, and there is a corresponding WebsocketDataHandler
in the gateway to handle the data push from shenyu-admin
.zookeeper
, it updates the changed data to zookeeper
, while ZookeeperSyncCache
listens to changes in zookeeper
data and processes it.http
, the gateway actively initiates long polling requests with a default timeout of 90s
. If there are no data changes from shenyu-admin
, the http
request is blocked; if data changes occur, it responds with the changed data information. If there are no data changes after 60s
, it responds with empty data. Upon receiving the response, the gateway initiates another http
request, repeating the same request process.Process analysis shows service registration, data synchronization, and service calling processes from the source code perspective.
Use the annotation @ShenyuDubboClient
to mark the dubbo
service that needs to be registered to the gateway.
Annotation scanning is accomplished through ApacheDubboServiceBeanListener
, which implements the ApplicationListener<ContextRefreshedEvent>
interface. During the Spring
container startup, when a context refresh event occurs, it executes the event handling method onApplicationEvent()
. In the overridden method logic, it reads the Dubbo
service ServiceBean
, builds metadata and URI
objects, and registers with shenyu-admin
.
For specific registration logic, please refer to [Client Access Principles](https://shenyu.apache.org/docs/design/register-center-design/)
.
The metadata and URI
data registered by the client through the registration center are processed on the shenyu-admin
end, responsible for storing in the database and synchronizing with the shenyu
gateway. The client registration handling logic of the Dubbo
plugin is in ShenyuClientRegisterDubboServiceImpl
. The inheritance relationship is as follows:
Dubbo
plugin registration;Registration information includes selectors, rules, and metadata.
The overall dubbo
service registration process is as follows:
Suppose a new selector data is added in the backend management system; the request enters the SelectorController
class’s createSelector()
method, responsible for data validation, adding, or updating data, and returning result information.
In the SelectorServiceImpl
class, the data is transformed and saved to the database, publishing the event and updating the upstream
.
In the Service
class, data persistence operations are completed, namely saving data to the database. The change data publication is done through eventPublisher.publishEvent()
. The eventPublisher
object is an instance of the ApplicationEventPublisher
class, with the fully qualified name org.springframework.context.ApplicationEventPublisher
, and the data publishing functionality is accomplished through Spring-related capabilities.
Once the event publication is complete, it automatically enters the DataChangedEventDispatcher
class’s onApplicationEvent()
method to handle events based on different data types and synchronization methods.
Upon startup, the gateway loads different configuration classes based on the specified data synchronization method, initializing relevant data synchronization classes.
After data is received, deserialization operations take place to read the data type and operation type. Different data types have different data handling methods and corresponding implementation classes. However, shared logic can be implemented through a template method design pattern, placing common logic in the handle()
method of the abstract class AbstractDataHandler
, while differing logic is left to their respective implementation classes.
Adding a new selector data is an addition operation that enters the specific data processing logic within SelectorDataHandler.doUpdate()
.
The general plugin data subscriber, CommonPluginDataSubscriber
, is responsible for handling all plugin, selector, and rule information.
The data is saved into the gateway’s memory; BaseDataCache
is the final cache data class, achieved through the singleton pattern. Selector data is stored in the SELECTOR_MAP
Map. In subsequent usage, data is also fetched from here.
The above logic is represented in the flowchart as follows:
In the Dubbo
plugin system, the class inheritance relationship is as follows:
ShenyuPlugin: Top-level interface defining interface methods;
AbstractShenyuPlugin: Abstract class implementing shared plugin logic;
AbstractDubboPlugin: Abstract class for the dubbo plugin implementing shared
dubbo
logic (ShenYu gateway supports ApacheDubbo and AlibabaDubbo);ApacheDubboPlugin: ApacheDubbo plugin.
Once proxied by the ShenYu
gateway, the request entry is ShenyuWebHandler
, which implements the org.springframework.web.server.WebHandler
interface, connecting all plugins through the chain of responsibility design pattern.
When the request reaches the gateway, determining whether a plugin executes is achieved through specified matching logic. In the execute()
method, selector and rule matching logic is executed.
The first to be executed is GlobalPlugin
, a global plugin that builds context information in its execute()
method.
Next is RpcParamTransformPlugin
, which reads parameters from the http
request, saves them to exchange
, and passes them to the rpc
service. In the execute()
method, this plugin’s core logic executes: retrieving request information from exchange
and processing parameters based on the request’s content format.
Then comes the execution of DubboPlugin
. In the doExecute()
method, it mainly checks metadata and parameters. In the doDubboInvoker()
method, it sets special context information and then begins generic dubbo
calls.
In the genericInvoker()
method:
ReferenceConfig
object;GenericService
object;pair
object;By generic calling, the gateway can invoke dubbo
services.
The ReferenceConfig
object is the key object supporting generic calls, and its initialization occurs during data synchronization.
Finally, the ResponsePlugin
is executed, handling the response result information from the gateway uniformly. The processing type is determined by MessageWriter
, with the class inheritance relationship shown below:
MessageWriter: Interface defining message processing methods;
NettyClientMessageWriter: Handling results from
Netty
calls;RPCMessageWriter: Handling results from
RPC
calls;WebClientMessageWriter: Handling results from
WebClient
calls;
Response processing for Dubbo
service calls is handled by RPCMessageWriter
.
In the writeWith()
method, the response result is processed, retrieving the result or handling exceptions.
With this analysis, the source code analysis regarding the Dubbo
plugin is complete, illustrated by the following flowchart:
This article starts from practical cases and gradually analyzes the proxying process of Dubbo
services by the ShenYu
gateway. The main knowledge points covered include:
AbstractShenyuPlugin
using the template method design pattern to handle generic operation types;BaseDataCache
using the singleton design pattern;springboot starter
to incorporate various registration centers and data synchronization methods;admin
for convenient traffic control;Disruptor
queue to decouple data from operations and buffer data.