Dubbo系列(一)dubbo介绍和入门

Dubbo系列(一)dubbo介绍和入门

学习Dubbo 之前,先了解一下这几个问题:

  1. Dubbo是什么?
  2. 互联网发展的背景
  3. Dubbo介绍
  4. Dubbo的优势在哪里?

了解了dubbo之后,让我们从零搭建一个简单的dubbo项目。

Dubbo是什么

官网介绍

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

可以了解到:

  1. Dubbo是一款RPC框架,核心功能是远程方法调用、服务的注册和发现
  2. Dubbo是由java语言开发
  3. Dubbo提供了智能容错、负载均衡实现

互联网发展的背景

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

  • 单一应用架构

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

  • 垂直应用架构

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

  • 分布式服务架构

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

  • 流动计算架构

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

Dubbo介绍

随着互联网架构的演进,为了满足大型业务量的项目,分布式架构已然成为主流,dubbo这样的RPC框架因此诞生,对于我们而言,有前人栽好的大树就该学会好好利用,并逐渐改善来满足个体需求。

dubbo架构

有了dubbo,我们可以很方便的对业务服务进行垂直拆分、横向拆分,并很好的协调起来,令所有服务节点像一个单独应用正常工作。

Registry:负责服务的注册和发现、订阅

Monitor:负责监控服务信息

Dubbo的优势在哪里

首先从官网上可以看到一些官方推荐的特性:

  • 面向接口代理的高性能RPC调用
    提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发者屏蔽远程调用底层细节。

  • 智能负载均衡
    内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高系统吞吐量。

  • 服务自动注册与发现
    支持多种注册中心服务,服务实例上下线实时感知。

  • 高度可扩展能力
    遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现和第三方实现。

  • 运行期流量调度
    内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能。

  • 可视化的服务治理与运维
    提供丰富服务治理、运维工具:随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数。

简单的梳理一下:

  1. RPC调用性能高
  2. 提供负载均衡实现
  3. 服务注册与发现
  4. 可扩展能力强
  5. 有监控系统,可流控
  6. 方便运维控制

这样看还不够直观,作为一个rpc框架,没有对比就没有伤害,这里列举一些其他的rpc框架:

  1. RMI(java原生实现),性能差,以上特性都不具备
  2. Spring Cloud(REST),只支持http,性能受限
  3. grpc(由google开发),只支持http,且只支持ProtoBuf序列化协议,性能较强
  4. …还有例如motan等就不作比较了

可以看出dubbo在使用上和扩展性方面都是比较好的,方便用户改造以及灵活的切换不同的通信协议、序列化协议等。

从零搭建简单的Dubbo项目

一、环境准备

jdk(笔者使用的版本是1.8)

maven(笔者使用的版本是3.3.9)

zookeeper(笔者使用的版本是3.4.13)

ps.笔者使用的dubbo版本是2.6.4,dubbo版本不同可能有所影响

二、构建服务提供者项目

由于暴露的仅仅是api,所以构建api和impl两个子模块

api模块

  • 定义一个接口,并提供需要被远程调用的方法
    public interface TestService {
    
        String say(String what);
    }
  • 为了方便消费端调用,提供引用xml,以免消费端需要先查看api后根据api来编写引用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://dubbo.apache.org/schema/dubbo"
           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"
           xmlns:context="http://www.springframework.org/schema/c">
    
        <dubbo:reference id="testService"
                         interface="com.xcxcxcxc.dubbo.provider.TestService"/>
    
    </beans>

