Dubbo Gateway - 网关设计

本文探讨了Dubbo与Spring Cloud的整合方案,分析了Dubbo服务自省的缺失及其实现的意义,并提供了多种整合策略,包括Dubbo+Spring Cloud+Zookeeper+Nacos的不同组合,展示了具体的配置和代码实例。

背景

先说结论:dubbo目前版本(2.7.1 & 3.X)无法使用开源网关组件。

为什么?

在这里插入图片描述

通过Dubbo服务与注册的设计可以看出Dubbo服务的基本特点:

  1. 注册/发现对象 - Dubbo服务接口
  2. 注册/发现载体 - Dubbo URL (元信息:接口、版本、分组等)

一个Dubbo URL示例 ↓↓↓

dubbo://192.168.50.233:20880/com.paranoia.api.HelloService?anyhost=true&application=dubbo-provider&bean.name=providers:dubbo:com.paranoia.api.HelloService&default.deprecated=false&default.dynamic=false&default.register=true&deprecated=false&dubbo=2.0.2&dynamic=false&generic=false&interface=com.paranoia.api.HelloService&methods=hello&pid=8744&register=true&release=2.7.1&side=provider&timestamp=1559126008855

也就可以看出Dubbo中没有微服务中服务自省的概念。

服务自省:简单讲就是微服务架构中,注册中心管理的对象是应用(服务),而非对外的服务接口。

Dubbo计划在2.7.3版本实现"服务自省"。

在这里插入图片描述

实现“服务自省”有什么好处?

  • 拓展Dubbo生态,接洽SC生态的部分开源组件(eureka/consul、zuul/gateway、zipkin…)
  • 降低Dubbo注册中心压力(一个服务/一个服务下N个service)

等不到,刚需?

Plan A:

Dubbo + SpringCloud + Zookeeper + Nacos

Plan B:

Dubbo + SpringCloud + Zookeeper

Plan C:

Dubbo(2.7.2) + SpringCloud + Nacos

Plan D:

Dubbo(2.7.3) + Spring-Cloud-Gateway + Nacos

拓展:为什么要把注册中心从 Zookeeper 迁移到 Nacos

从降低运维成本,提高服务稳定性的角度讲,我们不希望维护两套注册中心,所以我们最终好像大概也许可能要选择Plan B.

Dubbo2.7.2已经支持nacos的元数据配置,也就是说我们等六月初RELEASE正式发布,就可以使用一个Plan C : Dubbo+Sppring Cloud + Nacos 。 但无奈项目中使用的Dubbo 3.x版本并没有这个规划…,Plan D 也是这个问题

分层设计

graph TD;
    Spring-Cloud-Gateway-->facade-0;
    Spring-Cloud-Gateway-->facade-1;
    facade-0-->dubbo-provider-0;
    facade-0-->dubbo-provider-1;
    facade-1-->dubbo-provider-0;
    facade-1-->dubbo-provider-1;
项目定位Plan APlan B
Gateway网关层Spring Cloud GateWay + NacosSpring Cloud GateWay + zk
facade业务逻辑层Spring Cloud + Nacos + Dubbo + zkSpring Cloud + Dubbo + zk
'demo无'公共逻辑层
dubbo-provider服务层dubbo + zkdubbo + zk

可行性

Plan A : Dubbo+SpringCloud+Zookeeper+Nacos

dubbo-provider

pom

        <dependency>
            <groupId>com.paranoia</groupId>
            <artifactId>api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>

service

import org.apache.dubbo.config.annotation.Service;
@Service
public class HelloServiceImpl implements HelloService {
    public String hello(String name) {
        return "hi , how are you ? my friend " + name;
    }
}

启动类添加注解

@EnableDubbo(scanBasePackages = "com.paranoia.demo.service")

配置文件

server:
  port: 8081

spring:
  profiles:
    active: dev
  application:
    name: dubbo-provider
  cloud:
    zookeeper:
      client:
        sasl: false
      enabled: true
      connect-string: localhost:2181

dubbo:
  application.name: ${spring.application.name}
  registry.address: zookeeper://127.0.0.1:2181
  config-center.address: zookeeper://127.0.0.1:2181
  consumer.timeout: 3000

