目录
3.1.3 启动 Apache ShenYu Admin容器
3.1.4 拉取Apache ShenYu Bootstrap镜像
3.1.5 启动Apache ShenYu Bootstrap镜像
一、前言
随着云原生技术的兴起,以docker和k8s为代表的云原生技术正在被各类厂商接纳,而作为微服务的前置门户微服务网关,逐渐被赋予越来越重要的地位。但是在云原生技术体系下,传统的微服务网关势必很难发挥其作用,于是各类面向云原生友好和兼容的高性能网关就逐渐开始流行起来,在之前章节中我们分别介绍了apisix以及kong的详细使用,本篇将介绍另一种云原生网关 apache shenyu的使用。
二、Apache ShenYu 介绍
2.1 为什么叫ShenYu
ShenYu(神禹)是中国古代君主夏禹(后世亦称大禹)的尊称,他留下了三渡黄河造福人民并成功治理黄河洪水的感人故事。他和尧、舜一起被认为是中国古代三大帝王之一。
- 首先,ShenYu这个名字是为了弘扬我们中华文明的传统美德;
- 其次,对于网关来说最重要的是流量管理;
- 最后,社区将以公平、公正、公开、择优的方式做事,在向神禹致敬的同时,也符合 Apache Way;
中文文档地址:apache shenyu文档,或者:shenyu中文文档
2.2 ShenYu特点
- 代理:支持Apache Dubbo,Spring Cloud,gRPC,Motan,SOFA,TARS,WebSocket,MQTT;
- 安全性:签名,OAuth 2.0,JSON Web令牌,WAF插件;
- API治理:请求、响应、参数映射、Hystrix、RateLimiter插件;
- 可观测性:跟踪、指标、日志记录插件;
- 仪表板:动态流量控制,用户菜单权限的可视化后端;
- 扩展:插件热插拔,动态加载;
- 集群:NGINX、Docker、Kubernetes;
- 语言:提供.NET,Python,Go,Java客户端用于API注册;
2.3 ShenYu架构图
2.4 shenyu数据同步原理
通过上面的架构图,可以大致了解shenyu在工作时的一个原理,对于网关来说,了解其底层数据流向是很重要的,即我们的微服务中的各种API是如何被网关识别、接入、代理等,这个是前提,对shenyu来说也不例外,它是如何对微服务API进行代理的呢?这就需要搞清楚其数据同步原理。
下图展示了 Apache ShenYu 数据同步的流程,Apache ShenYu 网关在启动时,会从配置服务同步配置数据,并且支持推拉模式获取配置变更信息,然后更新本地缓存。管理员可以在管理后台(shenyu-admin),变更用户权限、规则、插件、流量配置,通过推拉模式将变更信息同步给 Apache ShenYu 网关,具体是 push 模式,还是 pull 模式取决于使用哪种同步方式。
在最初的版本中,配置服务依赖 Zookeeper 实现,管理后台将变更信息 push 给网关。而现在可以支持 WebSocket、Http长轮询、Zookeeper、Nacos、Etcd 和 Consul,通过在配置文件中设置 shenyu.sync.${strategy} 指定对应的同步策略,默认使用 WebSocket 同步策略,可以做到秒级数据同步。但是,有一点需要注意的是,Apache ShenYu网关 和 shenyu-admin 必须使用相同的同步策略。
如下图所示,shenyu-admin 在用户发生配置变更之后,会通过 EventPublisher 发出配置变更通知,由 EventDispatcher 处理该变更通知,然后根据配置的同步策略(Http、WebSocket、Zookeeper、Nacos、Etcd、Consul),将配置发送给对应的事件处理器。整体流程如下:
- 如果是 WebSocket 同步策略,则将变更后的数据主动推送给 shenyu-web,并且在网关层,会有对应的 WebsocketDataHandler 处理器来处理 shenyu-admin 的数据推送;
- 如果是 Zookeeper 同步策略,将变更数据更新到 Zookeeper,而 ZookeeperSyncCache 会监听到 Zookeeper 的数据变更,并予以处理;
- 如果是 Http 同步策略,由网关主动发起长轮询请求,默认有 90s 超时时间,如果 shenyu-admin 没有数据变更,则会阻塞 Http 请求,如果有数据发生变更则响应变更的数据信息,如果超过 60s 仍然没有数据变更则响应空数据,网关层接到响应后,继续发起 Http 请求,反复同样的请求;
2.4.1 Zookeeper数据同步原理
基于 Zookeeper 的同步原理很简单,主要是依赖 Zookeeper 的 watch 机制。Apache ShenYu网关会监听配置的节点,shenyu-admin 在启动的时候,会将数据全量写入 Zookeeper,后续数据发生变更时,会增量更新 Zookeeper 的节点,与此同时,Apache ShenYu网关会监听配置信息的节点,一旦有信息变更时,会更新本地缓存。
完整的同步过程如下图所示:
其他的同步方式可以参阅文档,有非常详细的说明:数据同步说明
三、Apache ShenYu 安装部署
Apache ShenYu提供了多种,包括单机部署,docker部署,k8s等多种部署方式,从此也可以发现,Apache ShenYu是一款面向云原生友好的网关,接下来演示如何基于docker快速部署Apache ShenYu;
3.1 部署流程
3.1.1 创建 Docker Network
docker network create shenyu
3.1.2 拉取Apache ShenYu Admin镜像
docker pull apache/shenyu-admin:2.5.1
3.1.3 启动 Apache ShenYu Admin容器
默认情况下使用H2作为数据库存储后台数据,也可以修改为mysql,这个可以参考上述的中文文档
docker run -d -p 9095:9095 --name shenyu-admin --net shenyu apache/shenyu-admin:2.5.1
3.1.4 拉取Apache ShenYu Bootstrap镜像
docker pull apache/shenyu-bootstrap:2.5.1
3.1.5 启动Apache ShenYu Bootstrap镜像
如果不需要修改配置,可以直接使用以下命令启动
docker run -d \
-p 9195:9195 \
--name shenyu-bootstrap \
--net shenyu \
--env SHENYU_SYNC_WEBSOCKET_URLS=ws://shenyu-admin:8085/websocket \
apache/shenyu-bootstrap:2.5.1
3.1.6 访问控制台
成功启动两个容器之后,就可以可以访问shenyu的管理控制台,界面效果如下:
默认登录账户,admin/123456,登录之后看到的效果如下
通过控制台,就可以开始愉快的使用shenyu提供的各种路由规则等功能了,当然为了发挥它的作用,还需要结合微服务一起使用,这个用起来就很像之前聊过的apisxi或kong网关。
四、Apache ShenYu 使用初体验
为了快速体验Apache ShenYu的各项功能使用,shenyu将完整的代码托管在github上面,开发者不管是研究源码,还是体验其各项配置,以及与自己的项目进行整合,都可以通过研究这套代码满足大多数的需求。
4.1 本地控制台部署
4.1.1 获取源码
源码地址:shenyu git源码,通过git clone命令将源码下载到本地
4.1.2 导入idea并编译
将下载的代码导入idea中进行编译,导入必须的依赖jar即可
4.1.3 各模块的作用
为了后续更深入的学习,有必要对各个源码模块做一些基本的了解
- 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 : 包括插件、请求路由和转发等的核心处理包;
4.1.4 开启控制台
从上面使用docker部署shenyu来看,主要是部署两个镜像,分别是:ShenYu Admin与ShenYu Bootstrap,这个正好对应着源码中的两个工程的模块服务,
这是两个springboot工程,直接运行各自的main方法,启动即可
启动完成后,浏览器直接访问地址:localhost:9095,即可看到下面的登录界面,登录账户:admin/123456;
界面的菜单和功能和使用上面docker部署的效果是一样的;
ShenYu结合微服务中常用的一些服务接口调用场景,提供了常用的一些集成模式,包括:http模式,dubbo模式,springcloud(springcloud-alibaba),grpc模式等,下面结合官方示例以几种常用模式分别做说明
4.2 http模式使用
打开上述源码中的shenyu-examples模块,里面提供了各种模式下的案例
在http模式下,重点关注的地方有下面几点
4.2.1 配置文件
核心配置文件如下,这个配置中,
- serverLists表示连接的shenyu管理中心的服务地址;
- contextPath表示访问接口时需要添加的前缀(隐藏真实路径);
server:
port: 8189
address: 0.0.0.0
shenyu:
client:
registerType: http #zookeeper #etcd #nacos #consul
serverLists: http://localhost:9095 #localhost:2181 #http://localhost:2379 #localhost:8848
props:
contextPath: /http
appName: http
port: 8189
nacosNameSpace: ShenyuRegisterCenter
4.2.2 测试接口
在http模式的代码中,提供了一个OrderController的接口类,截取其中的两个方法,最关键的是需要在类上表明一个注解:@ShenyuSpringMvcClient,这个注解后面跟了一个path,表示访问接口时候需要拼接的地址;
@RestController
@RequestMapping("/order")
@ShenyuSpringMvcClient(path = "/order")
public class OrderController {
/**
* Save order dto.
*
* @param orderDTO the order dto
* @return the order dto
*/
@PostMapping("/save")
@ShenyuSpringMvcClient(path = "/save", desc = "Save order")
public OrderDTO save(@RequestBody final OrderDTO orderDTO) {
orderDTO.setName("hello world save order");
return orderDTO;
}
/**
* Find by id order dto.
*
* @param id the id
* @return the order dto
*/
@GetMapping("/findById")
@ShenyuSpringMvcClient(path = "/findById", desc = "Find by id")
public OrderDTO findById(@RequestParam("id") final String id) {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setId(id);
orderDTO.setName("hello world findById");
return orderDTO;
}
}
4.2.3 测试接口效果
启动shenyu-http服务,访问接口:localhost:9195/http/order/findById?id=1,可以看到下面的效果,其实这个是不是跟gateway的效果很像;
4.3 dubbo模式使用
在微服务治理架构中,dubbo也是使用非常多的,在shenyu的源码中也提供了多dubbo模式的支持
以其中的一种方式来看,主要包括下面几部分
4.3.1 配置文件
核心配置包括,连接shenyu服务控制中心地址,以及dubbo的配置,dubbo的服务注册需要依赖zookeeper;
server:
port: 8011
address: 0.0.0.0
servlet:
context-path: /
spring:
main:
allow-bean-definition-overriding: true
shenyu:
client:
registerType: http #zookeeper #etcd #nacos #consul
serverLists: http://localhost:9095 #localhost:2181 #http://localhost:2379 #localhost:8848
props:
contextPath: /dubbo
appName: dubbo
nacosNameSpace: ShenyuRegisterCenter
port: 20888
dubbo:
application:
name: test-dubbo-service
registry:
address: zookeeper://127.0.0.1:2181
protocol:
name: dubbo
port: 20888
scan:
base-packages: org.apache.shenyu.examples.apache.dubbo.service.annotation.impl
4.3.2 服务实现
可以这么理解,dubbo服务注册到zk上之后,shenyu的admin会拉取zk上面的服务信息,然后存储到自己的数据库中,实际外部访问时,就可以通过类似http的方式进行访问了,服务实现类如下,其实最重要的就是ShenyuDubboClient这个注解,通过这个注解,相当于是将dubbo协议的服务转换成了http的服务接口;
@Service
public class DubboTestServiceImpl implements DubboTestService {
@Override
@ShenyuDubboClient(path = "/findById", desc = "Query by Id")
public DubboTest findById(final String id) {
DubboTest dubboTest = new DubboTest();
dubboTest.setId(id);
dubboTest.setName("hello world shenyu Apache, findById");
return dubboTest;
}
@Override
@ShenyuDubboClient(path = "/findAll", desc = "Get all data")
public DubboTest findAll() {
DubboTest dubboTest = new DubboTest();
dubboTest.setName("hello world shenyu Apache, findAll");
dubboTest.setId(String.valueOf(new Random().nextInt()));
return dubboTest;
}
@Override
@ShenyuDubboClient(path = "/insert", desc = "Insert a row of data")
public DubboTest insert(final DubboTest dubboTest) {
dubboTest.setName("hello world shenyu Apache Dubbo: " + dubboTest.getName());
return dubboTest;
}
@Override
@ShenyuDubboClient(path = "/findList", desc = "Find list")
public ListResp findList() {
ListResp listResp = new ListResp();
listResp.setTotal(1);
listResp.setUsers(Arrays.asList(new DubboTest("1", "test")));
return listResp;
}
}
4.3.3 控制台开启dubbo插件
进入到控制台,找到dubbo这个插件,然后编辑,开启使用并保存
4.3.4 启动服务
启动服务之前,先确保配置中连接的zk服务已经启动
启动完成后,检查控制台,可以看到拼装并转换好的接口地址就在shenyu的控制台中展示出来;
4.3.5 接口效果测试
访问接口,localhost:9195/dubbo/findById?id=1,看到如下效果说明正常集成了;
4.4 springcloud模式使用
springcloud也是日常开发中使用比较多的微服务框架,shenyu也提供了多这种模式的支持,以springcloud为例进行说明;
4.4.1 启动依赖服务
将admin与bootstrap服务启动起来,同时启动example模块下的eureka服务,启动完成后,在控制台界面上的插件列表那里开启springcloud;
4.4.2 springcloud模块配置
在springcloud工程模块中,核心配置文件如下,主要包括下面几部分:
- 连接shenyu admin控制服务;
- 连接eureka注册中心;
其实这个原理和上面的dubbo将服务注册到zk,然后通过shenyu admin同步服务信息原理是类似的;
server:
port: 8884
address: 0.0.0.0
spring:
application:
name: springCloud-test
# cloud:
# nacos:
# discovery:
# server-addr: 127.0.0.1:8848
springCloud-test:
ribbon.NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
shenyu:
client:
registerType: http #zookeeper #etcd #nacos #consul
serverLists: http://localhost:9095 #localhost:2181 #http://localhost:2379 #localhost:8848
props:
contextPath: /springcloud
port: 8884
nacosNameSpace: ShenyuRegisterCenter
logging:
level:
root: info
org.apache.shenyu: debug
启动springcloud模块服务后,在控制台就可以看到经过转换之后springcloud的一些服务地址信息
4.4.3 接口效果测试
以模块中提供的某个接口为例,访问地址:localhost:9195/springcloud/order/findById?id=1
五、配置规则持久化与更换服务注册中心
在上面的演示中,shenyu admin的配置规则数据是放在h2内存数据库中,这在生产环境中是不允许的,一旦服务重启,之前的配置规则就会丢失,所以shenyu的源码包中提供了mysql的方式;
5.1 配置规则使用mysql存储
找到shenyu-admin模块,将配置文件中如图所示的位置的那一行注释掉,同时将数据库连接信息改为自己的即可;
然后重启admin服务,就可以看到mysql的数据表初始化出来了
5.2 更换注册中心
从上面的几种使用模式的配置可以看到,默认情况下,对于客户端来说,使用的是webscoket与shenyu-admin进行通信,事实上,在如下配置参数中,是提供了多种服务注册方式的,比如zk,nacos,etcd等;
如果在你的项目中普遍使用的是zk或者nacos作为服务注册中心,为了最小代价的实现接入,就可以考虑使用zk或nacos,下面来看下具体的过程;
5.2.1 修改shenyu admin中的配置
修改application.yml文件,涉及到的位置如下
5.2.2 修改shenyu-bootstrap中的配置
修改application-local.yml配置文件,涉及到的位置如下
5.2.3 修改example - http模块的配置
以上述example模块中的http模块为例,只需要简单修改下配置即可
重启各模块服务验证效果
重启几个模块的服务,再次调用下接口:localhost:9195/http/order/findById?id=1,可以看到效果是一样的
通过连接zk客户端,不难发现,shenyu在管控台界面上的一些配置元数据信息就写到了zk节点上,这个在上面的关于数据同步介绍中有详细说明。
5.2.4 修改example - dubbo模块的配置
dubbo也是实际服务治理中使用比较多的,同上述的http模块配置文件修改类似,修改如下的配置,主要是修改连接的注册中心地址;
然后再在控制台上关闭这个插件,同时打开dubbo的插件
重启该模块的dubbo服务,重启完成后,就可以在控制台看到被shenyu同步后的dubbo服务信息列表了;
浏览器访问服务:localhost:9195/dubbo/findAll,可以看到如下效果
六、shenyu 插件配置与使用
细心的同学在使用admin的管控台发现,在左侧菜单的BaseConfig目录下有一个Plugin菜单,这就是shenyu提供的可视化插件配置中心;
6.1 插件简介
在之前学习apisix以及kong的时候,细心的同学发现在控制台上面也提供了一个可以集中管理和配置插件的地方,插件的作用简单来说就是为系统提供一个快速使用某种功能的入口,同时插件的机制让系统具备了更好的扩展性,比如像Java的SPI机制,spring框架中的各种bean的应用,都属于插件化思想的具体实现。
在apache shenyu的源码底层设计模式中,可以说正是插件化的设计,让这个网关具备了很高的灵活性和拓展性,而在shenyu的默认出厂设置中,内置了丰富的可以满足日常各类微服务场景的插件,比如限流插件,Request插件,Dubbo插件,Websocket插件,SPI插件等等...
以限流为例来说,当微服务接入shenyu网关之后,以往需要借助sentinel或hystrix等限流技术,此时就可以直接通过shenyu提供的限流插件进行限流即可,只需要通过简单的配置就可以满足,而且云原生网关作为流量的入口,在网关这一层做限流从架构设计来说也具备重要的意义。关于shenyu的各种插件的使用,可以参考文档:插件集合。
下面以限流插件为例进行一个详细的说明,其他的插件使用可以结合文档进行参考配置即可。
6.2 限流插件配置与使用流程
中文使用手册:限流配置手册
6.2.1 引入限流依赖
在shenyu-admin模块中引入限流依赖jar包
<!-- apache shenyu ratelimiter plugin start-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-plugin-ratelimiter</artifactId>
<version>${project.version}</version>
</dependency>
<!-- apache shenyu ratelimiter plugin end-->
6.2.2 在管控台界面添加限流配置
在插件列表那里找到rate_limiter这个插件,做如下的配置,这里使用了redis的单机模式,即使用redis作为限流的依赖,这里主要设置限流的数据,比如下面设置每秒只允许一个请求通过;
在插件那一栏,找到rate_limiter,进行规则配置;
配置规则如下,分别配置selector和rule,参考下图的配置;
6.2.3 增加测试接口
在examples源码模块的http模块中增加一个测试接口,名称为findAll,即上述配置的那个被限流的接口
@GetMapping("/findAll")
@ShenyuSpringMvcClient(path = "/findAll", desc = "findAll")
public OrderDTO findAll() {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setName("hello world findAll order");
return orderDTO;
}
6.2.4 限流效果验证
做好上述的准备工作之后,启动三个服务,shenyu-admin模块,shenyu-bootstrap模块,以及http模块,启动完成后,每秒一次调用接口:localhost:9195/http/order/findById?id=1
快速调用,将看到下面的效果,即被限流了;
七、写在文末
限于篇幅原因,本篇到这里就结束了,本文通过较长的篇幅详细介绍了云原生网关apache shenyu的使用,当然从文档来看,其包含的内容远远不止这些,通过其源码的学习,可以了解到shenyu在插件化的设计思想这一块还是很值得学习和借鉴的,随着云原生今后的不断规模化应用,详细云原生网关也将迈向更快的发展通道,因此有必要深入的了解和学习。本篇到此结束,感谢观看。