Dubbo

Dubbo

官网链接

1. 背景

1.1架构演变图

在这里插入图片描述

  • 单体架构

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

  • 垂直应用架构

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

  • 分布式服务架构

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

  • 流动计算架构

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

2. RPC

2. 1 概念

Remote Procedure Call远程过程调用,是一种不同进程间的通信方式,它允许程序调用另一个地址空间的过程或函数,不用开发人员显示的编写代码实现调用的细节(底层基本都是使用Socket).

当A服务器想远程调用B服务器时,需要借助远程调用插件通过url访问B服务器.当A需要携带数据给B或B返回数据给A时,这些数据都需要进行序列化才能进行传输,然后进行反序列化进行接收.
远程调用插件底层是使用Socket技术解决了通信的问题,序列化解决了信息传输的问题.

在这里插入图片描述

3. Dubbo的简略架构图及调用关系

在这里插入图片描述

  • 节点 角色说明

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

  • 调用关系

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

4. 搭建Dubbo环境

4.1 搭建Zookeeper环境

官网:Zookeeper

Zookeeper是一个分布式开源框架,交给了Apache进行管理,可以实现服务地址分配
它能提供配置维护,域名维护,分布式同步,组服务等.
他的目标是将封装好的复杂易出错的关键服务,将简单易用的接口和性能高效,功能稳定的系统提供给>用户
它包含一个简单的 原语集, 提供Java和

  • 下载zookeeper安装包
  • 解压安装包

可以选择在windows,Linux安装,在此以windows为例
在这里插入图片描述

  • 进入conf目录复制粘贴zoo_sample.cfg,修改文件名为zoo.cfg
#Zookeeper服务器之间或者客户端和服务端维持心跳的时间间隔值
#每隔2秒都会发送一个心跳
#默认情况下最小的会话超时时间为tickTime的两倍
tickTime=2000
#同时初始化的最大数量
initLimit=10
#最大同时连接数
syncLimit=5
#存放临时数据和日志的目录
dataDir=D:/zookeeper/zookeeper-3.4.13/tmp/
dataLogDir=D:/zookeeper/zookeeper-3.4.13/logs
#客户端连接的端口号
clientPort=2181
  • 在C:\Windows\System32\drivers\etc\hosts文件放开
    在这里插入图片描述

  • 在bin目录双击zkServer.cmd开启服务端,zkCli.cmd(退出请按Ctrl+C 输入Y)

在客户端输入 ls / 出现zookeeper就代表成功

4.2 搭建dubbo环境

  • 在github下载incubator-dubbo-ops-master,解压
  • 查看incubator-dubbo-ops-master\dubbo-admin\src\main\resources\application.properties
    在这里插入图片描述
  • 在incubator-dubbo-ops-master\dubbo-admin下cmd执行下面命令打包

mvn clean package -Dmaven.test.skip=true
在dubbo-admin目录下就会有一个target目录

  • 启动dubbo管理平台

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
浏览器输入localhost:7001
输入用户名和密码root

4.3 创建服务提供者和服务器消费者

根据用户的id查询用户所含有的角色信息
用户-----消费者
角色-----提供者

4.3.1创建common模块

存放服务提供者和服务消费者都需要的接口和javaBean
RoleServer和UserService接口,Role都可以放在该模块

4.3.2 服务提供者
  • 依赖
    在这里,服务提供者和消费者所需要的依赖是一致的
<dependencies>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.5</version>
      <exclusions>
        <exclusion>
          <!--我的解析不了根据依赖传递下载的spring-context,所以我不让它下载-->
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <!--引入zookeeper的客户端-->
    <dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.4.6</version>
    </dependency>
    <dependency>
      <groupId>com.101tec</groupId>
      <artifactId>zkclient</artifactId>
      <version>0.2</version>
    </dependency>

    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-framework</artifactId>
      <version>4.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-recipes</artifactId>
      <version>4.2.0</version>
    </dependency>
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.0.35.Final</version>
    </dependency>

    <!--依赖common模块-->
    <dependency>
      <groupId>comzy</groupId>
      <artifactId>common</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

  • 配置文件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="provider"  />

    <!-- 服务注册与发现:服务提供方把应用注册到zookeeper注册中心 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />

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

    <!--指定服务器提供者暴露的接口-->
    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.zy.service.RoleService" ref="demoService" />
    <!-- 和本地bean一样实现服务 -->
    <bean id="demoService" class="com.zy.service.impl.RoleServiceImpl" />
    <!--也可以使用阿里巴巴的@Service注解,需要开启组件扫描
        <context:component-scan base-package="com.zy.service"/>
    -->
</beans>

配置启动类

        //Spring容器的构建:加载配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:provider.xml");
        //启动Spring容器
        context.start();
        //从输入流中读取字节 --- 阻塞
        System.in.read();
  • 创建service的接口和实现类

RoleService接口放在common模块,自定义JavaBean–Role
RoleServiceImpl如下

@Service
public class RoleServiceImpl implements RoleService {

