Dubbo学习笔记

1.远程调用涉及的概念

1.1协议

协议是指多方共同遵循的规范,在网络中的计算机进行数据交换依靠各种协议:http、ftp等。
一台计算机按照规定好的格式发送数据,另一台计算机的程序按照指定的格式接收数据,两台计算机用互相理解的格式读写数据,达到数据交换的目的。

1.2RPC-远程过程调用协议

RPC是什么?
RPC是远程过程调用(Remote Procedure Call)的缩写形式。是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。该协议允许运行于一台计算机的程序调用另一台计算机的程序,程序员无需为网络交互功能编码。
RPC的作用?
主要功能是让构建分布式应用更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性(远程调用的语法跟本地调用的语法一样简洁)。在另一台计算机上的程序调用另外的计算机上的功能时,就像是使用自己的功能一样。RPC技术提供了透明的访问其他服务的底层实现细节,使用分布式系统的服务更加方便。
分布式是什么?
分布式是指多台计算机位于网络系统中,多台计算机形成一个整体对外界提供服务。用户使用系统不知道是多台计算机,使用不同的操作系统、不同的应用程序提供服务。

2.Dubbo初识

Apache Dubbo是一款高性能、轻量级的Java RPC框架,它有三个核心功能:面向接口的远程方法调用、智能容错和负载均衡、服务自动注册和发现。
Dubbo官网
高性能要从底层的原理说起,既然是一个RPC框架,要做的就是远程过程方法调用,那么提升性能就要从最关键、最耗时的两个方面入手:序列化和网络通信。
序列化:本地的对象要在网络上传输,必须要实现Serializable接口,也就是必须序列化。我们序列化的方式有很多:xml、json、二进制流…其中效率最高的就是二进制流,因为计算机就是二进制的,Dubbo采用的就是效率最高的二进制。
网络通信:不同于HTTP要进行七步走(三次握手四次挥手),Dubbo采用Socket通信机制,一步到位,提升了通信的效率,并且建立了长连接,不必反复连接。
废话:2017年SpringCloud横空出世后,已经停更好几年的Dubbo开始更新,阿里巴巴整合了当当网的Dubbo X,然后把Dubbo贡献给了Apache基金会,所以现在Dubbo是由Apache在维护和更新。

2.1Dubbo能做什么

  • 实现透明的远程方法调用,就像调用本地方法一样,可以忽略远程调用的实现细节,简单配置即可使用。
  • 服务的自动注册和服务发现。通过注册中心,服务实现动态管理(增减服务方)。调用服务的消费者无需写死调用地址。
  • 软件的负载均衡实现和容错机制,无需使用硬件。降低成本。

2.2Dubbo的底层实现原理

Dubbo的底层实现是动态代理,由Dubbo框架创建远程服务(接口)对象的的代理对象,通过代理对象调用远程方法。
在这里插入图片描述

2.3Dubbo支持的协议

支持8种协议:dubbo、hessian、rmi、http、webservice、thrift、memcached、redis。
Dubbo官方推荐使用dubbo协议,默认端口号为20880。

2.4Dubbo协议

dubbo协议的特点:
dubbo协议采用单一长连接和异步通信,适用于小数据量、大并发的服务调用,以及服务消费者(Consumer)机器数远大于服务提供者(Provider)机器数的情况。异步通信可以提高处理效率
网络通信:
Dubbo协议底层网络通信默认的是netty,性能非常优秀,官方推荐使用。
dubbo协议不适用的场景:
dubbo协议不适合传送大数据量的服务,比如传文件、传视频等,除非请求量很低。

2.5长连接和短连接

长连接的网络通道一旦建立就可以一直使用,除非断线宕机,省去了建立网络通道的时间。传输小数据量速度快,省去排队时间,所以效率高。一般服务器与服务器之间使用长连接。
在这里插入图片描述

短连接每次传输数据都要建立新的连接,耗时,但是使用完毕后连接断,不会占用服务器资源。一般服务器和客户端之间使用短链接

2.6Dubbo架构

此架构图来自于动力节点
在这里插入图片描述
此架构图来自于Dubbo官网
在这里插入图片描述
实际开发中需要的provider、consumer、register
可以将Container看成美团,里面有很多商家(Provider),商家每天把要卖的饭放到菜单(Registry),顾客(Cunsumer)查看菜单,然后选择自己想要的(notify),最后去商家取货(invoke),平台拥有者(Monitor)可以监控商家和顾客的操作。
官方解释:

  1. Provider:暴露服务的服务提供方
  2. Consumer:调用远程服务的服务消费方
  3. Registry:服务注册与发现的注册中心
  4. Monitor:统计服务的调用次数和调用时间的监控中心
  5. Container:服务运行容器

