Dubbo学习1-Hello world

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介: 前言互联网技术到今天已经非常成熟和稳定了,其中为了解决高并发、大规模的服务请求,出现了微服务、RPC这样的分布式架构。今天就从头开始学习RPC框架dubbo。为什么要学Dubbo关于分布式的解决方案有很多,光RPC框架就有很多种,甚至有人比较了RPC框架性能, 结果显示dubbo垫底,以及spring cloud这种推崇Rest Http请求代替RPC, 那为什么还要学习RPC?首先,RPC框架的发展并没有因为Spring Cloud的出现而变的衰弱。

img_c485151e98f5d92e22ca50861e1359d1.jpe

前言

互联网技术到今天已经非常成熟和稳定了,其中为了解决高并发、大规模的服务请求,出现了微服务、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 框架?

img_71e40165a7971b745017e818bd4c2159.jpe

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官方文档

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

img_23791576e8f92918933e5ec1909d4538.jpe

单一应用架构

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

垂直应用架构

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

分布式服务架构

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

流动计算架构

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

Dubbo面临的需求

img_834268c031cf5cbbfafa1a7fe0377e81.jpe

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

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

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

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

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

Dubbo的架构

img_f07431ff8daafff6906882197d395a2a.jpe

节点角色说明

节点 角色说明
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 完成。

参考

    关注我的公众号

img_acfe50023e4718b33064273d65e4cd67.jpe
唯有不断学习方能改变! -- Ryan Miao
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
6月前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
24天前
|
存储 负载均衡 监控
dubbo学习一:zookeeper与dubbo的关系,下载安装启动zookeeper(解决启动中报错)
这篇文章是关于Apache Dubbo框架与Zookeeper的关系,以及如何下载、安装和启动Zookeeper的教程,包括解决启动过程中可能遇到的报错问题。
38 3
dubbo学习一:zookeeper与dubbo的关系,下载安装启动zookeeper(解决启动中报错)
|
19天前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
24天前
|
监控 Dubbo Java
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
这篇文章详细介绍了如何将Spring Boot与Dubbo和Zookeeper整合,并通过Dubbo管理界面监控服务注册情况。
52 0
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
|
24天前
|
Dubbo IDE Java
dubbo学习二:下载Dubbo-Admin管理控制台,并分析在2.6.1及2.6.1以后版本的变化
这篇文章是关于如何下载和部署Dubbo管理控制台(dubbo-admin)的教程,并分析了2.6.1版本及以后版本的变化。
26 0
dubbo学习二:下载Dubbo-Admin管理控制台,并分析在2.6.1及2.6.1以后版本的变化
|
6月前
|
Dubbo Java 应用服务中间件
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
507 0
|
分布式计算 监控 Dubbo
【e3项目学习二】——zk与dubbo的组合运用
注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。使用dubbo-2.3.3以上版本,建议使用zookeeper注册中心。
|
Dubbo Java 应用服务中间件
dubbo的入门学习(三)springboot整合dubbo
dubbo的入门学习(三)springboot整合dubbo
dubbo的入门学习(三)springboot整合dubbo
|
Dubbo 应用服务中间件
如何去学习Dubbo?(一)
如何去学习Dubbo?(一)
107 0
如何去学习Dubbo?(一)
|
XML Dubbo Java
dubbo的入门学习(二)
dubbo的入门学习(二)
dubbo的入门学习(二)