Dubbo源码-从HelloWorld开始

时间:2022-05-07
本文章向大家介绍Dubbo源码-从HelloWorld开始,主要内容包括Dubbo简介、HelloWorld之前的两个小问题、HelloWorld的准备工作、运行HelloWorld、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

Dubbo简介

Dubbo,相信做后端的同学应该都用过,或者有所耳闻。没错,我就是那个有所耳闻中的一员。

公司在好几年前实现了一套自己的RPC框架,所以也就没有机会使用市面上琳琅满目的RPC框架产品。

之所以想好好看看Dubbo,有以下几个原因

  • 公司内部的框架一直在做迭代更新,配置越来越简洁,性能越来越好。但是作为使用者,它就像一个黑盒子,我们无法感知其内部的改动以及实现的原理
  • 现在使用的框架,因为使用了thrift,让平时的开发显得格外的蹩脚,常常在各种model的转换中迷失自我,耗尽了耐心
  • 阿里团队从去年开始重新维护Dubbo,并在春节之际进入Apache孵化器,在开源的道路上又猛跨一大步,其背后定然有我们值得学习借鉴的地方,更何况有阿里技术的背书
  • 开源项目是很好的学习素材,希望借助学习Dubbo代码,了解序列化、分布式、网络通讯等方面的知识

Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。

GitHub:https://github.com/apache/incubator-dubbo

官网:http://dubbo.apache.org/

中文用户手册:http://dubbo.io/books/dubbo-user-book/

HelloWorld之前的两个小问题

1.没有Dubbo之前,我们是什么样的工作方式

Dubbo代表的是一类RPC框架,类似的产品还有鼎鼎大名的gRPC。

没有Dubbo之前是什么样的,可以回想下我们学生时代做的项目。

一台电脑既是服务器又是客户端,估计当时也没有想过我调用的这个接口是哪台电脑上,我是不是可以多部署几台电脑,怎么样充分利用这几台电脑好让调用的效率更高。

因为即使想了,也搞不了,因为没钱!

即使我们在自己的PC上把项目做好了,需要部署到服务器上,那么我们只要记住那台服务器的IP,使用Socket通讯,就很简单的实现了服务的调用和通讯了。

2.Dubbo有什么用

接着学生时代的项目说,那时候我们做个图书管理系统,学籍管理系统,其访问量和并发量一般不会太高,准确说,是非常低。

但是如果还是一个服务端,大量的用户请求,达到高并发的场景,那么问题就来了,一台机子显然承受不住,这时候需要考虑分布式。

Dubbo的产生于微服务联系紧密,我们一方面想着借助微服务的思想,实现各个服务或者模块之间的解耦。那么我们另一方面就不能忽视服务之间的通讯,这时候Dubbo一类的RPC框架就应运而生。

我们需要考虑扩展性,比如为了防止访问过载,服务所在机器需要进行水平扩展,同时也要考虑不断增加的服务调用方。

我们需要考虑负载均衡,怎么样才能将服务集群的威力发挥到最大。

我们需要考虑如何自动的注册服务以及更新服务,如果做好异常情况下,比如注册中心宕机时,服务方和调用方之间的服务调用。

如此种种,都是催生Dubbo的重要因素。

HelloWorld的准备工作

  • 下载安装zookeeper,在命令行执行brew install zookeeper

相应的启动zk和关闭zk服务的命令分别是zkServer startzkServer stop

运行HelloWorld

导入Dubbo项目并且完成编译后,可以看到Dubbo项目的目录结构如下

今天要介绍的是dubbo-demo,该子模块包括

  • dubbo-demo-api(提取出公共接口)
  • dubbo-demo-consumer(服务调用方)
  • dubbo-demo-provider(服务提供方)

dubbo-demo-api

该模块最核心的类就是DemoService接口,该接口只有一个方法sayHello

package com.alibaba.dubbo.demo;

public interface DemoService {

    String sayHello(String name);

}

这个接口是联系调用方和提供方的纽带。

dubbo-demo-consumer

该模块核心的类为Consumer,主要是一个main函数

public class Consumer {

    public static void main(String[] args) {
        //Prevent to get IPV6 address,this way only work in debug mode
        //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not
        System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
        context.start();
        DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy

        while (true) {
            try {
                Thread.sleep(1000);
                String hello = demoService.sayHello("world"); // call remote method
                System.out.println(hello); // get result

            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }


        }

    }
}

其主要功能是加载配置文件,用于寻找服务提供方所在的位置,拿到DemoService接口的实现类DemoServiceImpl,并调用其方法实现sayHello

dubbo-demo-provider

该模块包含了DemoService的实现类DemoServiceImpl,同时包含一个服务启动类Provider

public class Provider {

    public static void main(String[] args) throws Exception {
        //Prevent to get IPV6 address,this way only work in debug mode
        //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not
        System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
        context.start();

        System.in.read(); // press any key to exit
    }

}

启动注册中心

因为调用方和服务提供方需要靠注册中心来联系,提供方将自己的服务登记到注册中心,调用方需要拉取可用的服务提供方的位置信息,比较常见的关系描述如下图所示

调用关系说明

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

鉴于Dubbo源码中,配置文件中的默认配置是multicast,但是我在运行的时候总是出现can't assign address的情况,所以改用zookeeper。

相应修改如下,在dubbo-demo-provider项目中,将dubbo-demo-provider.xml修改为

<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- provider's application name, used for tracing dependency relationship -->
    <dubbo:application name="demo-provider"/>

    <!-- use multicast registry center to export service -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!-- use dubbo protocol to export service on port 20880 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!-- service implementation, as same as regular local bean -->
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>

    <!-- declare the service interface to be exported -->
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/>

</beans>

将dubbo-demo-consumer项目中的dubbo-demo-consumer.xml修改为

<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- consumer's application name, used for tracing dependency relationship (not a matching criterion),
    don't set it same as provider -->
    <dubbo:application name="demo-consumer"/>

    <!-- use multicast registry center to discover service -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!-- generate proxy for the remote service, then demoService can be used in the same way as the
    local regular interface -->
    <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>

</beans>

同时在命令行输入zkServer start启动zk

分别启动Proiver和Consumer

运行Provider类,将自己的服务接口对外开放

运行Consumer类,寻找服务提供方,并调用其接口实现

至此,对于Dubbo有了一个初步的认识并通过dubbo-demo项目了解Dubbo的运作模式。

网上找了一份PDF版的源码阅读心得,如果有需要,下方留下你的邮箱

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。