SCA-facade

pom:同时集成SpringCloud和Dubbo

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--dubbo-->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!---->
        <dependency>
            <groupId>com.paranoia</groupId>
            <artifactId>api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

rest接口:使用dubbo-provider中的服务

import org.apache.dubbo.config.annotation.Reference;
@RestController
public class HelloController {

    @Reference
    HelloService helloService;

    @GetMapping("/hi")
    public String sayHi(@RequestParam String name) {
        System.out.println("SCA-facade get request name = " + name);
        return helloService.hello(name);
    }
}

启动类注解

@EnableDubbo
@EnableDiscoveryClient

配置文件
配置nacos作为CLoud的注册中心,
配置zk作为Dubbo的注册中心

spring:
  application:
    name: SCA-FACADE
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    zookeeper:
      client:
        asl: false
      enabled: true
      connect-string: localhost:2181
server:
  port: 8084

management:
  endpoints:
    web:
      exposure:
        include: "*"

dubbo:
  application.name: ${spring.application.name}
  registry.address: zookeeper://127.0.0.1:2181
  config-center.address: zookeeper://127.0.0.1:2181
  consumer.timeout: 3000

SCA-gateway

我们采用Spring-Cloud-Gateway作为Cloud的网关

pom

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-gateway-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

启动类添加注解

@EnableDiscoveryClient

配置文件
这里我们添加一个routes规则:GET请求&&path="/hi"的请求转发到SCA-FACADE服务

server:
  port: 8083

management:
  endpoints:
    web:
      exposure:
        include: "*"

spring:
  application:
    name: SC-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      default-filters:
      routes:
        - id: zk_route
          uri: lb://SCA-FACADE
            # path中是server服务中提供的接口
            # Method : 指定访问的请求类型
          predicates:
              - Path=/hi
              - Method=GET

facade需要在底层服务启动之后再启动,否则nacos会寻址失败导致项目启动失败。

检验负载均衡

两个dubbo-provider服务,两个facde服务,一个gateway服务

IMAGEPORTSNAMES
dubbo-provider8080/tcp, 0.0.0.0:18081->8081/tcpdubbo-provider-0
dubbo-provider8080/tcp, 0.0.0.0:8081->8081/tcpdubbo-provider-1
facade8080/tcp, 0.0.0.0:8084->8084/tcpfacade-0
facade8080/tcp, 0.0.0.0:18084->8084/tcpfacade-1
sc-gateway8080/tcp, 0.0.0.0:8083->8083/tcpgateway-0

多次请求网关地址:

curl http://47.106.221.***:8083/hi?name=dubbo-gateway

查看各个image控制台,发现无论是spring-cloud的还是dubbo的负载均衡都没有问题。

Plan B : Dubbo+SpringCloud+Zookeeper+Nacos

SC-facase-zk

相比Plan A ,facade只需要修改配置中心依赖以及配置文件

pom : 去掉naocs-dicovery 替换成 zk-discovery

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>

配置文件:

spring:
  application:
    name: SCA-FACADE-ZK
  cloud:
    #替换nacos为zk
    zookeeper:
      client:
        asl: false
      enabled: true
      connect-string: 47.106.221.253:2181
      discovery:
        enabled: true
        register: true

server:
  port: 8084

management:
  endpoints:
    web:
      exposure:
        include: "*"

dubbo:
  application.name: ${spring.application.name}
  registry.address: zookeeper://47.106.221.253:2181
  config-center.address: zookeeper://47.106.221.253:2181
  consumer.timeout: 3000
SC-gateway-zk

pom : 同SC-facade-zk

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>

配置文件

server:
  port: 8081

spring:
  application:
    name: dubbo-provider
  cloud:
    #替换nacos为zk
    zookeeper:
      client:
        sasl: false
      enabled: true
      connect-string: 47.106.221.253:2181

dubbo:
  application.name: ${spring.application.name}
  registry.address: zookeeper://47.106.221.253:2181
  config-center.address: zookeeper://47.106.221.253:2181
  consumer.timeout: 3000

