ApacheDubbo

Apache Dubbo

Apache Dubbo 的学习

本篇博客主要记录本人学习Apache Dubbo的一些知识点。

Dubbo 简介
Apache Dubbo是一款高性能的Java RPC框架。
RPC全称为remote procedure call,即远程过程调用。
例子:两台服务器A和B,分别部署一个服务。这时如果服务器A想要调用服务器B的服务就需要通过网络表达调用的语义和传达调用的数据。
而RPC并不是一个具体的技术,是指整个网络远程调用过程。

Dubbo则提供三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

Dubbo的架构
架构图:
Dubbo架构图
各节点说明
Provider:暴露服务的服务提供方
Container:服务运行容器
Registry: 服务注册与发现的注册中心
Monitor: 统计服务的调用次数和调用时间的监控中心
Consumer: 调用远程服务的服务消费方

其中虚线是异步访问,实线是同步访问
红线是程序运行时执行的功能,而蓝线是dubbo启动时完成的功能

调用的顺序:
0. 服务运行容器(Container)启动,加载,运行服务提供方(Provider)
1.服务提供方(Provider)启动时,向注册中心(Registry)注册自己提供的服务
2.服务消费方(Consumer)启动时,向注册中心(Registry)订阅自己需要的服务
3.注册中心(Registry)返回服务提供方的地址列表给消费方,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4.服务消费者(Consumer),从提供者地址列表中,基于软负载均衡算法(默认为Random),选一台提供者进行调用。
5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

本次学习将使用zookeeper作为dubbo的服务中心(zookeeper安装在虚拟机上)

dubbo使用的示例:
服务方的编写:
pom.xml需要导入的dubbo部分:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.7</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

web.xml配置文件:这里配置ContextLoaderListener用于读取applicationContext*.xml的配置文件

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext*.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

创建服务接口

public interface HelloService {

    public String sayHello(String name);
}

创建服务实现类:这里需要注意要使用dubbo提供@service注解,才可以将服务发布到zookeeper上。

@Service
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
        return "8083:hello : " + name;
    }

}

applicationContext-service.xml的配置

<!--当前引用名称:用于注册中心计算应用间的关系,注意:生产者和消费者名称要不一样-->
    <dubbo:application name="dubbodemo_provider"></dubbo:application>

    <!--连接服务注册中心zookeeper的地址-->
    <dubbo:registry address="zookeeper://192.168.235.133:2181"></dubbo:registry>

    <!--服务注册的协议和端口:默认端口20880-->
    <dubbo:protocol name="dubbo" port="20883"></dubbo:protocol>

    <!--扫描指定的包:加入@service注解的类会被发布成服务-->
    <dubbo:annotation package="com.jc.service.impl"></dubbo:annotation>

服务发布的效果截图:
dubbo服务发布截图

消费方的编写:
前面的pom.xml的配置基本与服务方一致,除了pom.xml中需要更改不同于服务方的端口号。

ps:这里的服务接口是从服务方直接复制的,正常情况下,应当将服务接口整合到一个项目中,再使用maven的坐标引入服务接口。

编写Controller:这里使用dubbo提供的@Reference注解实现注入

@RestController
@RequestMapping("/demo")
public class HelloController {

    @Reference
    private HelloService helloService;

    @RequestMapping("/hello")
    public String sayHello(String name) {
        //远程调用
        String res = helloService.sayHello(name);
        System.out.println(res);
        return res;
    }
}

applicationContext-web.xml的配置:

<!--当前引用名称:用于注册中心计算应用间的关系,注意:生产者和消费者名称要不一样-->
    <dubbo:application name="dubbodemo_consumer"></dubbo:application>

    <!--连接服务注册中心zookeeper的地址-->
    <dubbo:registry address="zookeeper://192.168.235.133:2181"></dubbo:registry>

    <!--扫描指定的包:加入@service注解的类会被发布成服务-->
    <dubbo:annotation package="com.jc.controller"></dubbo:annotation>

随后就可以启动服务提供方和消费方,进行远程调用。
ps:注意zookeeper的虚拟机的防火墙需要关闭,不然会调用失败

远程调用效果截图:
远程调用效果截图

Dubbo xml配置的说明:

<dubbo:annotation package="com.jc.controller"></dubbo:annotation>

包扫描:消费方和服务方都需要配置,用于扫描指定包下的类。
如果不适用包扫描和注解的方式进行发布服务的话,可以使用以下配置:
服务方的配置:

<bean id="helloService" class="com.jc.service.impl.HelloServiceImpl" />
<dubbo:service interface="com.lxs.jc.HelloService" ref="helloService" />

消费方的配置:

<dubbo:reference id="helloService" interface="com.lxs.api.HelloService" />

但如果用这种配置方法,每有一个服务就要再配置一遍,是相当麻烦的。所以还是注解的方式更方便。

在前面使用dubbo时,遇到了一个问题:使用dubbo的@service注解,导致spring出现找不到相应的bean的报错。
当时,想到的解决方法就是使用spring的@service注解取代dubbo的@service注解,再添加上面的service和reference的xml配置。问题的确可以通过这个方式解决,但是十分不方便。
最后,我重新开个项目再次编写时,就没有再出现这个问题。前一个项目的报错估计是因为我编写完配置文件后,将服务类所在包移动了多次,导致找不到相应的服务类而出现找不到相应的bean的问题。

dubbo 协议:
此处可以指定不同的协议和端口号。
dubbo协议适合小数据量大并发的服务调用,以及当服务消费机器数大于服务提供机数的情况。
ps:可以在同一工程中配置多个协议,不同的服务使用不同的协议

<dubbo:protocol name="dubbo" port="20883"></dubbo:protocol>

负载均衡:dubbo提供多个负载均衡策略,默认为random

Dubbo无法发布被事务代理的service问题:
如果在服务提供方加上@Transaction事务注解后,服务就会发布失败。
原因:因为spring是基于JDK动态代理方式创建代理对象,而此代理对象的完整类名为com.sun.proxy.$Proxy42(最后两位数字不是固定的),我们在配置中进行包扫描不是com.sun.proxy,而是:com.jc.service.impl。所以就导致Dubbo在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。

    <dubbo:annotation package="com.jc.service.impl"></dubbo:annotation>

解决方法:使用cglib代理方法
applicationContext-service.xml配置使用cglib代理方式:

    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

这里还需要在xml文件前面添加以下内容,不然就会出现无法识别tx:annotation-driven的错误。

xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans

修改服务类:在Service注解中加入interfaceClass属性,值为HelloService.class,作用是指定服务的接口类型

@Service(interfaceClass = HelloService.class)
@Transactional
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return "8083:hello : " + name;
    }
}

这个时候,服务就可以发布到zookeeper上了。

在解决Dubbo无法发布被事务代理的service问题时遇到的问题:
在配置好后,通过消费方调用服务提供方的服务时出现服务调用超时的问题。
随后进行了一系列的问题排查:

  1. 确保了zookeeper的虚拟机已关闭防火墙,服务提供方已成功发布服务
  2. 在服务提供方的@service中添加timeout的参数,设为5000ms,仍然会出现服务调用超时的问题
  3. 最后,我查看主机的mysql服务是否开启,发现也是开启的。我试着重启mysql服务,发现是我自己在applicationContext-service.xml中把数据源的密码配置错误,从而导致连接数据库失败,并且使得调用服务超时。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值