dubbo

Dubbo是分布式服务框架,是阿里巴巴的开源项目,现交给apache进行维护,Dubbo致力于提高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案

1. 基本概念

RPCRemote Procedure Call】是指远程过程调用,是一种进程间通信方式

  • 在客户端将对象进行序列化
  • 底层通信框架使用netty(基于tcp协议的socket),将序列化的对象发给服务方提供方
  • 服务提供方通过socket得到数据文件之后,进行反序列化,获得要操作的对象
  • 对象数据操作完毕,将新的对象序列化,再通过服务提供方的socket返回给客户端
  • 客户端获得序列化数据,再反序列化,得到最新的数据对象,至此,完成一次请求

节点角色

节点 角色说明
Provider 服务的提供方
Consumer 服务的消费方
Registry 服务注册与发现的注册中心
Monitor 监控服务的统计中心
Container 服务运行容器

调用关系

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

     

2. dubbo入门

  • 注册中心:zookeeper作为注册中心
    • 注册中心负责服务地址的注册与查找,相当于目录服务
    • 服务提供者和消费者只在启动时与注册中心交互,注册中不转发请求,压力较小
    • Zookeeperapache hadoop的子项目,是一个树形的目录服务,支持变更推送,适合作为dubbo的服务注册中心,工业强度较高,可用于生产环境
  • 服务提供方
    • pom.xml
    <?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">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>dubbo-quick</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <packaging>war</packaging>
        <properties>
            <spring.version>5.0.6.RELEASE</spring.version>
        </properties>
        <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.7</version>
        </dependency>
        <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
        </dependency>
            <dependency>
                <groupId>com.github.sgroschupf</groupId>
                <artifactId>zkclient</artifactId>
                <version>0.1</version>
            </dependency>
            <dependency>
                <groupId>javassist</groupId>
                <artifactId>javassist</artifactId>
                <version>3.11.0.GA</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven </groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <configuration>
                        <port>8001</port>
                        <path>/</path>
                    </configuration>
                    <executions>
                        <execution>
                            <!-- 打包完成后,运行服务 -->
                            <phase>package</phase>
                            <goals>
                                <goal>run</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    • 服务方服务
package com.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.service.HelloService;

@Service
public class HelloServiceImp implements HelloService {
    public String sayHello(String name) {
        return "hello "+name;
    }
}
    • 服务方spring配置
<?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">
    <!--1.服务提供方在zookeeper中的“别名”-->
    <dubbo:application name="dubbo-server"/>
    <!--2.注册中心的地址-->
    <dubbo:registry address="zookeeper://192.168.80.128:2181"/>
    <!--3.扫描类(将什么包下的类作为服务提供类)-->
    <dubbo:annotation package="com.service.impl"/>
</beans>
    • 服务方web配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         id="WebApp_ID" version="3.1">
    <listener>
<!--启动上下文监听-->
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-server.xml</param-value>
    </context-param>
</web-app>
  • 消费方
    • pom.xml,与服务方一致,修改Tomcat端口8002
    • 消费方controller
      package com.controller;
      
      import com.alibaba.dubbo.config.annotation.Reference;
      import com.com.service.HelloService;
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.ResponseBody;
      
      @Controller
      public class HelloController {
      
          @Reference
          private HelloService helloService;
      
          @RequestMapping("/hello")
          @ResponseBody
          public String hello(String name){
              helloService.sayHello(name);
              return "ok";
          }
      }
    • 消费方接口
      package com.com.service;
      
      public interface HelloService {
          public String sayHello(String name);
      }
    • 消费方springMVC
      <?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的应用名称,通常使用项目名 -->
          <dubbo:application name="dubbo-consumer" />
          <!--配置Dubbo的注册中心地址 -->
          <dubbo:registry address="zookeeper://192.168.80.128:2181" />
          <!--配置Dubbo扫描类,将这个类作为服务进行发布 -->
          <dubbo:annotation package="com.controller" />
      </beans>
    • 消费方web
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         id="WebApp_ID" version="3.1">
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/springMVC.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
  •  监控中心
    • 服务管理端解压 dubbo-admin-master.zip 修改配置文件
    • 返回到项目根目录,使用maven打包:mvn clean package
    • dos下运行target目录中的jar文件:java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
    • 浏览器输入:http://localhost:7001/ ,第一次访问时,需要登录,帐号密码都是root
  • 监控统计中心,记录服务被调用多少次
    • 解压dubbo-monitor-simple-2.5.3.zip, 修改dubbo-monitor-simple-2.5.3\conf\dubbo.properties
    • 双击运行dubbo-monitor-simple-2.5.3\bin\start.bat

    • 分别修改dubbo-serverdubbo-consumerspring.xml,加入下面标签