启动服务dubbo-provider , sc-facase-zk , sc-gateway-zk

查看zk中数据:

在这里插入图片描述

### 将 Dubbo 服务与 AWS API Gateway 集成的解决方案 AWS API Gateway 是一种完全托管的服务,用于创建、发布、维护、监控和保护 API。然而,AWS API Gateway 默认并不直接支持 Dubbo 协议,因为 Dubbo 是一种基于 RPC 的协议,而 AWS API Gateway 主要处理 HTTP/HTTPS 请求[^5]。因此,为了实现 Dubbo 服务与 AWS API Gateway 的集成,需要引入一个中间层来完成协议转换和负载转发。 以下是实现 Dubbo 服务与 AWS API Gateway 集成的一种可能方案: #### 1. 使用网关代理进行协议转换 可以部署一个支持 Dubbo 协议的网关代理(如 Apache APISIX 或自定义的 Nginx 插件),该代理负责将来自 AWS API Gateway 的 HTTP 请求转换为 Dubbo 协议请求,并将结果返回给客户端。具体步骤如下: - **网关配置**:在 AWS API Gateway 中配置后端 URL,指向上述网关代理的地址。 - **协议转换**:网关代理接收 HTTP 请求后,解析请求内容并将其转换为 Dubbo 调用所需的格式。 - **服务调用**:通过 Dubbo 客户端从注册中心(如 Nacos)获取目标服务地址并发起远程调用。 - **响应处理**:将 Dubbo 响应结果转换为 HTTP 响应并返回给 AWS API Gateway。 ```python # 示例代码:Dubbo 客户端调用逻辑 from dubbo.client import DubboClient def invoke_dubbo_service(service_name, method_name, params): # 创建 Dubbo 客户端 client = DubboClient(service_name, zookeeper="zookeeper://nacos:8545") # 调用 Dubbo 方法 result = client.call(method_name, *params) return result ``` #### 2. 利用 AWS Lambda 进行 Dubbo 调用 另一种方法是使用 AWS Lambda 函数作为中介,通过 Java 或 Python SDK 在 Lambda 中实现 Dubbo 客户端调用逻辑。AWS API Gateway 可以触发 Lambda 函数执行以下操作: - 接收 HTTP 请求并解析参数。 - 使用 Dubbo 客户端发起远程调用。 -Dubbo 响应结果封装为 HTTP 响应返回给客户端。 ```java // 示例代码:Lambda 函数中的 Dubbo 调用 import com.alibaba.dubbo.config.ReferenceConfig; import com.alibaba.dubbo.rpc.service.GenericService; public class DubboInvoker { public String invoke(String service, String method, Object[] args) { ReferenceConfig<GenericService> reference = new ReferenceConfig<>(); reference.setInterface(service); reference.setUrl("dubbo://dubbo-service:20880"); GenericService genericService = reference.get(); return genericService.$invoke(method, new String[]{}, args); } } ``` #### 3. 结合 Nacos 注册中心动态更新路由 Dubbo 服务通常依赖注册中心(如 Nacos)来管理服务地址。为了确保 AWS API GatewayDubbo 网关之间的路由动态更新,可以采用以下策略: - **自动发现服务**:网关代理定期从 Nacos 获取最新服务列表并更新内部路由表。 - **健康检查**:结合 K8s Service 或 Nginx 的上游健康检查机制,确保只有健康的 Dubbo 实例被调用[^4]。 #### 4. 处理单点故障 为了避免网关代理成为系统瓶颈或单点故障,建议采取以下措施: - **多实例部署**:在多个可用区部署网关代理实例,并通过 AWS Load Balancer 实现流量分发。 - **容灾设计**:结合 DNS 轮询或云服务商提供的负载均衡器实现跨区域容灾。 ### 注意事项 - AWS API Gateway 的默认超时时间为 29 秒,如果 Dubbo 服务响应时间较长,可能需要调整此限制。 - Dubbo 的序列化方式(如 Hessian)可能与 HTTP 的 JSON 格式不兼容,需在网关代理中实现相应的 Payload 建模和转换逻辑[^5]。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高级摸鱼工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值