调用关系说明:

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

3.Dubbo直连

点对点直连:消费者直接访问服务提供者,没有注册中心。消费者必须指定服务提供者的访问地址(url)。
服务提供者步骤:

  1. 新建一个maven web工程,作为服务的提供者
  2. 导入相关依赖
  3. 定义实体类,实现序列化接口
  4. 定义服务的接口和实现类
  5. 定义spring的配置文件
    a:声明Dubbo服务提供者的名称:保证唯一
    b:声明Dubbo使用的协议和端口号
    c:暴露服务,使用直连方式
  6. 修改web.xml,注册spring监听器

创建一个maven项目,由于Dubbo与Spring是无缝对接的,所以在pom.xml中添加Spring的相关依赖。

 <!--Spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <!--dubbo依赖-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.2</version>
    </dependency>

注意: Dubbo的版本为2.6.2时,启动会报错(无法将register的“N/A”从String类型转换为Boolen类型)。解决方法,对Dubbo版本进行升级(本文升到2.6.4)。
本案例是Provider提供一个根据用户id查询用户信息的服务。首先创建实体类User:

public class User {
    private Integer id;
    private String name;
    private Integer age;
    }

在创建一个UserService接口,提供一个根据id查询用户的方法,消费者远程调用此接口:

public interface UserService {
    /**
     * provider提供的服务  消费者远程调用此接口
     * @param id
     * @return
     */
    User getUserById(Integer id);
}

实现此接口,重写方法,模拟数据:

public class UserServiceImpl implements UserService {
    @Override
    public User getUserById(Integer id) {
        User user=new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(18);
        return user;
    }
}

以上的步骤都是被写烂了的,关键在一在Spring的配置文件中配置Dubbo:dubbo-provider.xml
注意: dubbo的包有两个,引入Apache的:dubbo.apache.org
步骤:

  • 声明Provider:dubbo:application
  • 协议Protocol:dubbo:protocol
  • 暴露服务:dubbo:service
<?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.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--服务提供者声明名称:必须保证服务名称的唯一性,它的名称是dubbo内部使用的唯一标识-->
    <dubbo:application name="provider"/>

    <!--访问服务协议的名称和端口号,dubbo官方推荐使用的是dubbo协议,端口号默认为20880-->
    <!--
    name:指定协议的名称
    port:指定协议的端口号,默认20880
    -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!--暴露服务的接口  dubbo:service
    interface:暴露服务接口的全限定类名
    ref:是这个接口的实现类在Spring容器中的标识,即id
    register:由于直连方式不使用注册中心,所以要设置register的值为  N/A
     -->
    <dubbo:service interface="com.zhouqun.service.UserService" ref="userService" registry="N/A"/>
    <!--将服务接口的实现类注入到Spring容器中-->
    <bean id="userService" class="com.zhouqun.service.impl.UserServiceImpl"/>
</beans>

最后在web.xml中配置监听器:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:dubbo-provider.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

Consumer需要知道Provider提供了哪些接口,以及接口中有哪些方法,所以需要把Provider的Model打成jar包放到本地仓库。(打包快捷键:双击ctrl)去Provider模块的pom.xml中将

<packaging>war</packaging>

注释掉。打包完成后去掉注释。
注意: 打包时若双击ctrl无效,则用maven的Lifecycle的install工具打包,打成的jar包会在设置的本地仓库中。

服务消费者步骤:

  • 创建一个maven web工程,服务的消费者Consumer
  • 配置pom.xml,引入依赖(Spring,Dubbo,Provider)
  • 设置Dubbo的核心配置文件
  • 编写Controller
  • 配置中央调度器(DispatcherServlet)

在Consumer的pom.xml中引入依赖:

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--Spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <!--dubbo依赖-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.2</version>
    </dependency>
    <!--provider依赖-->
    <dependency>
      <groupId>com.zhouqun</groupId>
      <artifactId>Provider</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

此处的Dubbo版本要与Provider一致,报错之后Provider的版本升级至2.6.4,这里也要升级。

配置核心文件:

