服务调用—Dubbo

简介

官网:Apache Dubbo

什么是 duboo

是一款高性能、轻量级的开源 Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

dubbo 是阿里开发的,2018年初阿里把 dubbo 开源给了 apache。

推荐的代码设计方式

把 interface service 放在一个公共的项目中,让别的具体的项目去实现。

然后如果有项目想要使用具体实现,都先去引入公共项目的依赖,然后 dubbbo 会完成远程调用。

dubbo的工作原理

原视频:27_尚硅谷_原理_服务暴露流程_哔哩哔哩_bilibili

duboo 并不是一个实体工具,它是一个规则规范,它实际去依赖的是注册中心,比如 zookeeper。zookeeper 需要实际启动,而 dubbo 只需要在项目中引入依赖,并按照规则去使用即可。

框架设计

  • config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类

  • proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory

  • registry 注册中心层:封装服务地址的注册与发现,以服务 UR为中心,扩展接口为 RegistryFactory, Registry, RegistryService

  • cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance

  • monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService

  • protoco远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter

  • exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer

  • transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec

  • serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool

解析加载

服务暴露

使用 dubbo 的优缺点

个人对 dubbo 的理解

dubbo 就相当于 feignClient,但是 feignClient 是代理 Controller API接口,即 feignClient 需要用一个额外的项目,显式地写在项目里面,然后提供者和消费者都启动着,消费者通过 feignClient 去调用提供者。那么就是说,提供者、消费者的接口方法定义和实现都是在自己的模块里面的,然后消费者引入 feignClient 这个模块。

而 dubbo 是代理 Service 层的接口方法,直接相当于 @Resource 一样引入一个 Service层的依赖,就可以直接用它的方法。就是说,dubbo 并不需要用一个额外的项目,显式地写在项目里面,而是由一个公共的服务组件,比如 framework 来把接口方法定义,然后提供者和消费者去引入这个组件即可,只是调用接口方法的时候使用 dubbo 的注解告诉 dubbo 一下。

dubbo 的健壮性

  • 监控中心宕掉不影响使用,只是丢失部分采样数据

  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务

  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台

  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯

  • 服务提供者无状态,任意一台宕掉后,不影响使用

  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

  • dubbo 提供了直连方式,即在注解上直接写死调用地址

dubbo快速开始

  • 服务提供者(Provider):暴露服务的服务提供方,服务提供者在自己的容器启动时,向注册中心注册自己提供的服务。

  • 服务消费者(Consumer): 调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

  • 注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者

  • 监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

下载监控中心 Dubbo-OPS

下载完成后解压。然后如果 zookeeper 的地址不是本机,就去 resources 中的配置文件修改。

dubbo-admin - 管理控制台

想要 admin 的 jar包,只需要进 admin 目录下 cmd,mvn clean package,就可获得 jar。

然后就可以使用命令启动 admin,地址是 http:localhost:7001,root/root。

dubbo-moitor-simple - 监控中心

还是去目录下 cmd 运行 mvn clean package,就可获得 jar。

如果有 2.0.0 的话,去运行 bin/start.bat,启动监控服务。

监控中心的端口是 7070,然后访问地址是 localhost:8080

配置

https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/

dubbo 有非常多的配置,注解中也有许多属性。

实例

实践1

代码地址:nwonknU/learning - Gitee.com

前置

引入依赖
<!-- 普通 Maven项目 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>dubbo</artifactId>
  <version>2.6.2</version>
</dependency>
<!-- zookeeper 作为注册中心 -->
<dependency>
  <groupId>org.apache.curator</groupId>
  <artifactId>curator-framework</artifactId>
  <version>2.12.0</version>
</dependency>
​
<!-- SpringBoot使用的依赖 -->
<dependency>
  <groupId>com.alibaba.boot</groupId>
  <artifactId>dubbo-spring-boot-starter</artifactId>
  <version>0.2.0</version>
</dependency>
让别的服务引入的公共组件

这个一般是叫 framework,统一让别的服务引入的组件模块,一般在里面写想让 dubbo 做 RPC 的接口方法,以及一些共用的工具类和统一返回类型等等。

public interface UserService {
    List<UserAddress> getUserAddressList(String userId);
}
​
public interface OrderService {
    List<UserAddress> initOrder(String userId);
}

服务提供者

修改配置文件
server:
  port: 8081
dubbo:
  application:
    # 指定当前服务/应用的名字
    name: user-service-provider
  # 注册中心
  registry:
    # 使用的协议
    protocol: zookeeper
    address: 127.0.0.1:2181
  # 指定通信规则,协议、端口
  protocol:
    name: dubbo
    port: 20880
  # 要扫描的包路径,类上有 dubbo 的 @Service注解
  # import com.alibaba.dubbo.config.annotation.Service;
  scan:
    base-packages: com.atguigu.gmall
  # 监控中心
  monitor:
    protocol: registry
启动类
// 开启 dubbo 的功能
@EnableDubbo
// 开启服务容错
//@EnableHystrix
@SpringBootApplication
public class UserServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceProviderApplication.class, args);
    }
}
接口方法实现
import com.alibaba.dubbo.config.annotation.Service;
import com.atguigu.gmall.pojo.UserAddress;
import com.atguigu.gmall.service.UserService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Component;
​
// 这是 dubbo 的注解,暴露服务,不是 Spring 的
// 现在好像改了,改成了 @DubboService,然后别人引入的时候是 @DubboReference
@Service
// 这才是 Spring 的,将类注册为 bean
@Component
public class UserServiceImpimplements UserService {
//    @HystrixCommand
    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("UserServiceImpl..3.....");
        UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
        UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
        return Arrays.asList(address1, address2);
    }
}

服务消费者

修改配置文件
server:
  port: 8082
dubbo:
  application:
    # 指定当前服务/应用的名字
    name: order-service-consumer
  # 注册中心
  registry:
    address: zookeeper://127.0.0.1:2181
  # 指定通信规则,协议、端口
  protocol:
    name: dubbo
    port: 20880
  # 要扫描的包路径,类上有 dubbo 的 @Service注解
  # import com.alibaba.dubbo.config.annotation.Service;
  scan:
    base-packages: com.atguigu.gmall
  # 监控中心
  monitor:
    protocol: registry
启动类
@EnableDubbo
//@EnableHystrix
@SpringBootApplication
public class OrderServiceConsumerApplication {
   public static void main(String[] args) {
      SpringApplication.run(OrderServiceConsumerApplication.class, args);
   }
}
接口方法实现
@Service
public class OrderServiceImpimplements OrderService {
    // dubbo 来远程引用
    @Reference(loadbalance = "random", timeout = 1000, check = false)
    UserService userService;
//    @HystrixCommand(fallbackMethod = "hello")
    @Override
    public List<UserAddress> initOrder(String userId) {
        System.out.println("用户id:" + userId);
        //1、查询用户的收货地址
        List<UserAddress> addressList = userService.getUserAddressList(userId);
        return addressList;
    }
​
    public List<UserAddress> hello(String userId) {
        return Arrays.asList(new UserAddress(10, "测试地址", "1", "测试", "测试", "Y"));
    }
}

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值