impl模块

  • 由于需要dubbo来暴露服务,首先引入maven依赖
    <?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">
        <parent>
            <artifactId>service-provider</artifactId>
            <groupId>com.xcxcxcxcx</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>service-provider-impl</artifactId>
    
        <properties>
            <dubbo.version>2.6.4</dubbo.version>
        </properties>
    
        <dependencies>
            <!--dubbo-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dubbo</artifactId>
                <version>${dubbo.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dubbo-registry-zookeeper</artifactId>
                <version>${dubbo.version}</version>
            </dependency>
    
            <!-- api -->
            <dependency>
                <groupId>com.xcxcxcxcx</groupId>
                <artifactId>service-provider-api</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
    </project>
  • 定义实现类,实现TestService接口
    package com.xcxcxcxc.dubbo.provider.impl;
    
    import com.xcxcxcxc.dubbo.provider.TestService;
    
    /**
     * @author XCXCXCXCX
     * @since 1.0
     */
    public class TestServiceImpl implements TestService{
    
        @Override
        public String say(String what) {
            return "someone say that : \"" + what + "\"";
        }
    }
  • 为了简单,编写简单的引导类来暴露服务
    public class ServiceExposer {
    
    
        public static void main(String[] args) throws IOException {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/service-provider.xml");
            context.start();
            System.in.read(); // 按任意键退出,为了避免主线程结束而导致服务取消暴露
        }
    }
  • 当然别忘了配置所需要暴露服务的信息
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    
           xmlns="http://www.springframework.org/schema/beans" 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-4.3.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">
    
    
        <context:property-placeholder location="classpath:properties/appliaction.properties"/>
    
        <!-- provider's application name, used for tracing dependency relationship -->
        <dubbo:application name="${application.name}" owner="${dubbo.application.owner}"/>
    
        <!-- use multicast registry center to export service -->
        <dubbo:registry protocol="zookeeper" address="${dubbo.zk.servers}"
                group="${dubbo.zk.group}" file="${dubbo.cache.dir}/service-provider.cache"/>
    
        <!-- use dubbo protocol to export service on port 20880 -->
        <dubbo:protocol name="dubbo" port="${dubbo.service.provider.port}"
                        accesslog="${dubbo.protocol.accesslog}"/>
    
        <!-- service implementation, as same as regular local bean -->
        <bean id="testSerivce" class="com.xcxcxcxc.dubbo.provider.impl.TestServiceImpl"/>
    
        <!-- declare the service interface to be exported -->
        <dubbo:service interface="com.xcxcxcxc.dubbo.provider.TestService"
                       ref="testSerivce" timeout="3000"/>
    </beans>

properties

    application.name=service-provider
    dubbo.service.provider.port=20000
    dubbo.service.provider.threads=200
    dubbo.cache.dir=/logs/cache
    
    dubbo.zk.servers=192.168.179.130:2181
    dubbo.zk.group=dubbo-learning-dev
    
    dubbo.application.owner=xcxcxcxcx
    dubbo.protocol.accesslog=/logs/dubbo-user.log

三、构建服务消费者项目

  • 依赖于dubbo来发现服务,依然需要引入dubbo依赖(别忘了引入api包)
    <?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">
        <parent>
            <artifactId>dubbo-learning</artifactId>
            <groupId>com.xcxcxcxcx</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>service-consumer</artifactId>
    
        <properties>
            <dubbo.version>2.6.4</dubbo.version>
        </properties>
    
        <dependencies>
            <!-- dubbo及相关依赖包 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dubbo</artifactId>
                <version>${dubbo.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dubbo-registry-zookeeper</artifactId>
                <version>${dubbo.version}</version>
            </dependency>
    
            <!-- api -->
            <dependency>
                <groupId>com.xcxcxcxcx</groupId>
                <artifactId>service-provider-api</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
    </project>
  • 配置服务发现的相关信息
    <?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="service-provider" owner="xcxcxcxcx"/>
    
        <!--这里是使用zk作为注册中心,指定协议和zk地址 -->
        <dubbo:registry protocol="zookeeper" group="dubbo-learning-dev"
                        address="192.168.179.130:2181"/>
    
        <!-- api包中提供的引用xml -->
        <import resource="classpath*:client/test-reference.xml"/>
    
    
    </beans>
  • 编写简单的引导主类,用于测试服务调用情况
    package com.xcxcxcxcx.dubbo.consumer;
    
    import com.xcxcxcxc.dubbo.provider.TestService;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * @author XCXCXCXCX
     * @since 1.0
     */
    public class ServiceConsumer {
    
    
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/service-consumer.xml");
            context.start();
            TestService testService = (TestService)context.getBean("testService"); // 获取远程服务代理
            long start = System.currentTimeMillis();
            String returnVal = testService.say("hello world!"); // 执行远程方法
            long end = System.currentTimeMillis();
            System.out.println(returnVal); // 显示调用结果
            System.out.println("cost " + (end - start) + " ms"); // 显示调用耗时
    
            //第二次调用
            TestService testService2 = (TestService)context.getBean("testService"); // 获取远程服务代理
            long start2 = System.currentTimeMillis();
            String returnVal2 = testService2.say("hello world2!"); // 执行远程方法
            long end2 = System.currentTimeMillis();
            System.out.println(returnVal2); // 显示调用结果
            System.out.println("cost " + (end2 - start2) + " ms"); // 显示调用耗时
        }
    }

准备好后,开始准备测试远程服务

四、远程服务调用测试

  • 开始测试之前别忘了启动zk注册中心

确保zk启动成功,确保端口已暴露,确保能远程连接上zk

  • 启动服务提供者的引导主类

这里没有提供暴露是否成功的信息,没有报错就好

在zk上可以查看到节点信息:

展示图

  • 启动服务消费者的引导主类

控制台信息:

someone say that : “hello world!”

cost 106 ms

someone say that : “hello world2!”

cost 3 ms

可见第一次由于需要与服务建立连接,通信开销,耗时较长,第二次调用耗时仅需3ms。

ps. 本次搭建环境均是内网,另外,如果出现qos报错的情况可以忽略,一般是端口冲突问题,用于运维的通信端口。

小结

本文从官网和个人的理解出发,对dubbo进行了简单介绍和分析,以及介绍了如何搭建简单dubbo项目,随着使用时间的增加,以后将会面向dubbo源码剖析其底层原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值