<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="consumer"/>

    <!--引用远程服务接口-->
    <!--
       id:Provider实现类注入时的id
       interface:调用远程接口的全限定类名
       url:访问服务器接口的地址(provider中设置的protocol的协议名和端口号)
       register:不使用注册中心,值为N/A
       -->
    <dubbo:reference
            id="userService"
            interface="com.zhouqun.service.UserService"
            url="dubbo://localhost:20880"
            registry="N/A"/>
    <!--<dubbo:registry address="N/A"/>-->
</beans>

因为要编写Controller,所以要再配置一个Spring的配置文件(spring-context)来扫组件,开启注解驱动,如果要走视图的话还要配置视图解析器:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描组件-->
    <context:component-scan base-package="com.zhouqun.controller"/>

    <!--开启注解驱动-->
    <mvc:annotation-driven/>
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

再com.zhouqun.controller包下创建一个UserController,调用Provider中的UserService接口进行用户查询:

import com.zhouqun.pojo.User;
import com.zhouqun.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @author 周区区
 * @version 1.0
 * @date 2021/7/10 14:13
 */
@Controller
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping(value = "/user/{id}")
    public String UserDetail(@PathVariable("id") Integer id, Model model){
        User user = userService.getUserById(id);
        model.addAttribute("user",user);
        return "userdetail";
    }
}

然后在web.xml中配置中央调度器DispatcherServlet:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">

  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:dubbo-consumer.xml,classpath:spring-context.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

因为UserController返回了一个视图:userdetail,所以要创建一个userdetail.jsp,用来呈现用户信息。

<%--
  Created by IntelliJ IDEA.
  User: 周群
  Date: 2021/7/10
  Time: 14:49
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户详情</title>
</head>
<body>
<h1>用户详情</h1>
<div>用户名称:${user.name}</div>
<div>用户年纪:${user.age}</div>
</body>
</html>

然后配置Tomcat,注意,Provider的端口号和Consumer的端口号不能一样,否则会端口号被占用。
在这里插入图片描述
在这里插入图片描述
注意,这里要先启动provider,在启动consumer。

启动之后会报错:

 java.lang.IllegalStateException: Serialized class com.zhouqun.pojo.User must implement java.io.Serializable

因为数据在网络中传输需要进行序列化,所以要使User实体类实现Serializable接口。再次运行:
在这里插入图片描述

4.Dubbo常用标签

可以分为三大类:

  1. 公共标签
  2. 服务提供者标签
  3. 服务消费者标签

4.1公共标签

配置应用信息:名称最好是唯一值,用来给Dubbo框架内部使用

 <dubbo:application name="服务的名称"/>

配置注册中心

<dubbo:registry address="ip:port" protocol="协议名"/>

4.2服务提供者标签

配置访问服务提供者的协议信息:协议名和端口号

<dubbo:protocol name="dubbo" port="20880"/>

暴露配置的服务:

<dubbo:service interface="服务接口的全限定类名" ref="接口的实现类在Spring容器中的标识,即id"/>

4.3服务消费者标签

配置服务消费者引用的远程服务:

<dubbo:reference id="服务实现类注入时的id,与上面的ref一致" interface="服务的全限定类名"/>

这么一看,dubbo:service和dubbo:reference的内容其实差不多。

5.常用项目配置

5.1关闭检查check

dubbo默认会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止spring初始化完成,以便上线时能及早发现问题。默认“check=true”,设置值为false关闭检查。
例如:测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
例1:关闭某个服务的启动时检查:

<dubbo:reference interface="com.zhouqun.UserService" check="false"/>

例2:关闭注册中心启动时检查:

默认启动时注册中心存在并运行,不启动报错
<dubbo:registry check="false"/>

5.2请求重试retries

远程服务调用重试次数,不包括第一次调用,默认是2次,加上第一次一共是3次。

<dubbo:reference retries="5"/>

6.注册中心Zookeeper

Zookeeper官方文档

6.1为什么使用注册中心

对于服务提供方,它需要发布服务,而且由于系统的复杂性,服务的数量、类型页不断膨胀。对于服务消费方,它最关心如何获取到它需要的服务,而面对复杂的系统,需要管理大量的服务调用。
而且,服务的提供方也有可能是服务的消费方,充当两种角色。通过将服务统一管理起来。可以有效的优化内部应用对服务发布/使用的流程和管理。服务注册中心可以通过特定的协议来完成服务对外的统一。Dubbo提供的注册中心由以下几种类型:

  1. Multicast注册中心:组播方式
  2. Redis注册中心:使用Redis作为注册中心
  3. Simple注册中心:就是一个dubbo服务。作为注册中心,提供查找服务的功能。
  4. Zookeeper注册中心:使用Zookeeper作为注册中心。

