Title

springBoot整合Dubbo的使用

Zookeeper

ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列、分布式通知/协调等。

建议使用zookeeper3.4.5及以上版本注册中心。

Zookeeper是Apache Hadoop的子项目,强度相对较好,建议生产环境使用该注册中心。

Dubbo未对Zookeeper服务器端做任何侵入修改,只需安装原生的Zookeeper服务器即可,所有注册中心逻辑适配都在调用Zookeeper客户端时完成。

 

Zookeeper配置
1、下载zookeeper

2、然后修conf/zoo.cfg

dataDir=D:\zookeeper-3.3.6\\data

dataLogDir=D:\zookeeper-3.3.6\\log

3、执行zkServer.cmd,启动Zookeeper

 

监控中心

监控中心的主要使用就是查看dubbo提供者和消费者的信息,以及他们的调用情况。


监控中心配置
1、下载dubbo-monitor

2、然后修conf/dubbo.properties

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

dubbo.jetty.port=28080

3、执行start.bat,启动监控中心


监控中心界面
在浏览器输入 http://localhost:8080,就可以进入监控中心

 

构建API模块
项目结构:
springbootdubboapi
springbootdubboclient
springbootdubboservice

 

api模块中就一个接口,然后将api模块打包(maven→Lifecycle→install)双击install

public interface TestServiceApi {
   String sayHello(String name);
}

 

Dubbo服务提供者
Pom.xml添加dubbo依赖

<!-- spring web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!-- 整合dubbo-->
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>

<!-- zookeeper客户端-->
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.11</version>
        </dependency>

<!-- 打包的api路径 -->
        <dependency>
            <groupId>com.test</groupId>
            <artifactId>springbootdubbo_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

 

application.yml配置dubbo注册中心

 

server:
  port: 8081  # 端口号
spring:
  dubbo:    # Dubbo服务提供者配置
    application:
      name: provider  # 服务名称
    registry:
      address: zookeeper://127.0.0.1:2181  # 注册中心地址
    protocol:
      name: dubbo  # dubbo协议
      port: 28081  # dubbo协议端口

 

 

提供服务

@Service //注意是com.alibaba.dubbo.config.annotation.Service包的service
@Component
public class ITestService implements TestServiceApi {

    @Override
    public String sayHello(String s) {
        return "Hello" + s;
    }
}

 

启动服务

注意加上@EnableDubboConfiguration注解

@SpringBootApplication
@ComponentScan(basePackages = "com.Test.*")
@EnableDubboConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

 

监控中心可查看到发布的服务

 

Dubbo服务消费者

Pom.xml添加dubbo依赖

<!-- spring web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!-- 整合dubbo-->
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>

<!-- zookeeper客户端-->
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.11</version>
        </dependency>

<!-- 打包的api路径 -->
        <dependency>
            <groupId>com.test</groupId>
            <artifactId>springbootdubbo_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

 

application.yml配置dubbo注册中心

server:
  port: 8082  # 端口号
spring:
  dubbo:    # Dubbo服务提供者配置
    application:
      name: provider  # 服务名称
    registry:
      address: zookeeper://127.0.0.1:2181  # 注册中心地址
    protocol:
      name: dubbo  # dubbo协议
      port: 28082  # dubbo协议端口

 

消费者调用服务

@RestController
@RequestMapping(value = "/test")
public class DepController {

    @Reference //注意是com.alibaba.dubbo.config.annotation.Reference包的
    private TestServiceApi testServiceApi;

    @RequestMapping(value = "/sayHello")
    public String sayHello() {
        return testServiceApi.sayHello("张三消费者");
    }
}

 

启动消费者

注意加上@EnableDubboConfiguration注解

@SpringBootApplication
@ComponentScan(basePackages = "com.test.*")
@EnableDubboConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

 

监控中心可查看到发布的consumer服务

 

输入网址就能显示内容了

http://localhost:8082/test/sayHello

 

超时时间,重试次数配置

timeout:可以设置duboo调用的超时时间(毫秒为单位)
retries :可以设置重试次数

@Service(timeout = 1000, retries = 3, group = "group1")
@Component

 

服务分组

可以用group属性

示例:

@Service(timeout = 1000, retries = 3, group = "group1")
@Component
public class IEmpService implements EmpServiceApi {

    @Override
    public String sayHello(String s) {
        return "hello" + s;
    }
}


@Service(timeout = 1000, retries = 3, group = "group2")
@Component
public class IEmpService implements EmpServiceApi {


    @Override
    public String sayHello(String s) {
        return "hello" + s;
    }
}


@RestController
@RequestMapping(value = "/test")
public class EmpController {

    @Reference(group = "group1", loadbalance = "roundrobin")
    private TestServiceApi testServiceApi1;

    @Reference(group = "group2", loadbalance = "roundrobin")
    private TestServiceApi testServiceApi2;

    @RequestMapping(value = "/sayHello1")
    public String sayHello() {
        return empServiceApi1.sayHello("消费者1");
    }

    @RequestMapping(value = "/sayHello2")
    public String sayHello() {
        return empServiceApi2.sayHello("消费者2");
    }


}

 

负载均衡算法 

random 随机
leastactive 最小活跃值
consistenthash 一致哈希
roundrobin 轮询

配置:

 

