Dubbo & ZooKeeper 简单入门

Scroll Down

Dubbo & ZooKeeper

分布式的基本定义

分布式系统是若干个独立计算机的集合 ,这些计算机对于用户来说就像单个相关系统

利用更多机器,进行更多计算

image

使用廉价的机器完成更高性能的计算机才能完成的工作

应用架构的演变

  1. 单一的小型应用
  2. 垂直应用架构(多个应用放在多个多个服务器上)
    • 界面-逻辑实现分离
    • 应用
  3. 分布式服务架构

RPC

远程过程调用

相对于本地过程调用,本地A方法调用本地B方法

远程过程调用,本地的A方法调用另外一台电脑上的B方法

img

他允许程序调用另一个地址空间的过程或函数,而不用程序员显式编码这个远程调用的细节,使调用本地的过程和调用远程的过程代码基本相同

img

ZooKeeper

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

安装zookeeper

下载地址:https://zookeeper.apache.org/releases.html

下载安装完成后,需要配置一个文件才能进行运行

在安装目录下conf文件夹下配置一个zoo.cfg

需要把zoo_sample.cfg复制一份,然后进行配置

如果出错,确保环境变量中JAVA_HOME配置正确

启动zookeeper

启动bin目录下

以管理员身份启动 zkServer.cmd,服务端程序

如果没有闪退就证明启动成功了,如果闪退可能是Java环境变量的问题

再启动zkCli.cmd,这是客户端程序

Dubbo Admin

为了方便我们管理Dubbo,我们使用Dubbo Admin来进行管理

下载Dubbo Admin 的方式很简单

https://github.com/apache/dubbo-admin/tree/master

直接clone或者下载下来都行

因为这个只有源码,只能自己进行构建,我们使用maven进行构建

在项目根目录打开cmd

mvn clean package

便会自动开始打包

Dubbo Admin默认的端口是7001端口

server.port=7001
spring.velocity.cache=false
spring.velocity.charset=UTF-8
spring.velocity.layout-url=/templates/default.vm
spring.messages.fallback-to-system-locale=false
spring.messages.basename=i18n/message
spring.root.password=root
spring.guest.password=guest

dubbo.registry.address=zookeeper://127.0.0.1:2181

这里面的东西都能进行更改

如果zookeeper的端口号进行了修改的话,这里也要同步进行修改

打包好的jar在dubbo-admin/target文件夹下,cd到那边,在这里进行启动

java -jar jar包名

基本上就成功运行了

重要提醒:打开dubbo-admin之前要打开zookeeper

Dubbo

img

  1. 面向接口代理的高性能RPC调用
  2. 智能负载均衡
  3. 服务自动注册与发现

快速开始

导入依赖

这里没有使用spring boot,使用的是一个普通的maven项目

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

因为zookeeper的注册也需要使用jar包

Dubbo 支持 zkclient 和 curator 两种 Zookeeper 客户端实现

这里注意

  1. Dubbo从 2.2.0 版本开始缺省为 zkclient 实现
  2. Dubbo从 2.3.0 版本开始支持可选 curator 实现

根据我这里的Dubbo版本,我们使用curator实现

<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.2.0</version>
</dependency>

场景描述

这里分为两个角色生产者(服务提供者)消费者(服务使用者)

生产者提供服务,消费者消费服务

定义生产者提供服务的类

public interface UserService()
{
    User findUserById(String id);
}

消费者使用的类是

public interface OrderService()
{
    void addOrder();
}

这是两个接口

其中消费者使用的方法中会调用这个生产者的UserService

代码编写

定义公共的接口项目

在官方文档中指出

http://dubbo.apache.org/zh-cn/docs/user/best-practice.html

建议将服务接口、服务模型、服务异常等均放在 API 包中,因为服务模型和异常也是 API 的一部分,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。

所以我们在使用Dubbo的时候最好建立一个API包

在项目中新建API模块,取名service-api,这是一个maven项目,里面存放的内容有

  1. Bean
  2. Service的接口
  3. ...等公共的部分

所以我们在里面新建一个包,com.dubboLearn.pojo,编写Bean

public class User {
    private String UserId;
    private String UserName;
}

新建一个包com.dubboLearn.service编写Service,里面的内容和刚刚场景描述中的相同

编写服务提供者

新建一个模块dubbo-provider,也是一个普通的maven项目,在pom.xml文件中需要导入依赖

