国产高性能java网关–神禹shenyu(原名soul)
其实从18年开始就已经在关注soul网关了,因为当时公司在做微服务转型,时间比较急,还是基于springcloud gateway搭建了网关。虽然没有使用,但还是在关注,果不其然,这个优秀的项目成功进入了Apache社区,并改名为神禹(shenyu),在这两年微妙的大环境下,再次为我们果然的努力而自豪。
神禹网关的文档很全,对于初学者很友好,今天将我这边的搭建经验分享给大家。
源码模块介绍
推荐大家优先阅读数据同步原理和客户端接入原理,可以帮助更好的使用。
-
shenyu-admin : 插件和其他信息配置的管理后台 -
shenyu-bootstrap : 用于启动项目,用户可以参考 初始化好的一个网关demo -
shenyu-client : 用户可以使用 Spring MVC,Dubbo,Spring Cloud 快速访问 -
shenyu-disruptor : 基于disruptor的封装 -
shenyu-register-center : shenyu-client提供各种rpc接入注册中心的支持 -
shenyu-common : 框架的通用类 -
shenyu-dist : 构建项目 -
shenyu-metrics : prometheus(普罗米修斯)实现的 metrics -
shenyu-plugin : ShenYu 支持的插件集合 -
shenyu-spi : 定义 ShenYu spi -
shenyu-spring-boot-starter : 支持 spring boot starter -
shenyu-sync-data-center : 提供 ZooKeeper,HTTP,WebSocket,Nacos 的方式同步数据 -
shenyu-examples : RPC 示例项目 -
shenyu-web : 包括插件、请求路由和转发等的核心处理包
数据同步
数据同步是指在 shenyu-admin
后台操作数据以后,使用何种策略将数据同步到 Apache ShenYu
网关。Apache ShenYu
网关当前支持ZooKeeper
、WebSocket
、Http长轮询
、Nacos
、Etcd
和 Consul
进行数据同步。
建议配置之前先学习数据同步原理 ,方便日后使用了解底层逻辑和阅读源码。

