zoukankan      html  css  js  c++  java
  • Dubbo学习

    目录

    前言
    为什么要学Dubbo
    什么是RPC
    Dubbo的产生背景
    单一应用架构
    垂直应用架构
    分布式服务架构
    流动计算架构
    Dubbo面临的需求
    Dubbo的架构
    Demo time
    新建一个maven项目
    提供服务的API
    提供服务的provider
    消费服务的consumer
    参考

    前言

    互联网技术到今天已经非常成熟和稳定了,其中为了解决高并发、大规模的服务请求,出现了微服务、RPC这样的分布式架构。今天就从头开始学习RPC框架dubbo。

    为什么要学Dubbo

    关于分布式的解决方案有很多,光RPC框架就有很多种,甚至有人比较了RPC框架性能, 结果显示dubbo垫底,以及spring cloud这种推崇Rest Http请求代替RPC, 那为什么还要学习RPC?

    首先,RPC框架的发展并没有因为Spring Cloud的出现而变的衰弱。其次,历史悠久的市场上大部分公司都会使用RPC来解决分布式问题。

    那么,为啥要选Dubbo? 只能说Dubbo在国内的流行程度远超过gRPC、thrift等,而且中文资料很多,在国内的技术圈混则必须要掌握这个技能。当然,缺点也不少,比如由于官方很长时间没有维护导致Dubbo各种落后。令人惊喜的是,Alibaba已经开始专注开源项目了,dubbo重新开启维护,进入Apache Incubating。然而,很多人也因此选择了其他RPC来代替dubbo。

    Dubbo发音问题: da bou; |ˈdʌbəʊ|

    什么是RPC

    RPC(Remote Procedure Call)表示远程过程调用。

    两台机器A和B。A部署了首页的服务,想要获取订单信息,订单服务部署在机器B上。这样,A通过远程调用B上的函数(function)来得到信息就属于远程过程调用。

    以下来自
    谁能用通俗的语言解释一下什么是 RPC 框架?

    1.首先,要解决通讯的问题。主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程调用共享同一个连接。
    2.第二,要解决寻址问题。也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称是什么,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
    3.第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal), 通过寻址和传输将序列化的二进制发送给B服务器。
    4.第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
    5.第五,返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用。

    Dubbo的产生背景

    以下来自Dubbo官方文档

    随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

    单一应用架构

    当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。

    垂直应用架构

    当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。

    分布式服务架构

    当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。

    流动计算架构

    当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

    Dubbo面临的需求

    在大规模服务化之前,应用可能只是通过 RMI 或 Hessian 等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过 F5 等硬件进行负载均衡。

    当服务越来越多时,服务 URL 配置管理变得非常困难,F5 硬件负载均衡器的单点压力也越来越大。 此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和 Failover,降低对 F5 硬件负载均衡器的依赖,也能减少部分成本。

    当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。 这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。

    接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器? 为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。

    以上是 Dubbo 最基本的几个需求。

    Dubbo的架构

    节点角色说明

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

    调用关系说明

    1.服务容器负责启动,加载,运行服务提供者。
    2.服务提供者在启动时,向注册中心注册自己提供的服务。
    3.服务消费者在启动时,向注册中心订阅自己所需的服务。
    4.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
    5.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
    6.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

    Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。

    Demo time

    首先,确认本次的目标。学习一项技术首先要了解背景以及意义。前文摘自官网的内容已经给出了答案。然后就是一个Hello World, 给学习者一个信心:这东西很容易上手的。So,接下来的demo依旧来自官方,特别简单的一个模拟运行。后面再继续深入用法。

    由于Maven在之前极盛行,demo仍旧用maven当作构建工具,当然,后面熟悉后可切换为gradle。

    本次demo见 https://github.com/Ryan-Miao/dubbo-hello-demo

    新建一个maven项目

    在idea里新建空的maven项目。

    File->new->project->maven

    填写group和artifact。

    
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.test</groupId>
        <artifactId>dubbo-hello-demo</artifactId>
        <packaging>pom</packaging>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <repositories>
            <repository>
                <id>central</id>
                <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
                <name>aliyun</name>
            </repository>
        </repositories>
        <pluginRepositories>
            <pluginRepository>
                <id>central</id>
                <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
                <name>aliyun</name>
            </pluginRepository>
        </pluginRepositories>
    
    </project>
    

    提供服务的API

    通过上述的介绍也能理解,消费者需要知道提供者的接口,那么就一定要共享接口和参数以及响应类。所以,我们先抽离一个单独的API项目来专门声明API。

    在项目名上右键,new -> moudle, 选择maven,新建一个新的空maven项目。

    然后,创建一个用户服务接口com.test.hello.api.IUserService

    package com.test.hello.api;
    
    public interface IUserService {
        String sayHi(String name);
    }
    

    这次的主角是dubbo,所以就不填充参数和包结构整理了。简单传入参数String和返回String就好。

    提供服务的provider

    刚才声明了一个服务的接口,我们还需要一个实现,来提供真实的服务。而这个服务则是一个独立的项目。我们可以部署在某个机器上。

    在项目名上右键,new -> module, 选择Spring Initializr, 然后只选择web就可以了。最终生成的pom如下

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.test</groupId>
    	<artifactId>hello-provider</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<name>hello-provider</name>
    	<description>Demo for dubbo provider hello world</description>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.0.0.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    		<java.version>1.8</java.version>
    		<dubbo.version>2.6.1</dubbo.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>dubbo</artifactId>
    			<version>${dubbo.version}</version>
    		</dependency>
    
    		<dependency>
    			<groupId>com.test</groupId>
    			<artifactId>hello-api</artifactId>
    			<version>1.0-SNAPSHOT</version>
    		</dependency>
    	</dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    
    </project>
    
    

    当然,手动添加dubbo依赖

    <dependency>
    	<groupId>com.alibaba</groupId>
    	<artifactId>dubbo</artifactId>
    	<version>${dubbo.version}</version>
    </dependency>
    

    还要引入我们刚才定义的共享接口定义项目:

    <dependency>
    	<groupId>com.test</groupId>
    	<artifactId>hello-api</artifactId>
    	<version>1.0-SNAPSHOT</version>
    </dependency>
    

    接下来,就是实现这个接口了。创建实现类com.test.helloprovider.service.impl.UserService

    package com.test.helloprovider.service.impl;
    
    
    import com.test.hello.api.IUserService;
    
    import java.util.Date;
    
    public class UserService implements IUserService {
        @Override
        public String sayHi(String name) {
            return "Hi " + name + ", current date is: " + new Date();
        }
    }
    

    然后,只要把这个服务发布出去就行了。在spring cloud里,发布一个服务就是发布web项目,启动tomcat来提供一个rest api。而在这里,我们不需要。我们要做的是把自己注册到dubbo里,等消费者来拿。

    在resource下新建provider.xml

    <?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: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://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 提供方应用信息,用于计算依赖关系 -->
        <dubbo:application name="hello-provider"  />
    
        <!-- 使用multicast广播注册中心暴露服务地址 -->
        <dubbo:registry address="multicast://224.5.6.7:1234" />
    
        <!-- 用dubbo协议在20880端口暴露服务 -->
        <dubbo:protocol name="dubbo" port="20880" />
    
        <!-- 声明需要暴露的服务接口 -->
        <dubbo:service interface="com.test.hello.api.IUserService" ref="userService" />
    
        <!-- 和本地bean一样实现服务 -->
        <bean id="userService" class="com.test.helloprovider.service.impl.UserService" />
    </beans>
    
    

    然后,我们只要启动Spring容器就行了,我们的bean还是声明在spring里的。

    创建一个启动类com.test.helloprovider.HelloProviderApplication

    package com.test.helloprovider;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.io.IOException;
    
    public class HelloProviderApplication {
    
    	public static void main(String[] args) throws IOException {
    		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
    				new String[] {"provider.xml"});
    		context.start();
    		System.in.read(); // 按任意键退出
    	}
    }
    

    运行main方法即可。

    这里的注册中心只是简单的multicast组播。这样,我们就发布了一个用户服务,提供sayHi方法。接下来只要给消费者调用就行。

    消费服务的consumer

    同样的步骤,我们来建立一个consumer。这个consumer是另一个独立的项目,这个项目也可以部署在另一个机器上。这个项目需要调用provider的项目来获得用户信息。

    和provider不同的是,项目的artifact不一样。

    新建好之后就可以在spring容器里远程调用了。同样在resource下新建一个consumer.xml

    <?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: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://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
        <dubbo:application name="hello-consumer"  />
    
        <!-- 使用multicast广播注册中心暴露发现服务地址 -->
        <dubbo:registry address="multicast://224.5.6.7:1234" />
    
        <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
        <dubbo:reference id="userService" interface="com.test.hello.api.IUserService" />
    </beans>
    
    

    然后,调用我们的bean完成消费。创建启动类

    
    public class HelloConsumerApplication {
    
        public static void main(String[] args) {
            final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                    new String[]{"consumer.xml"});
            context.start();
            final IUserService userService = context.getBean("userService", IUserService.class); // 获取远程服务代理
            String hello = userService.sayHi("world"); // 执行远程方法
            System.out.println("===================================");
            System.out.println(hello); // 显示调用结果
            System.out.println("===================================");
        }
    }
    

    运行main方法可以看到控制台打印内容

    
    22:43:38.034 [main] INFO com.alibaba.dubbo.config.AbstractConfig -  [DUBBO] Refer dubbo service com.test.hello.api.IUserService from url multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?anyhost=true&application=consumer-of-helloworld-app&check=false&dubbo=2.6.1&generic=false&interface=com.test.hello.api.IUserService&methods=sayHi&pid=6204&register.ip=192.168.0.108&remote.timestamp=1521902609769&side=consumer&timestamp=1521902617561, dubbo version: 2.6.1, current host: 192.168.0.108
    22:43:38.206 [DubboClientHandler-192.168.0.108:20880-thread-1] DEBUG com.alibaba.dubbo.remoting.transport.DecodeHandler -  [DUBBO] Decode decodeable message com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcResult, dubbo version: 2.6.1, current host: 192.168.0.108
    ===================================
    Hi world, current date is: Sat Mar 24 22:43:38 CST 2018
    ===================================
    22:43:38.207 [DubboShutdownHook] INFO com.alibaba.dubbo.config.AbstractConfig -  [DUBBO] Run shutdown hook now., dubbo version: 2.6.1, current host: 192.168.0.108
    22:43:38.208 [DubboShutdownHook] INFO com.alibaba.dubbo.registry.support.AbstractRegistryFactory -  [DUBBO] Close all registries [multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?application=consumer-of-helloworld-app&dubbo=2.6.1&interface=com.alibaba.dubbo.registry.RegistryService&pid=6204&timestamp=1521902617639], dubbo version: 2.6.1, current host: 192.168.0.108
    22:43:38.208 [DubboShutdownHook] INFO com.alibaba.dubbo.registry.multicast.MulticastRegistry -  [DUBBO] Destroy registry:multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?application=consumer-of-helloworld-app&dubbo=2.6.1&interface=com.alibaba.dubbo.registry.RegistryService&pid=6204&timestamp=1521902617639, dubbo version: 2.6.1, current host: 192.168.0.108
    22:43:38.208 [DubboShutdownHook] INFO com.alibaba.dubbo.registry.multicast.MulticastRegistry -  [DUBBO] Unregister: consumer://192.168.0.108/com.test.hello.api.IUserService?application=consumer-of-helloworld-app&category=consumers&check=false&dubbo=2.6.1&interface=com.test.hello.api.IUserService&methods=sayHi&pid=6204&side=consumer&timestamp=1521902617561, dubbo version: 2.6.1, current host: 192.168.0.108
    22:43:38.208 [DubboShutdownHook] INFO com.alibaba.dubbo.registry.multicast.MulticastRegistry -  [DUBBO] Send broadcast message: unregister consumer://192.168.0.108/com.test.hello.api.IUserService?application=consumer-of-helloworld-app&category=consumers&check=false&dubbo=2.6.1&interface=com.test.hello.api.IUserService&methods=sayHi&pid=6204&side=consumer&timestamp=1521902617561 to /224.5.6.7:1234, dubbo version: 2.6.1, current host: 192.168.0.108
    

    如此,hello world 完成。

  • 相关阅读:
    739. Daily Temperatures
    556. Next Greater Element III
    1078. Occurrences After Bigram
    1053. Previous Permutation With One Swap
    565. Array Nesting
    1052. Grumpy Bookstore Owner
    1051. Height Checker
    数据库入门及SQL基本语法
    ISCSI的概念
    配置一个IP SAN 存储服务器
  • 原文地址:https://www.cnblogs.com/cxy2020/p/13095402.html
Copyright © 2011-2022 走看看