推荐使用Zookeeper,这是Apache Hadoop的子项目,是一个树形的目录服务,支持变更推送,适合作为dubbo服务的注册中心,工业强度较高,可用于生产环境。
Zookeeper就像windows的资源管理器,包含了所有的文件,服务提供者和服务消费者都在注册中心登记,服务消费者使用的访问地址不用写死。而且注册中心使用心跳机制更新服务提供者的状态。不能使用的服务提供者会自动从注册中心删除,服务提供者不会调用不能使用的服务。

6.2注册中心是什么

Zookeeper是一个高性能、分布式、开源的分布式应用程序协调服务。简称zk,翻译为动物管理员。可以理解为windows中的资源管理器或者注册表。Zookeeper是一个树形结构,这种树形结构和标准文件系统类似。Zookeeper树中的每个节点被称为Znode,和文件系统的树目录一样,Zookeeper中的每个节点可以拥有子节点,每个节点表示一个唯一服务资源。Zookeeper运行需要java环境。
在这里插入图片描述

6.3Zookeeper在windows上的安装

Windows安装Zookeeper
Zookeeper安装包下载地址:Zookeeper3.6.3
将下载的压缩包解压,bin文件夹里面存放了可执行文件:zkServer.cmd,用来启动Zookeeper。
在这里插入图片描述
然后打开conf文件夹,里面有一个Zookeeper的配置文件:zoo_sample.cfg,这是Zookeeper配置文件的样例文件,不是真实的配置文件,我们需要把这个文件拷贝一份并改名zoo.cfg。
在这里插入图片描述
在zoo.cfg中修改文件保存位置,一般在Zookeeper的安装目录下新建一个data文件夹,拷贝这个路径,把zoo.cfg的文件路径修改成这个。

# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes. 存放Zookeeper接收的文件 不要使用临时目录
dataDir=D:/Apache/Zookeeper/apache-zookeeper-3.6.3/data

接下来启动Zookeeper,去bin文件夹下双击zkServer.cmd。
出现DOS界面闪退,由于看不到报错原因,先去修改zkServer.cmd,将zkServer.cmd 末尾的代码中 :

call %JAVA% --> java

​ 想要查看报错异常,添加 pause 即可
在这里插入图片描述
保存文件再次双击zkServer.cmd,可以看到报错信息:
在这里插入图片描述
包下错了,gg。
zookeeper 从 3.5 版本以后,命名就发生了改变,如果是 apache-zookeeper-3.5.5.tar.gz 这般命名的,都是未编译的,而 apache-zookeeper-3.5.5-bin.tar.gz 这般命名的,才是已编译的包。所以,重新下包,再来一遍。
新的下载地址:Zookeeper3.6.3
重新配置zoo.cfg,双击zkServer.cmd,成功运行。

6.4Linux环境下安装Zookeeper

linux环境下安装Zookeeper:安装视频

7.Dubbo项目使用Zookeeper

7.1新建工程

新建一个普通maven项目:zk-Interface,用来存放实体bean和业务接口。
新建一个maven web项目:zk-Provider,作为服务提供者。
新建一个maven web项目:zk-Consumer,作为服务消费者。

7.2zk-Interface

在这个Model下面创建com.dubbo.pojo包放实体类,实体类一定要序列化。com.dubbo.service包放业务接口。

public class User implements Serializable {
    private Integer id;
    private String name;
    private String sex;
    }
public interface UserService {
    /**
     * 根据用户id查询用户
     * @param id
     * @return
     */
    User getUserById(Integer id);
}

业务接口需要在Provider中实现。

7.3zk-Provider

首先导入依赖,spring、dubbo,zookeeper,虽然Interface已经暴露的接口,但是provider也需要暴露了什么接口,所以还需要导入zk-Interface的依赖。

 <!--Spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <!--dubbo依赖-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.4</version>
    </dependency>
     <!--zookeeper依赖-->
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-framework</artifactId>
      <version>4.1.0</version>
    </dependency>
    <!--zk-Interface依赖-->
    <dependency>
      <groupId>com.zhouqun</groupId>
      <artifactId>zk-Interface</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>

然后新建一个com.dubbo.servide.impl包,实现Provider的接口。

