引言

之前,我们项目中遇到要调用别的服务的接口时,通常选择使用Http去调用,如下

String result = HttpClient.get("xxxxxyour urlxxx");
User user = JSONObject.praseObject(result,User.class);
Return user;

这样做有很多弊端:

  1. url需要自己编写,容易出错
  2. 反序列化的过程需要自己编写,麻烦
  3. Http基于短链接方式,每次连接都要三次握手四次挥手,效率低。

那为什么不直接把要用到的服务所在的项目打包jar,引入jar的形式去使用呢?

        这样一来效率太低了,如果这样做,jar包中会包含很多不需要的类,以及jar包关联的其他jar,比如mybatis的,等等。所以,不推荐直接引入jar包的形式。

dubbo与http对比

1、传输协议对比

dubbo是基于TCP/IP协议的使用第三方网络框架Netty去创建TCP连接的,实际上就是通过TCP进行传输,属于数据链路层

http也是基于TCP/IP协议,建立Http连接进行传输,属于应用层

2、传输数据格式对比

http传输时,不仅要传输请求体,还有请求头、请求行等信息,有些信息对于服务调用来说是多余的,因此dubbo自定义了一套数据格式

3、连接方式对比

dubbo的服务消费者远大于服务提供者,默认使用socket长连接,即首次访问建立连接以后,后续网络请求使用相同的网络通道
- http1.1协议默认使用短连接,每次请求均需要进行三次握手,而http2.0协议开始将默认socket连接改为了长连接(keep-alive)

使用单一的连接避免了服务提供者被压垮,使用长连接可以减少服务连接的握手验证

4、序列化方式对比

dubbo采用Hessian二进制序列化,二进制格式的序列化,是效率最高的

http采用Json格式序列化

dubbo适用于少数据量高并发的场景,并且服务消费者要大于服务提供者

用dubbo调用服务步骤

        使用Dubbo去调用服务,主要分为三步

  1. 将提供者和消费者的springboot启动类标注为dubbo服务,具体做法是在启动类上添加@EnableDubbo注解
  2. 在服务提供者中编写接口和实现类,并在实现类上标注@DubboService注解
  3. 在消费者中引入服务提供者提供的接口,使用@DubboRefence注解

之后,就可以调用该接口了

@SpringBootApplication
@MapperScan("com.wupy.application.mapper")
@EnableTransactionManagement
@EnableDubbo
public class CurryFishServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(CurryFishServerApplication.class, args);
    }
}
@DubboService
public class InnerUserInterfaceInfoServiceImpl implements InnerUserInterfaceInfoService {
@DubboReference
    private InnerUserInterfaceInfoService innerUserInterfaceInfoService;
    @DubboReference
    private InnerUserService innerUserService;
    @DubboReference
    private InnerInterfaceInfoService innerInterfaceInfoService;

原理剖析

服务提供者如何提供服务?

在配置好注册中心(nacos/redis)后,编写接口及实现类,并将其注册为Dubbo服务,此时,会利用一些工具拿到服务提供主机的IP地址和服务的端口号,将这些信息注册到注册中心,在注册中心中会以Map的形式注册此服务<String(服务名),List<String(URL)>>,同时会注册本地注册表HashMap<String(服务名),class(实现类)>,如果一个接口对应多种实现类,那么可以在服务名中加上版本号进行区分。服务器接收服务消费者发送的请求,并通过反序列化拿到请求中的Invocation对象,,Invocation中包含接口名、方法名、参数值列表、参数类型列表、版本号。之后通过反射,基于实现类找到对象,利用反射执行对象的方法,得到结果result。并将结果返回给服务消费者。

服务消费者如何获取服务?

首先会基于代理模式,根据服务接口产生代理对象,在代理对象中将当前调用服务提供者方法的接口名、方法名、参数值列表、参数类型列表、版本号等信息封装成Invocation对象,从注册中心通过负载均衡策略从List<URL>中拿到URL,将Invocation作为参数发送请求(host,port,Invocation)

到服务提供者服务器。

扩展机制

dubbo中在发送请求的过程中有扩展机制,可以选择信息传输的协议,使用工厂模式,定义了Protocol接口,有不同的实现,根据不同的设置,去使用不同的网络协议,可以是NettyServer也可以使用HttpServer。

容错

可以在服务提供者和服务消费者端,分别进行异常检测,抛出相对应的异常,并记录下发生异常的调用信息,在一段时间后进行重试调用。