    @Override
    public List<Role> queryRoleByUserId(Integer id) {
        //假设在数据库中查询到了三个角色的信息
        ArrayList<Role> roles = new ArrayList<>();
        roles.add(new Role(1,"CEO","高级打工者"));
        roles.add(new Role(2,"CTO","高级代码搬运工"));
        roles.add(new Role(3,"Programmer","cv工程师"));
        return roles;
    }
}
4.1.3服务消费者
  • consumer.xml
    <context:component-scan base-package="com.zy.service"/>
    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <dubbo:application name="consumer"  />

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

    <!-- 生成远程服务代理,可以和本地bean一样使用roleService -->
    <dubbo:reference id="roleService" interface="com.zy.service.RoleService" />
  • UserServiceImpl
    它的接口放在common模块
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private RoleService roleService;

    @Override
    public List<Role> roles(Integer userId) {
        return roleService.queryRoleByUserId(userId);
    }
}
  • 启动类
    public static void main(String[] args) throws IOException {
        //Spring容器的构建:加载配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml");
        //启动Spring容器
        context.start();
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        List<Role> roles = userService.roles(1);
        for (Role role : roles) {
            System.out.println(role);
        }

        //从输入流中读取字节 --- 阻塞
        System.in.read();
    }
4.1.4 测试
  • 开启zookeeper的服务端和客户端
  • 开启dubbo
  • 启动消费者和提供者
  • 浏览器输入http://localhost:7001/

因为我是安装到本地的并没有安装到Linux上,所以在配置文件里指定zookeeper的地址时可以使用127.0.0.1

在这里插入图片描述

5. 监控中心

打包dubbo-monitor-simple
mvn package -Dmaven.test.skip=true
到target文件夹解压gz进入解压文件夹的.bin文件夹双击start.bat
在服务提供者和消费者的配置文件配置监控中心
<dubbo:monitor protocol=“registry”/>

监控中心的配置文件

dubbo.container=log4j,spring,registry,jetty-monitor
dubbo.application.name=simple-monitor
dubbo.application.owner=dubbo
dubbo.registry.address=zookeeper://127.0.0.1:2181
#其他服务与监控中心通信的端口号
dubbo.protocol.port=7070
#监控中心访问web页面的端口号
dubbo.jetty.port=8080
dubbo.jetty.directory=${user.home}/monitor
dubbo.charts.directory=${user.home}/monitor/charts
dubbo.statistics.directory=${user.home}/monitor/statistics
dubbo.log4j.file=logs/dubbo-monitor-simple.log
dubbo.log4j.level=WARN

6. dubbo的注解版

使用<dubbo:annotation package=“com.zy.service”/>开启dubbo的组件扫描
属性注入使用注解@Reference,service层使用注解@Service,它们都是用alibaba包下的,不是spring

7. hystrix容错

使用在服务消费方,提供方不需要
在springMVC环境下使用的

  • 依赖
    <dependency>
      <groupId>com.netflix.hystrix</groupId>
      <artifactId>hystrix-core</artifactId>
      <version>1.5.12</version>
    </dependency>
    <dependency>
      <groupId>com.netflix.hystrix</groupId>
      <artifactId>hystrix-javanica</artifactId>
      <version>1.5.12</version>
    </dependency>
        <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
  • spring.xml
    <!--组件扫描-->
    <context:component-scan base-package="com.zy.controller"/>
    <!--处理器适配器,处理器映射器-->
    <mvc:annotation-driven />
    <!--通过切面配置代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <bean class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"/>
  • 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_4_0.xsd"
         version="4.0">
  <!--前端控制器-->
  <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:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>
  <!--监听器-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:consumer.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--设置编码格式-->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encodingUTF-8</param-name>
      <param-value></param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>
</web-app>
  • controller.java
  /**
     *容错
     * 注解@ResponseBody //需要依赖jackson工具
     * @author yxk
     * @param userId
     * @return java.util.List<com.zy.pojo.Role>
     * Date 2021/4/7 11:27
     */
    @RequestMapping("/listRole.action")
    @ResponseBody
    @HystrixCommand(fallbackMethod = "hystrix")
    public List<Role>  listRoleAll(Integer userId) {
        List<Role> roles = roleService.queryRoleByUserId(userId);
        System.out.println(roles);
        return roles;

    }


    public List<Role> hystrix(Integer userId) {
        System.out.println("服务调用失败执行该方法");
        return null;
    }

注意: hystrix方法的参数和返回值需要和listRoleAll方法一致

8. 负载均衡

consumer.xml

负载均衡:loadbalance
random 随机
roundrobin 轮询
eastactive 响应时间最短
onsistenthash 一致性hash

<dubbo:reference id="roleService" interface="com.zy.service.RoleService" check="false" loadbalance="random"/>

proviter.xml
每启动一次修改一次port,模拟服务提供者集群

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

线程模型

dubbo采用的网络通信是netty,netty采用的是NIO
NIO(非阻塞IO),并发高,网络传输快,封装性好
主要使用的环境在高并发
服务提供方 NettyServer 使用两种类型的线程池:IO线程,业务线程

IO线程:
EvenLoopGroop(boss)任务:j接收客户端的请求,并把接受的请求分发给worker处理
EvenLoopGroop(worker)任务
boos+worker加起来被称为"IO线程"
IO线程:主要用来处理网络中产生的网络数据,通过解码(反序列化)和编码(序列化)完成

业务线程:主要处理具体的业务逻辑

dubbo默认采用的机制采用长连接的方式.默认情况下一个consumer和一个provider只会建立一个连接,
在这种情况下,IO线程主要进行解码和编码,处理网络数据,监听具体的数据请求,直接通过channel发布.
业务线程主要处理IO线程处理之后的业务数据

  • NIO( 非阻塞IO模式)
    在这里插入图片描述

更多功能开发请参考官方文档

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值