public class UserServiceImpl implements UserService{
    @Override
    public User getUserById(Integer id) {
        User user=new User();
        user.setId(id);
        user.setName("张三");
        user.setSex("男");
        return user;
    }
}

然后开始配置Dubbo的核心配置文件: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.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明dubbo服务提供者的名称,保证唯一性-->
    <dubbo:application name="zk-Provider"/>
    <!--声明协议和端口号,不管是不是直连都需要去声明-->
    <dubbo:protocol name="dubbo" port="20880"/>
    <!--指定注册中心地址和端口号-->
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <!--暴露服务接口-->
    <dubbo:service interface="com.dubbo.service.UserService" ref="userService"/>
    <!--加载接口实现类-->
    <bean id="userService" class="com.dubbo.service.impl.UserServiceImpl"/>
</beans>

可见配置文件比点对点直连多了个 dubbo:registry标签声明注册中心。
接下来去web.xml中配置监听器。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:provider.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

然后配置tomcat。端口号(8081,1098)

7.4zk-Consumer

首先添加依赖,与zk-Provider一致。这里就不贴了。
编写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.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明dubbo消费者名称,保证唯一性-->
    <dubbo:application name="zk-Consumer"/>
    <!--指定注册中心-->
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <!--引用远程服务接口-->
    <dubbo:reference interface="com.dubbo.service.UserService" id="userService"/>
</beans>

因为要编写Controller,所以要再配置一个Spring的配置文件(springContext)来扫组件,开启注解驱动,如果要走视图的话还要配置视图解析器:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描组件-->
    <context:component-scan base-package="com.dubbo.controller"/>

    <!--开启注解驱动-->
    <mvc:annotation-driven/>
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

然后在web.xml中配置DispatcherServlet:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">

  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:consumer.xml,classpath:springContext.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

然后编写UserController:

@Controller
public class UserController {
    @Autowired
    UserService userService;

    @RequestMapping(value = "/user/{id}")
    public String userDetail(@PathVariable("id") Integer id, Model model){
        User user = userService.getUserById(id);
        model.addAttribute("user",user);
        return "userdetail";
    }
}

最后编写一个userdetail.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户详情</title>
</head>
<body>
<div>用户名称:${user.name}</div>
<div>用户年纪:${user.age}</div>
</body>
</html>

然后配置tomcat:(8080,1099)

7.5启动项目

首先启动注册中心,双击zkService.cmd
然后启动Provider
最后启动Consumer

8.版本号version的使用

当服务进行扩展时要更新版本号,再次发布,但不能干掉以前的老版本(等同软件更新,有人不愿意更新,就会继续使用老版本,不能强制所有人使用新版本),此时就涉及到版本号version的使用。
服务提供者创建:
依旧沿用上一节的zk-Interface,然后新建服务提供者和服务消费者。Provider的依赖与上一节zk-Provider的依赖一样。
然后新建com.dubbo.service.impl包,新建服务接口UserService的两个实现类:UserServiceImpl1、UserServiceImpl2。

public class UserServiceImpl1 implements UserService {
    @Override
    public User getUserById(Integer id) {
        User user = new User();
        user.setName("老藏"+"01版本");
        user.setSex("男");
        return user;
    }
}
public class UserServiceImpl2 implements UserService {
    @Override
    public User getUserById(Integer id) {
        User user = new User();
        user.setName("老李"+"版本02");
        user.setSex("女");
        return user;
    }
}

编写dubbo配置文件:
不管一个接口有多少个实现类,只要服务提供者指定了版本号,那么消费者引用远程接口服务的时候就必须指定版本号。

<?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.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明dubbo服务提供者的名称,保证唯一性-->
    <dubbo:application name="multi-Provider"/>
    <!--声明协议和端口号-->
    <dubbo:protocol name="dubbo" port="20880"/>
    <!--使用注册中心-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <!--暴露服务 通过版本号来识别调用哪个服务-->
    <dubbo:service interface="com.dubbo.service.UserService" ref="UserService1" version="1.0.0"/>
    <dubbo:service interface="com.dubbo.service.UserService" ref="UserService2" version="2.0.0"/>

    <!--声明实现类-->
    <bean id="userService1" class="com.dubbo.service.impl.UserServiceImpl1"/>
    <bean id="userService2" class="com.dubbo.service.impl.UserServiceImpl2"/>
</beans>

然后在web.xml中配置监听器:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:multi-provider.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