官方的文档比较全,参照逐步配置即可,这里列出我这边采用的方式——官方推荐的websocket方式
首先在 pom.xml
文件中引入以下依赖:
<!-- apache shenyu data sync start use websocket-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-sync-data-websocket</artifactId>
<version>${project.version}</version>
</dependency>
然后在 yml
文件中进行如下配置:
shenyu:
sync:
websocket :
urls: ws://localhost:9095/websocket # urls:是指 shenyu-admin的地址,如果有多个,请使用(,)分割。
shenyu-admin 配置
在 yml
文件中进行如下配置:
shenyu:
sync:
websocket:
enabled: true
当建立连接以后会全量获取一次数据,以后的数据都是增量的更新与新增,性能好。而且也支持断线重连 (默认30
秒)。推荐使用此方式进行数据同步,也是Apache ShenYu
默认的数据同步策略。
快速打造shenyu网关实例
maven依赖
<dependencies>
<!-- 官方有要求添加这部分,但是实际没效果-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-webflux</artifactId>-->
<!-- <version>2.2.2.RELEASE</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot</artifactId>-->
<!-- <version>2.2.2.RELEASE</version>-->
<!-- </dependency>-->
<!--shenyu gateway start-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-gateway</artifactId>
<version>${shenyu.version}</version>
</dependency>
<!--shenyu data sync start use websocket-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-sync-data-websocket</artifactId>
<version>${shenyu.version}</version>
</dependency>
<!--if you use http proxy start this-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-plugin-divide</artifactId>
<version>${shenyu.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-plugin-httpclient</artifactId>
<version>${shenyu.version}</version>
</dependency>
</dependencies>
<!-- 我主项目的springboot项目已经到2.5.3,但是shenyu需要的是2.2.2的版本,所以需要特别处理下-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
配置文件
spring:
main:
allow-bean-definition-overriding: true
management:
health:
defaults:
enabled: false
shenyu:
sync:
websocket :
urls: ws://localhost:9095/websocket #设置成你的 shenyu-admin 地址
server:
port: 9999
启动类
@SpringBootApplication
public class GatewayStarter {
public static void main(String[] args) {
SpringApplication.run(GatewayStarter.class, args);
}
}
客户端接入
对于网关来说 实际的服务提供方或者服务调用方都是客户端。
http方式
shenyu网关默认就是http方式接入,因此几乎不需要改什么配置即可运行
maven依赖
<dependencies>
<!--必备: spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- shenyu sometings 重点在这里 -->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-client-springmvc</artifactId>
<version>${shenyu.version}</version>
</dependency>
</dependencies>
测试类
@RestController
@RequestMapping("/hello")
@ShenyuSpringMvcClient(path = "/hello")
public class HelloController {
@GetMapping("/index")
@ShenyuSpringMvcClient(path="/index")
public String hello(){
return "hello world";
}
@GetMapping("/haha")
public String haha(){
return "O(∩_∩)O哈哈~ world";
}
}
启动类
@SpringBootApplication
public class CmsStarter {
public static void main(String[] args) throws JsonProcessingException {
SpringApplication.run(CmsStarter.class, args);
}
}
nacos注册方式配置
实际项目中用的比较多的是nacos
修改网关管理平台配置的注册方式为nacos
shenyu:
register:
registerType: nacos #http #zookeeper #etcd #nacos #consul
serverLists: localhost:8848 #localhost:2181 #http://localhost:2379 #localhost:8848
props:
sessionTimeout: 5000
connectionTimeout: 2000
checked: true
zombieCheckTimes: 5
scheduledTime: 10
nacosNameSpace: ShenyuRegisterCenter
shenyu客户端补充如下依赖:
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-register-client-nacos</artifactId>
<version>${shenyu.version}</version>
</dependency>
shenyu客户端修改配置文件:
shenyu:
client:
registerType: nacos
serverLists: localhost:8848
props:
contextPath: /http
appName: http
port: 8188
isFull: false
nacosNameSpace: ShenyuRegisterCenter
# registerType : 服务注册类型,填写 nacos
# serverList: 为nacos注册类型时,填写nacos地址,多个地址用英文逗号分隔
# port: 你本项目的启动端口,目前springmvc/tars/grpc需要进行填写
# contextPath: 为你的这个mvc项目在shenyu网关的路由前缀,比如/order ,/product 等等,网关会根据你的这个前缀来进行路由.
# appName:你的应用名称,不配置的话,会默认取 `spring.application.name` 的值
# isFull: 设置true 代表代理你的整个服务,false表示代理你其中某几个controller;目前适用于springmvc/springcloud
# nacosNameSpace: nacos的命名空间xxxxxxxxxx shenyu: client: registerType: nacos serverLists: localhost:8848 props: contextPath: /http appName: http port: 8188 isFull: false nacosNameSpace: ShenyuRegisterCenter# registerType : 服务注册类型,填写 nacos# serverList: 为nacos注册类型时,填写nacos地址,多个地址用英文逗号分隔# port: 你本项目的启动端口,目前springmvc/tars/grpc需要进行填写# contextPath: 为你的这个mvc项目在shenyu网关的路由前缀,比如/order ,/product 等等,网关会根据你的这个前缀来进行路由.# appName:你的应用名称,不配置的话,会默认取 `spring.application.name` 的值# isFull: 设置true 代表代理你的整个服务,false表示代理你其中某几个controller;目前适用于springmvc/springcloud# nacosNameSpace: nacos的命名空间shenyu: client: registerType: nacos #zookeeper #etcd #nacos #consul serverLists: localhost:8848 #localhost:2181 #http://localhost:2379 #localhost:8848 props: contextPath: /cms appName: cms port: 7001 nacosNameSpace: ShenyuRegisterCenter
SpringCloud接入
首先要在网关管理后台中开启springcloud插件

在网关中引入相关依赖:
<!-- apache shenyu springCloud plugin start-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-plugin-springcloud</artifactId>
<version>${shenyu.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-plugin-httpclient</artifactId>
<version>${shenyu.version}</version>
</dependency>
<!-- apache shenyu springCloud plugin end-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
补充nacos的配置:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 你的nacos地址
在SpringCloud项目中引入依赖:
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-client-springcloud</artifactId>
<version>${shenyu.version}</version>
</dependency>
具体实例代码
@RestController
@RequestMapping("/helloS")
@ShenyuSpringCloudClient(path = "/helloS")
public class HelloController {
@GetMapping("/index")
@ShenyuSpringCloudClient(path="/index")
public String hello(){
return "hello world";
}
@GetMapping("/haha")
public String haha(){
return "O(∩_∩)O哈哈~ world";
}
}
原先访问localhost:7001/helloS/index,现在可以通过localhost:9999/cms/helloS/index进行访问,实现网关的统一代理。
至此完成SpringCloud服务的接入,但是也有几点问题
由于依赖shenyu的jar包,因此必须要考虑到依赖版本问题,比如shenyu的SpringBoot版本低于业务项目版本时怎么办?
是否应该将业务项目的依赖版本尽可能的与网关的依赖版本独立开来。
SpringCloud与Http融合
全部调整为HTTP注册方式,然后需要手动设置选择器和规则,这样会比较麻烦,但是后端的服务之间没有依赖。
后端的服务间调用则采用任意方式都可以。
运行
启动shenyu网关后端管理项目
run ShenyuAdminBootstrap。
修改对应数据库的配置信息
server:
port: 9095
address: 0.0.0.0
spring:
# profiles:
# active: h2
thymeleaf:
cache: true
encoding: utf-8
enabled: true
prefix: classpath:/static/
suffix: .html
datasource:
url: jdbc:mysql://yunho-mysql:3306/shenyu?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
mybatis:
config-location: classpath:/mybatis/mybatis-config.xml
mapper-locations: classpath:/mappers/*.xml
shenyu:
register:
registerType: nacos #http #zookeeper #etcd #nacos #consul 这里采用nacos接入
serverLists: localhost:8848 #localhost:2181 #http://localhost:2379 #localhost:8848
props:
sessionTimeout: 5000
connectionTimeout: 2000
checked: true
zombieCheckTimes: 5
scheduledTime: 10
nacosNameSpace: ShenyuRegisterCenter
database:
dialect: mysql
init_script: "META-INF/schema.sql"
#custom_init_script: "/opt/schema.sql"
init_enable: true
sync:
websocket:
enabled: true #采用推荐的websocket方式实现数据同步
aes:
secret:
key: 2095132720951327
ldap:
enabled: false
url: ldap://xxxx:xxx
bind-dn: cn=xxx,dc=xxx,dc=xxx
password: xxxx
base-dn: ou=xxx,dc=xxx,dc=xxx
object-class: person
login-field: cn
jwt:
key: 2095132720951327
shiro:
white-list:
- /
- /favicon.*
- /static/**
- /index**
- /plugin
- /platform/**
- /websocket
- /configs/**
- /shenyu-client/**
- /error
- /actuator/health
- /swagger-ui.html
- /webjars/**
- /swagger-resources/**
- /v2/api-docs
- /csrf
swagger:
enable: true
logging:
level:
root: info
org.springframework.boot: info
org.apache.ibatis: info
org.apache.shenyu.bonuspoint: info
org.apache.shenyu.lottery: info
org.apache.shenyu: info
启动shenyu网关后端管理项目ShenyuAdminBootstrap,访问http://localhost:9095/,用户名密码:admin/123456
启动网关
启动GatewayStarter
3.3.1.RELEASE.jar;D:mylocalreporgprojectlomboklombok1.16.18lombok-1.16.18.jar" io.yunho.hudn.gateway.GatewayStarter
2021-09-08 16:02:48.733 INFO 55632 --- [ main] org.apache.shenyu.web.logo.ShenyuLogo :
_____ _
/ ____| |
| (___ | |__ ___ _ __ _ _ _ _
___ | '_ / _ '_ | | | | | | |
____) | | | | __/ | | | |_| | |_| |
|_____/|_| |_|___|_| |_|__, |__,_|
__/ |
|___/
:: Shenyu :: (v2.4.0-SNAPSHOT)
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _
( ( )___ | '_ | '_| | '_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |___, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.2.RELEASE)
2021-09-08 16:02:48.918 INFO 55632 --- [ main] io.yunho.hudn.gateway.GatewayStarter : Starting GatewayStarter on Jason-Think with PID 55632 (D:myideahundunhudn-gatewaytargetclasses started by Jason in D:myideahundun)
2021-09-08 16:02:48.919 INFO 55632 --- [ main] io.yunho.hudn.gateway.GatewayStarter : No active profile set, falling back to default profiles: default
2021-09-08 16:02:50.930 INFO 55632 --- [ main] o.a.s.w.c.ShenyuConfiguration : load plugin:[global] [org.apache.shenyu.plugin.global.GlobalPlugin]
2021-09-08 16:02:50.931 INFO 55632 --- [ main] o.a.s.w.c.ShenyuConfiguration : load plugin:[context_path] [org.apache.shenyu.plugin.context.path.ContextPathPlugin]
2021-09-08 16:02:50.931 INFO 55632 --- [ main] o.a.s.w.c.ShenyuConfiguration : load plugin:[divide] [org.apache.shenyu.plugin.divide.DividePlugin]
2021-09-08 16:02:50.931 INFO 55632 --- [ main] o.a.s.w.c.ShenyuConfiguration : load plugin:[webClient] [org.apache.shenyu.plugin.httpclient.WebClientPlugin]
2021-09-08 16:02:50.931 INFO 55632 --- [ main] o.a.s.w.c.ShenyuConfiguration : load plugin:[divide] [org.apache.shenyu.plugin.divide.websocket.WebSocketPlugin]
2021-09-08 16:02:50.931 INFO 55632 --- [ main] o.a.s.w.c.ShenyuConfiguration : load plugin:[paramTransform] [org.apache.shenyu.plugin.base.ParamTransformPlugin]
2021-09-08 16:02:50.931 INFO 55632 --- [ main] o.a.s.w.c.ShenyuConfiguration : load plugin:[response] [org.apache.shenyu.plugin.response.ResponsePlugin]
2021-09-08 16:02:50.996 INFO 55632 --- [ main] s.s.s.d.w.WebsocketSyncDataConfiguration : you use websocket sync shenyu data.......
2021-09-08 16:02:51.015 INFO 55632 --- [ main] o.a.s.p.s.d.w.WebsocketSyncDataService : websocket connection is successful.....
2021-09-08 16:02:51.998 INFO 55632 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 9999
2021-09-08 16:02:52.001 INFO 55632 --- [ main] io.yunho.hudn.gateway.GatewayStarter : Started GatewayStarter in 3.685 seconds (JVM running for 6.083)
到此已完成自定义网关的启动。
原文始发于微信公众号(云户):国产高性能java网关–神禹shenyu(原名soul)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/35273.html