Dubbo

1、Dubbo基础知识

1、什么是分布式系统?

​ 分布式系统是若干个独立计算机的集合,这些计算机对于用户来说就像单个相关系统。分布式系统是建立在网络之上的软件系统。

2、分布式的发展演练

img

3、RPC

​ 简单的理解就是,RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数或方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

RPC两个核心模块:通讯,序列化

2、Dubbo

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

基本概念:

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

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

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

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

​ 下面罗列一些Dubbo常用的,也就是说每个项目的Dubbo的Xml文件中基本都会出现的标签,并以表格的形式列举标签中常见的可用属性:

<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.test.UserServiceBo" ref="userService" version="1.0.0" timeout="3000"/>

<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="userService" interface="com.test.UserServiceBo" version="1.0.0" timeout="3000"/>

<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />

<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />

Dubbo配置的覆盖规则:

  • 方法配置级别优于接口级别
  • Consumer端配置优于Provider配置优于全局配置
  • 最后是Dubbo Hard Code的配置值

2.1、使用dubbo+zookeeper整合springboot创建提供者、消费者案列:

提供者:

首先导入相关的依赖jar包

<dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
        <!--<dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

这里有个版本配合,dubbo的版本在25之间使用zkClient的jar包,2.5之后使用curator依赖包。

然后在properties中配置

#要注册的服务名
dubbo.application.name=provider-server
#注册中心的地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#扫描包下要被注册的服务
dubbo.scan.base-packages=com.hao.service

编写实现类

@Service  //注意:这里使用的是dubbo下的service注解
@Component  //让其被扫描到,放到IOC容器中去
public class BuyTicketImpl implements BuyTicket {
    @Override
    public String buyTicket() {
      return "快点买票啊,不然就回不去了";
    }
}

这样就可以在监控中心可以看到该提供者了

消费者:

首先跟提供者一样导入一样的jar包,跟上面一样

其次就在配置文件中配置消费者信息

#消费者名字
dubbo.application.name=consumer-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

然后就是使用了,首先先创建一个跟提供者一样包路径的接口,再生成相应的实现类

@Controller
@Service  //注意:这里使用的是springmvc中的service注解
public class UserService {
    @Reference
    BuyTicket buyTicket;
    @RequestMapping("/dd")
    @ResponseBody
    public String buyTicket(){
        String s = buyTicket.buyTicket();
        return s;
    }
}

这样消费者就可以通过dubbo+zookeeper拿到不同服务器上的服务了。这个是基于springboot做的。

下面是基于spring项目搭建的

提供者:

  <dependencies>
        <!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.4</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
<?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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
		 http://code.alibabatech.com/schema/dubbo
		 http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <dubbo:application name="DubboDemo-Provider"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:protocol name="dubbo" port="20880"/>
    <bean id="UserServiceImpl" class="com.hao.service.UserServiceImpl"/>

    <dubbo:service interface="com.hao.service.UserService" ref="UserServiceImpl"/>

</beans>
//提供者启动类
public class test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-provider.xml"); //通过读取配置文件获取容器
        context.start(); 
        System.out.println("提供者服务已注册成功");
        try {
            System.in.read();  //让该程序一直执行下去,不会停止
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在启动的时候可能会报日志冲突的问题:需要自己在resource文件夹下添加log4j.properties文件

###set log levels###
log4j.rootLogger=info, stdout
###output to the console###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n

消费者:

消费者这里也要创建一个和提供者一样的接口。

public interface UserService {
    String say();
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="dubboDemo-consumer"/>

    <!-- 使用预发 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <dubbo:reference interface="com.hao.service.UserService" id="user"/>

</beans>
public class test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-consumer.xml"); //也是通过读取配置文件获取容器,再通过容器获取指定的接口实现类
        context.start();
        UserService user = context.getBean("user", UserService.class);
        System.out.println("执行前");
        String say = user.say();
        System.out.println(say);  //这里注意:消费者只能获取到提供者接口实现类中return的值,方法具体中具体的实现获取不了。
        System.out.println("执行后");
        try {
            System.in.read();  //让程序一直运行下去。
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

zookeeper宕机与dubbo直连

现象:zookeeper注册中心宕机,还可以消费dubbo暴露的服务。

原因:

  • 监控中心宕机后不影响使用,只是丢失部分采样数据。
  • 数据库宕机后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务。
  • 注册中心对等集群,任意一台宕机后,将自动切换到另一台。
  • 注册中心全部宕机后,服务提供者和服务消费者仍能通过本地缓存通讯。
  • 服务提供者无状态,任意一台宕机后,不影响使用。
  • 服务提供者全部宕机后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复。

集群下dubbo负载均衡配置

在集群负载均衡是,dubbo提供了多种均衡策略,默认为random随机调用。

负载均衡策略:Random(随机)、RoundRobin(循环)、LeastActive(最少调用)、ConsistentHash(一致性)

服务降级

当服务器压力剧增的情况下,根据实际业务员情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。

其中:

  • mock=force:return+null表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • mock=fail:return+null表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

集群容错模式

Failover Cluster:失败自动切换,当出现失败时,重试其它服务器。

Failfast Cluster:快速失败,只发起一次调用,失败立即报错。

Failback Cluster:失败自动恢复,后代记录失败请求,定时重发。

Forking Cluster:并行调用多个服务器,只要一个成功即返回。

Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错。

3、Dubbo原理

RPC原理

一次完整的RPC调用流程(同步调用,异步另说)如下:
1)服务消费方(client)调用以本地调用方式调用服务;
2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
3)client stub找到服务地址,并将消息发送到服务端;
4)server stub收到消息后进行解码;
5)server stub根据解码结果调用本地的服务;
6)本地服务执行并将结果返回给server stub;
7)server stub将返回结果打包成消息并发送至消费方;
8)client stub接收到消息,并进行解码;
9)服务消费方得到最终结果。
RPC框架的目标就是要2~8这些步骤都封装起来,这些细节对用户来说是透明的,不可见的。

Netty通信原理

​ Netty是一个异步事件驱动的网络应用程序框架, 用于快速开发可维护的高性能协议服务器和客户端。它极大地简化并简化了TCP和UDP套接字服务器等网络编程。

Selector 一般称 为选择器 ,也可以翻译为 多路复用器,Connect(连接就绪)、Accept(接受就绪)、Read(读就绪)、Write(写就绪)

Netty基本原理

Dubbo原理(框架设计)

  • config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
  • proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory
  • registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService
  • cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance
  • monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService
  • protocol 远程调用层:封装 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原理(服务引用)

dubbo原理(服务调用)

原文地址:https://www.cnblogs.com/xiaopanjava/p/14443485.html