Dubbo使用APISIX作为网关
为什么使用网关
Dubbo服务本身没有暴露HTTP接口,客户端(如:Web,APP)无法直接调用其提供的方法。
而APISIX可以通过dubbo-proxy插件为Dubbo服务提供外部访问的HTTP接口,因此特别适合与Dubbo框架一起使用。
在Dubbo服务架构中如何使用APISIX
关于在Dubbo服务架构中使用APISIX作为接入网关,Dubbo官方的文档已经给出了说明。
在此,结合具体的示例进行实践。
假设已经存在了基于Dubbo架构的服务提供者和消费者,如下所示:
// Dubbo服务提供者接口
public interface HelloService {
String sayHello(String name);
}
// Dubbo服务提供者接口实现类
@DubboService
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "Hello, " + name;
}
}
// Dubbo服务消费者接口
public interface HelloServiceConsumer {
Object hello(String name);
}
// Dubbo服务消费者接口实现类
@Service
public class HelloServiceConsumerImpl implements HelloServiceConsumer {
// 引用Dubbo服务提供者
@DubboReference
private HelloService helloService;
@Override
public Object hello(String name) {
return this.helloService.sayHello(name);
}
}
此时如果希望Dubbo服务消费者(也可以是任何Dubbo服务)希望被来自APISIX的HTTP请求调用,那么如何实现呢?
按照dubbo-proxy插件文档示例描述,APISIX路由中指定的插件参数包含3个部分:
"service_name": "org.apache.dubbo.sample.tengine.DemoService", # 要调用的Dubbo服务接口完整限定名
"service_version": "0.0.0", # Dubbo服务版本名称,默认为0.0.0
"method": "tengineDubbo" # Dubbo服务方法名
也就是说,必须存在一个Dubbo服务接口org.apache.dubbo.sample.tengine.DemoService,该接口有一个名为tengineDubbo的方法。
// java package: org.apache.dubbo.sample.tengine
public interface DemoService {
// 通过APISIX传递的参数保存在Map对象中
// 返回给APISIX的结果也必须是一个Map对象,且在该Map对象中的数据结构为:
// {
// "status": "200", // 状态码,200表示成功,500表示错误
// "header1": "value1", // 消息头
// "header2": "valu2",
// "body": "blahblah" // 消息体
// }
Map<String, Object> tengineDubbo(Map<String, Object> context);
}
如果此时向APISIX的路由接口发起一个请求:
curl http://127.0.0.1:9080/demo -H "Host: example.org" -X POST --data '
{
"service": "org.chench.extra.dubbo.consumer.service.HelloServiceConsumer",
"method": "hello",
"parameters": [
{
"type": "java.lang.String",
"value": "chench"
}
]
}'
那么,消息体中的内容就是传递给Dubbo服务方法的Map对象数据。
所以,为了调用任意的Dubbo服务,应该编写一个专门对接APISIX请求的胶水层Dubbo服务,在该服务方法中通过反射的方式实现对任意其他Dubbo服务的调用。
如下接口或实现类都定义在Java包org.chench.extra.dubbo.apisix中。
// 对Dubbo服务调用做一个抽象,包含三个属性:要调用的Dubbo服务完整接口限定名,Dubbo服务方法名,Dubbo服务方法参数列表
public class DubboInvocation {
/** 服务的完整限定名,如:org.chench.extra.dubbo.HelloService */
private String service;
/** 服务的方法名 */
private String method;
/** 服务的方法参数列表 */
private DubboInvocationParameter[] parameters;
}
// 定义Dubbo服务方法参数,包含类型和值
public class DubboInvocationParameter {
private String type;
private String value;
}
// 对接APISIX请求的胶水层Dubbo服务接口
public interface APISIX2DubboService {
Map<String, Object> invoke(Map<String, Object> context) throws Exception;
}
// 对接APISIX请求的胶水层Dubbo服务接口实现
public class APISIX2DubboServiceImpl implements APISIX2DubboService {
private static final Logger LOGGER = LoggerFactory.getLogger(APISIX2DubboServiceImpl.class);
@Autowired
private ApplicationContext appContext;
@Override
public Map<String, Object> invoke(Map<String, Object> context) throws Exception {
// 返回给APISIX的数据为一个Map对象
Map<String, Object> httpResp = new HashMap<>();
String body = null;
try {
body = new String((byte[]) context.get("body"));
// 利用反射机制调用Dubbo服务的方法
DubboInvocation invocation = JSONObject.parseObject(body, DubboInvocation.class);
int paramSize = invocation.getParameters().length;
Object[] args = new Object[paramSize];
Class[] types = new Class[paramSize];
for (int i = 0; i < args.length; i++) {
DubboInvocationParameter parameter = invocation.getParameters()[i];
args[i] = parameter.getValue();
types[i] = Class.forName(parameter.getType());
}
Object svc = appContext.getBean(Class.forName(invocation.getService()));
Object result = svc.getClass().getMethod(invocation.getMethod(), types).invoke(svc, args);
httpResp.put("status", 200);
httpResp.put("body", JSONObject.toJSONString(result));
} catch (Exception e) {
LOGGER.error("invoke dubbo error, body: {}, error: {}", body, e.getMessage(), e);
httpResp.put("status", 500);
httpResp.put("body", e.getStackTrace());
e.printStackTrace();
}
return httpResp;
}
}
然后将这个对接APISIX的Dubbo服务进行注册:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- service implementation, as same as regular local bean -->
<bean id="APISIX2DubboService" class="org.chench.extra.dubbo.apisix.APISIX2DubboServiceImpl"/>
<!-- declare the service interface to be exported -->
<dubbo:service interface="org.chench.extra.dubbo.apisix.APISIX2DubboService" ref="APISIX2DubboService"/>
</beans>
至此,在Dubbo服务侧需要准备的工作就完毕了。
在APISIX这一侧,需要做2件事情:
第一,启用dubbo-proxy插件。
如果是以Docker方式启动的APISIX,在配置文件${APISIX_HOME}/example/apisix_conf/config.yaml中添加插件配置。
# 在APISIX 3.4.1中需要手动添加如下配置参数启用dubbo-proxy插件
plugins:
- dubbo-proxy
第二,创建一个路由指定需要调用的Dubbo服务。
curl http://127.0.0.1:9180/apisix/admin/routes/2 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uris": [
"/demo"
],
"plugins": {
"dubbo-proxy": {
"service_name": "org.chench.extra.dubbo.apisix.APISIX2DubboService", # 这是对接APISIX的Dubbo服务接口
"service_version": "0.0.0",
"method": "invoke"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"192.168.2.8:20881": 1
}
}
}'
最后,调用APISIX接口进行验证:
curl http://127.0.0.1:9080/demo -X POST --data '
{
"service": "org.chench.extra.dubbo.consumer.service.HelloServiceConsumer", # 指定需要调用的Dubbo服务接口完整限定名
"method": "hello", # 指定需要调用的Dubbo服务接口方法
"parameters": [ # 指定需要调用的Dubbo服务接口方法参数列表,每一个参数都要指定类型和值
{
"type": "java.lang.String",
"value": "chench"
}
]
}' -D-
# 调用成功返回
HTTP/1.1 200 OK
Date: Mon, 07 Aug 2023 15:17:24 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 15
Connection: keep-alive
Server: APISIX/3.4.1
"Hello, chench"
# 调用失败返回
HTTP/1.1 502 Bad Gateway
Date: Mon, 07 Aug 2023 15:18:09 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 229
Connection: keep-alive
Server: APISIX/3.4.1
X-APISIX-Upstream-Status: 502
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>openresty</center>
<p><em>Powered by <a href="https://apisix.apache.org/">APISIX</a>.</em></p></body>
</html>
至此,一个以APISIX作为网关调用Dubbo服务的方法就实现了。
但是如果在每一个Dubbo架构的应用中都需要定义一个对接APISIX的胶水层Dubbo服务,显得重复而且不利用维护,所以可以将这个胶水层Dubbo服务单独做成一个Spring Boot Starter组件,然后在每一个需要使用的地方直接引入即可,具体实现参考:dubbo-apisix-springboot-starter。
【参考】
APISIX+Dubbo+Nacos 最佳实践
Dubbo注解方式与spring的整合原理即@DubboService的机制(2)
【Dubbo】三种Dubbo配置与实现原理(XML、注解、API)
Dubbo使用APISIX作为网关的更多相关文章
- Dubbo想要个网关怎么办?试试整合Spring Cloud Gateway
一.背景 在微服务架构中 API网关 非常重要,网关作为全局流量入口并不单单是一个反向路由,更多的是把各个边缘服务(Web层)的各种共性需求抽取出来放在一个公共的"服务"(网关)中 ...
- apisix网关-构建docker镜像构建及插件化开发
高能劝退:lua开发,适合小白看!!! 前段时间有个项目,用的java程序做网关,压测tps只有1k多点,惨不忍睹. 后来公司有个大佬改用apisix做网关,tps飙升到1w多. 于是对神奇的apis ...
- Dubbo 在 K8s 下的思考
作者 | 曹胜利 Apache Dubbo PMC 导读:Dubbo 作为高性能 Java RPC 框架的刻板印象早已深入人心,在 Cloud Native 的架构选型上,Spring Cloud ...
- apisix docker镜像构建及插件化开发
高能劝退:lua开发,适合小白看!!! 前段时间有个项目,用的java程序做网关,压测tps只有1k多点,惨不忍睹. 后来公司有个大佬改用apisix做网关,tps飙升到1w多. 于是对神奇的apis ...
- Dubbo 迈出云原生重要一步 - 应用级服务发现解析
作者 | 刘军(陆龟) Apache Dubbo PMC 概述 社区版本 Dubbo 从 2.7.5 版本开始,新引入了一种基于实例(应用)粒度的服务发现机制,这是我们为 Dubbo 适配云原生基础 ...
- Soul API 网关源码解析 03
目标 使用 soul 代理 dubbo 服务 dubbo 服务如何注册到网关的? dubbo 插件是如何工作的? 理清 http --> 网关--> dubbo provider 整条链路 ...
- 景顺长城基于 Apache APISIX 在金融云原生的生产实践
本文介绍了景顺长城在金融云原生架构演进中选择 APISIX 作为网关工具的技术细节,同时分享了使用 APISIX 的实践细节,并对 APISIX 的未来展望进行了探讨. 作者李奕浩,景顺长城信息技术部 ...
- 厉害了,Spring Cloud Alibaba 发布 GA 版本!
? 小马哥 & Josh Long ? 喜欢写一首诗一般的代码,更喜欢和你共同 code review,英雄的相惜,犹如时间沉淀下来的对话,历久方弥新. 相见如故,@杭州. 4 月 18 日, ...
- 想用Nginx代理一切?行!
Nginx能代理一切吗? 是的,Nginx可以作为一个优秀的http网关,但nginx能代理SSH2,MySQL,Oracle的连接吗?也算行吧,nginx有stream-module,专门处理TCP ...
- 王院生:Apache APISIX 微服务网关极致性能架构解析
2019 年 10 月 27 日,又拍云联合 Apache APISIX 社区举办 API 网关与高性能服务最佳实践丨Open Talk 杭州站活动,Apache APISIX PPMC 成员王院生做 ...
随机推荐
- 银河麒麟安装nmon以及rpc.rstatd的方法
背景说明 随着公司业务的发展,需要在ARM环境上面进行性能测试. 为了进行ARM环境的验证,需要一些组件进行资料收集. 比较好的方式是使用nmon或者是rstatd进行性能参数收集. 为了方便部署,想 ...
- SAP PO7.5 有关https 接口body编码格式 application/x-www-form-urlencoded
近期项目中,在PO中做接口 遇到OAUTH2.0认证方式,token获取过程中编码格式为 "application/x-www-form-urlencoded" 实现过程错误记录: ...
- SPI在Java中的实现与应用 | 京东物流技术团队
1 SPI的概念 API API在我们日常开发工作中是比较直观可以看到的,比如在 Spring 项目中,我们通常习惯在写 service 层代码前,添加一个接口层,对于 service 的调用一般也都 ...
- 从零开始配置vim(24)——自动补全
neovim 自带的代码补全的效果并不好,而且它分为好多类,如果需要人为的去判断使用路径补全.使用当前buffer中的单词补全.亦或者使用include 来进行补全,那样使用起来就很不方便了.针对代码 ...
- 安装和定位vimrc
在上一篇文章中,我们简单开了一个头,阐述了下学习vim的必要性,这章开始,会慢慢由浅入深的学习它的一套完整的,高效的文本编辑方式方法.废话不多说,咱们正式开始吧 安装NeoVim 相对于vim来说,n ...
- 解决Edge浏览器提示“此网站已被人举报不安全”
今天下午微软旗下的 Microsoft Edge 浏览器将百度搜索的跳转域名 (*.baidu.com/link?url=*) 封杀,百度搜索首页可以打开,但搜索任何关键词点击搜索结果都会被拦截. 当 ...
- C# 笔记之基本语法
C#是一种现代的.通用的编程语言,由微软公司开发和推广.它于2000年发布,是一种结构化.面向对象和组件化的语言,旨在为Windows操作系统和Microsoft .NET框架提供强大的支持.可用于开 ...
- Pdfium.Net.Free 一个免费的Pdfium的 .net包装器--添加文本
项目地址: Pdfium.Net:https://github.com/1000374/Pdfium.Net PdfiumViewer:https://github.com/1000374/Pdfiu ...
- 从嘉手札<2023-10-30 >
杂诗 壬戌辛酉日夜,闲看日月,秋风萧瑟,感怀予身期年孑然,岁月难留,故有所感,藉以此诗. 闲来无事,细数春秋. 初月难盈,残烛易收. 未若知人意,夜夜息绝游. 红叶醉天水,星河绕满楼. 竹影戚戚乱,岁 ...
- 仅1cm厚!华硕发布全球最薄13.3英寸笔记本
近日,华硕发布了新款Zenbook S 13 OLED,官方称其为世界最纤薄的13.3英寸OLED笔记本电脑. 据悉,这款电脑的厚度仅有1cm,重量也仅有1kg,相较其他同尺寸的笔记本,确实更加轻薄. ...