<!-- 让监控 去注册中心 自动找服务 -->
<dubbo:monitor protocol="registry"/>

3. 配置说明

  • 启动时检查,默认为true,启动时会在注册中心检查依赖的服务是否可用,不可用时会抛出异常,在消费方编写初始化容器的main方法启动
    <!--默认是true:抛异常;false:不抛异常-->
    <dubbo:consumer check="false" />
  • 超时时间:由于网络或服务端不可靠,会导致调用过程中出现不确定的阻塞状态(超时),为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间
    <!--设置超时时间为2秒,默认为1秒-->
    <dubbo:provider timeout="2000"/
  • 重试次数:当出现失败,自动切换并重试其它服务器,dubbo重试的缺省值是2次,我们可以自行设置,总共尝试n+1次
<!-- 消费方连接第1次不算,再来重试3次,总共重试4次 -->
<dubbo:provider timeout="2000" retries="3"/>
    • 并不是所有的方法都适合设置重试次数
      • 幂等方法:适合(当参数一样,无论执行多少次,结果是一样的,例如:查询,修改)
      • 非幂等方法:不适合(当参数一样,执行结果不一样,例如:删除,添加)
<!--单独设置某个方法-->
<dubbo:reference interface="service.HelloService" id="helloService">
<dubbo:method name="sayHello" retries="3"/>
<dubbo:method name="sayNo" retries="0"/> <!-- 不重试 -->
</dubbo:reference>
  • 多版本:一个接口多个版本的实现类可以用版本号规定使用哪个版本,控制层要改为自动注入,因为@Reference注解和 <dubbo:reference>在这里冲突,当消费者的版本修改为 version="*",那么就会随机调用服务提供者的版本
    <dubbo:service interface="service.HelloService"
    class="service.impl.HelloServiceImpl01" version="1.0.0"/>
    <dubbo:service interface="service.HelloService"
    class="service.impl.HelloServiceImpl02" version="2.0.0"/>
    <dubbo:reference interface="service.HelloService" id="helloService"
    version="2.0.0">
    <dubbo:method name="sayHello" retries="3"/>
    <dubbo:method name="sayNo" retries="0"/>
    </dubbo:reference>
  • 本地存根:先在消费者处理一些业务逻辑,再调用提供者的过程,就是本地存根” ,必须使用构造方法的方式注入
    public class HelloServiceStub implements HelloService {
    private HelloService helloService;
    // 注入HelloService
    public HelloServiceStub(HelloService helloService) {
    this.helloService = helloService;
    } p
    ublic String sayHello(String name) {
    System.out.println("本地存根数据验证。。。");
    if(!StringUtils.isEmpty(name)){
    return helloService.sayHello(name);
    } r
    eturn "i am sorry!";
    } p
    ublic String sayNo() {
    return helloService.sayNo();
    }
    }
    <dubbo:reference interface="service.HelloService" id="helloService"
    version="1.0.0" stub="service.impl.HelloServiceStub">
    <dubbo:method name="sayHello" retries="3"/>
    <dubbo:method name="sayNo" retries="0"/>
    </dubbo:reference>

4.负载均衡策略

dubbo一共提供4种策略,缺省为 random 随机分配调用,可以通过服务管理端进行权重分配

 

 

 5.高可用

  • zookeeper注册中心宕机,可以消费dubbo暴露的服务 ,监控中心宕掉不影响使用,只是丢失部分采样数据数据库宕掉后
  • 注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复\
  • 关闭zookeeper消费者仍然可以正常消费

6. 服务降级

根据实际的情况和流量,对一些服务有策略的停止或换种简单的方式处理,从而释放服务器的资源来保证核心业务的正常运行

  • 实现方式:管理控制台配置服务降级
    • 屏蔽mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null ,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响
    • 容错mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null ,不抛异常。用来容忍不重要服务不稳定时对调用方的影响

 

posted @ 2021-07-29 14:20  forever_fate  阅读(50)  评论(0)    收藏  举报