服务消费者创建:
消费者的依赖跟multi-Provider一样,然后创建dubbo项目的配置文件,multi-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.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明服务消费者的名称:保证唯一性-->
    <dubbo:application name="multi-Consumer"/>
    <!--使用注册中心-->
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <!--声明引用的远程服务 一定要指定版本号-->
    <dubbo:reference id="userService1" interface="com.dubbo.service.UserService" version="1.0.0"/>
    <dubbo:reference id="userService2" interface="com.dubbo.service.UserService" version="2.0.0"/>
</beans>

然后创建一个spring配置文件:springContext.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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描组件-->
    <context:component-scan base-package="com.dubbo.controller"/>

    <!--开启注解驱动-->
    <mvc:annotation-driven/>
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

然后在web.xml中配置中央调度器:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">

  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:multi-Consumer.xml,classpath:springContext.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

然后编写Controller:

@Controller
public class UserController {
//类型一致时通过byName扫描,所以这里变量名要和配置文件中的id一样。
    @Autowired
    UserService userService1;
    @Autowired
    UserService userService2;

    @RequestMapping(value = "/user/{id}")
    public String getUserById(@PathVariable("id") Integer id,Model model){
        User user1 = userService1.getUserById(id);
        User user2 = userService2.getUserById(id);
        model.addAttribute("user1",user1);
        model.addAttribute("user2",user2);
        return "userdetail";
    }
}

配tomcat,启动注册中心,启动提供者,启动消费者。

9.监控中心

9.1什么是监控中心

Dubbo的使用,其实只需要注册中心、服务提供者、服务消费者。但是并不能看到有哪些消费者和提供者,为了更好的调试、发现问题、解决问题,因此引入了dubbo-admin。通过dubbo-admin可以对消费者和提供者进行管理。可以在dubbo应用部署做动态的调整,服务的管理。
dubbo-admin下载地址
git失败,上链接dubbo监控中心配置

10.负载均衡

集群: 集群是一种计算机系统,是一种服务结构。把一组多个计算机,包括硬件和软件组织在一个网络中。互相连接起来共同完成某个工作。对用户来说使用的是一个计算机,集群对用户是透明的。
负载均衡: 负载均衡是以集群为前提的,意思是将负载进行平衡、分摊到多个操作单元上进行执行。
对于网络而言,并不是一开始就需要负载均衡,当网络访问量不断增长,单个处理单元无法满足负载需求时,网络应用流量将要出现瓶颈时,负载均衡才会起作用。一般通过一个或多个前端负载均衡器,将工作负载分发到后端的一组服务器上,从而达到整个系统的高性能和高可用性。
负载均衡有两方面的含义:首先,单个重负载的工作分配到多个服务器做并行处理,每个服务器处理结束后,将结果汇总,返回给客户,系统处理能力得到大幅度提高,这是集群技术带来的优势。其次,大量的并发访问或数据流量分担到多台服务器分别处理,减少用户等待响应的时间。每个访问分配给不同的服务器处理。

10.1负载策略

Random LoadBalance
随机,按照权重设置随机概率。在一个截面上碰撞的概率高,但是调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
轮询,按照公约后的权重设置轮询比例。存在慢的提供者累积请求问题:加入第二台服务器很慢,但没挂,当请求调到第二台服务器时就卡在那里,久而久之,所有的请求都卡在调第二台服务器上。(适用于服务器性能差不多的情况)
Least Active LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少的请求,因为慢的提供者调用前后计数差会越大。(适用于服务器性能差异较大的情况)
ConsistentHash LoadBalance
一致性Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂掉了,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者,不会引起剧烈变动。(优势,发生故障可平稳过渡)缺省只对第一个参数hash,如果要修改,请配置:

<dubbo:parameter key="hash.arguments" value="0,1"/>

10.2配置方式

<dubbo:service interface="..." loadbalance="roundrobin"/>

<dubbo:reference interface="..." loadbalance="roundrobin"/>

随机:loadbalance=“random”
轮询:loadbalance=“roundrobin”
最少活跃:loadbalance=“leastactive”
一致性Hash:loadbalance="consistenthash "

10.3代码实现

要用到linux,上链接吧负载均衡代码实现

彩蛋:关于翻译的插件(IDEA2017)

在这里插入图片描述
点击下载,然后重启IDEA,选中单词或语句,按ctrl+shift+y即可翻译。
关于快速切换的快捷键:下图标红的地方首字母都有个下划线,想快速切换时,按alt+【下标】即可切换,例如,想打开Project,只需要按【alt+1】
在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值