<dependency>
    <groupId>com.dubboLearn</groupId>
    <artifactId>service-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

这样构建的时候就导入了Api模块的依赖

编写服务的实现类,在com.dubboLearn.service.impl包下新建UserServiceImpl

public class UserServiceImpl implements UserService {

    public static Map<String,User> userMap;
    static {
        userMap = new HashMap<String, User>();
        userMap.put("1",new User("1","lucas"));
    }
    public User findUserById(String id) {
        return UserServiceImpl.userMap.get(id);
    }

}

我们这里使用的假数据,由静态代码块进行初始化

现在我们将配置dubbo并暴露服务

因为dubbo的底层也使用spring进行项目的管理,我们可以使用spring配置文件进行配置

在官方文档中

http://dubbo.apache.org/zh-cn/docs/user/quick-start.html

创建,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://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">

    <!-- 提供方应用信息,用于计算依赖关系 -->
    <!-- 只要不和别的服务同名就行 -->
    <dubbo:application name="server-provider"  />

    <!-- 使用zookeeper注册中心暴露服务地址 -->
    <!-- 指定注册中心的位置 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />
    <!-- 也可以这样写 -->
    <!-- <dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181"/> -->

    <!-- 用dubbo协议在20880端口暴露服务 -->
    <!-- 指定通信规则 -->
    <dubbo:protocol name="dubbo" port="20880" />

    <!-- 声明需要暴露的服务接口 -->
    <!-- ref指向真正实现的类 -->
    <dubbo:service interface="com.dubboLearn.service.UserService" ref="userService" />

    <!-- 和本地bean一样实现服务 -->
    <!-- 注册这个bean到 spring 容器 -->
    <bean id="userService" class="com.dubboLearn.service.impl.UserServiceImpl" />
</beans>
启动这个服务

编写main方法

public static void main(String[] args) throws IOException {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:provider.xml");
    //启动Ioc容器
    context.start();
    //阻塞进程,不让容器关闭
    System.in.read();
}

此时如果报错可能是jar包导入的不对,导入的是阿里的依赖,不是阿帕奇的

如果zookeeper启动的话,那么项目启动就会成功,在Dubbo admin控制台中也能看得见v

image20200505165006599.png

编写服务的使用者

新建一个模块dubbo-consumer,是一个普通的maven项目

和provider一样,新建一个包com.dubboLearn.service.impl,新建一个类OrderServiceImpl

编写实现类

public class OrderServiceImpl implements OrderService {
    
    private UserService userService;

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    public void addOrder() {
        User user = userService.findUserById("1");
        if (user!=null)
            System.out.println(user.getUserName()+"订购了一些东西");
    }
}
配置dubbo

新建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://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">

    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <dubbo:application name="dubbo-consumer"  />

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

    <!-- 生成远程服务代理,可以和本地bean一样使用UserService -->
    <!-- 声明需要访问的服务的接口,在本地IOC容器中生成代理 -->
    <dubbo:reference id="userService" interface="com.dubboLearn.service.UserService" />

    <!-- 在容器中注册我们刚刚写好的Bean -->
    <bean id="orderService" class="com.dubboLaern.service.impl.OrderServiceImpl">
        <property name="userService" ref="userService"/>
    </bean>
</beans>
启动消费者
public static void main(String[] args) throws IOException {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
    OrderService orderService = context.getBean("orderService", OrderService.class);
    orderService.addOrder();
    System.in.read();
}

这样调用就成功了

dubbo 监控中心

在刚刚的Dubbo Admin文件夹中有一个dubbo-monitor,在里面构建项目,构建完会有一个压缩包,解压

里面有一个conf文件夹,文件夹下有一个properties文件,里面的文件按需更改

值得注意的是

dubbo.protocol.port=7070

这个可能会用到

bin目录下找到start.bat,启动,访问刚刚配置文件中的端口号,如果能访问成功那就证明配置没问题

配置注册的服务

provider.xml中配置

使用以下两种都可以

  1.  <dubbo:monitor protocol="registry"/>
    
  2.  <dubbo:monitor address="127.0.0.1:7070"/>
    

第一个表示从注册中心寻找

第二个表示直接连接监控中心,address中填的端口号就是刚刚配置的端口号

image20200505164737012.png

这样监控中心就有服务的信息了

当然,在consumer那边也是可以配置的