random:权重随机算法,根据权重值进行随机负载。它的算法思想很简单。

假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为 10。

现在把这些权重值平铺在一维坐标值上,[0, 5) 区 间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。

接下来通过 随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个 区间上。

比如数字 3 会落到服务器 A 对应的区间上,此时返回服务器 A 即可。

权重 越大的机器,在坐标轴上对应的区间范围就越大,因此随机数生成器生成的数字就会 有更大的概率落到此区间内。

只要随机数生成器产生的随机数分布性很好,在经过多 次选择后,每个服务器被选中的次数比例接近其权重比例。


leastactive:最少活跃调用数算法,活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求这个是比较科学的负载均衡算法。

每个服务提供者对应一个活跃数 active。初始情况下,所有服务提供者活跃数均为 0。 每收到一个请求,活跃数加 1,完成请求后则将活跃数减 1。

在服务运行一段时间后, 性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服 务提供者能够优先获取到新的服务请求。

 

consistenthash:hash 一致性算法,相同参数的请求总是发到同一提供者 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者, 不会引起剧烈变动。

 

roundrobin:加权轮询算法是指将请求轮流分配给每台服务器。

举个例子,我们有三台服务器 A、B、C。 我们将第一个请求分配给服务器 A,第二个请求分配给服务器 B,第三个请求分配给 服务器 C,第四个请求再次分配给服务器 A。

这个过程就叫做轮询。轮询是一种无状 态负载均衡算法,实现简单,适用于每台服务器性能相近的场景下。

但现实情况下, 我们并不能保证每台服务器性能均相近。

如果我们将等量的请求分配给性能较差的服 务器,这显然是不合理的。

因此,这个时候我们需要对轮询过程进行加权,以调控每 台服务器的负载。经过加权后,每台服务器能够得到的请求数比例,接近或等于他们 的权重比。

比如服务器 A、B、C 权重比为 5:2:1。那么在 8 次请求中,服务器 A 将 收到其中的 5 次请求,服务器 B 会收到其中的 2 次请求,服务器 C 则收到其中的 1次请求。

 

集群容错 

在分布式网络通信中,容错能力是必须要具备的,什么叫容错呢? 从字面意思来看: 容:是容忍, 错:是错误。 就是容忍错误的能力。

我们知道网络通信会有很多不确定因素,比如网络延迟、网络中断、服务异常等,会造成当前这次请求出现失败。当服务通信出现这个问题时,需要采取一定的措施应对。

而 dubbo 中提供了容错机制来优雅处理这种错误,在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。

 

failover:失败自动切换,当出现失败,重试其它服务器。(缺省) 通常用于读操作,但重试会带来更长延迟。 可通过 retries=“2” 来设置重试次数(不含第一次)。
failfast:快速失败,只发起一次调用,失败立即报错。 通常用于非幂等性的写操作,比如新增记录。
failsafe:失败安全,出现异常时,直接忽略。 通常用于写入审计日志等操作。
failback:失败自动恢复,后台记录失败请求,定时重发。 通常用于消息通知操作。

forking:并行调用多个服务器,只要一个成功即返回。 通常用于实时性要求较高的读操作,但需要浪费更多服务资源。 可通过 forks=“2” 来设置最大并行数。
broadcast:广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0 开始支持) 通常用于通知所有提供者更新缓存或日志等本地资源信息。
在实际应用中查询语句容错策略建议使用默认 failover ,而增删改建议使用 failfast 或者使用 failover (retries=”0”) 策略,防止出现数据重复、添加等等其它问题!

建议在设计接口时候把查询接口方法单独做一个接口提供查询。

 

服务降级 

当某个非关键服务出现错误时,可以通过降级功能来临时屏蔽这个服务。降级可以有几个层面的分类: 自动降级和人工降级; 按照功能可以分为:读服务降级和写服务降级
1. 对一些非核心服务进行人工降级,在大促之前通过降级开关关闭哪些推荐内容、评 价等对主流程没有影响的功能。
2. 故障降级,比如调用的远程服务挂了,网络故障、或者 RPC 服务返回异常。

那么 可以直接降级,降级的方案比如设置默认值、采用兜底数据(系统推荐的行为广告 挂了,可以提前准备静态页面做返回)等等 。
3. 限流降级,在秒杀这种流量比较集中并且流量特别大的情况下,因为突发访问量特 别大可能会导致系统支撑不了。

这个时候可以采用限流来限制访问量。当达到阀值 时,后续的请求被降级,比如进入排队页面,比如跳转到错误页(活动太火爆,稍 后重试等)

 

Dubbo中如何实现服务降级?
Dubbo中提供了一个mock的配置,可以通过 mock来实现当服务提供方出现网络异常或者挂掉以后,客户端不抛出异常,而是通过 Mock数据返回自定义的数据 。

 

客服端调用服务配置参数,增加mock配置,以及修改timeout=500, 表示本次调用的超时时间是0.5秒,

这样可以模拟出失败的场景 需要配置cluster=failfast,否则因为默认是failover导致客户端会发起3次重试,等待的时间比较长。

 

 

服务端代码,只需要加一个休眠时间让客户端调用超时即可。

 

启动时检查 

Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"。

可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。 

 

posted @ 2022-03-31 10:41  guochengcheng  阅读(759)  评论(0)    收藏  举报