Dubbo初识-入门

Apache Dubbo是一个分布式服务框架,于2019年5月,正式称为Apache的顶级项目。前身于2012年开源,但是2014年停止维护,所幸阿里巴巴2017年9月重新对Dubbo启动了维护并长期投入规划。

Apache Dubbo主要实现了多个系统之间的高性能、透明化调用,是一个RPC框架,不过相比普通RPC框架,它还提供了服务治理功能,如服务注册、监控、容错、路由等。

Apache Dubbo提供不仅限于如下功能:

  • 面向接口代理的高性能RPC调用:服务以接口为力度,屏蔽远程调用底层细节;
  • 智能负载均衡:内置多种负载均衡策略,智能感知节点健康状况,减少调用延迟,提升吞吐;
  • 服务自动注册与发现:支持多种注册中心服务,服务实例上下线实时感知;
  • 高度可扩展能力:遵循微内核+插件的涉及原则,所有核心能力如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现与第三方实现;
  • 运行期流量调度:内置条件、脚本等路由策略,通过配置不同的路由规则,实现灰度发布、同机房优先等功能;
  • 可视化的服务治理与运维:提供丰富治理、运维工具,随时查询服务元数据、服务建康状态及调用统计,实施下发路由策略、调整配置参数。

部署架构

  • 注册中心:协调Consumer与Provider之间的地址注册于发现。

        

  • 配置中心
    • 存储Dubbo启动阶段的全局配置,保证配置的跨环境共享与全局一致性;
    • 负责服务治理规则(路由规则、动态配置等)的存储与推送;

        

  • 元数据中心
    • 接收Provider上报的服务接口元数据,未Admin等控制台提供运维能力(如服务测试、接口文档等);
    • 作为服务发现机制的补充,提供额外的接口/方法级别的配置信息的同步能力,相当于注册中心的额外扩展;

        

上述三个中心并不是运行Dubbo的必要条件。

从Apache Dubbo架构图可以清晰的看出,除了基本的RPC框架的只能,它的核心功能便是监控以及服务注册

服务发现的一个核心组件是注册中心,Provider注册地址到注册中心,Consumer从注册中心读取和订阅Provider地址列表,因此,要启用服务发现,需要为Dubbo增加注册中心配置。如果不需要,可以设置未N/A,Dubbo支持多种注册中心,比如Zookeeper、Nacos、Consul等。Dubbo自身也提供了多种注册中心组件的对接。

以dubbo-spring-boot-starter使用方式为例,可如下增加注册中心配置:

# application.properties
dubbo
 registry
  address: zookeeper://127.0.0.1:2181

Dubbo3相比于Dubbo2引入了全新的服务发现模型——应用级服务发现,在工作原理、数据格式上不能兼容

  • Dubbo3应用级服务发现,以应用力度组织地址数据
  • Dubbo2接口级服务发现,以接口力度组织地址数据

Dubbo3格式的Provider地址不能被Dubbo2的Consumer识别到,反之Dubbo2的消费者也不能订阅到Dubbo3 Provider。

应用级服务发现:

主要有以下优势:

  • 适配云原生微服务变革。像Kubernetes等平台都继承了微服务概念抽象,Dubbo3的应用级服务发现是适配各种微服务体系的通用模型;
  • 提升性能与可伸缩性,支持超大规模集群的服务治理。从本质上解决了注册中心地址数据的存储与推送压力,相应的Consumer侧的地址计算压力也成数量级下降。

 配置参数

  • dubbo:application

        描述提供方的应用信息,比如应用名称、维护人、版本等,其中名称是必填项

  • dubbo:registry

        配置注册中心地址,如果不需要可以设置为N/A,支持多种注册中心。

  • dubbo:protocol

        协议信息,默认采用Dubbo协议,还可选择如Hessian、Webservice、Thrift等。

  • dubbo:service

        发布的服务接口描述,interface表示接口,ref表示接口实现。

集群容错

当服务调用这调用服务提供者的接口时,如果因为网络等问题出现请求失败,为了应对这种情况而实现的机制,叫做集群容错。Dubbo提供了6中容错模式,默认为Failover Cluster。

  1. Failover Cluster:失败自动切换到集群中的其他机器进行重试,默认重试次数为2,可通过属性retries=2来修改,但是越大,响应延迟就越高,通常用于读操作,因为事务型操作会带来数据重复问题。
  2. Failfast Cluster:快速失败,即失败后立即报错,只发起一次调用,通常用于一些幂等的写操作,避免结果不确定的情况下出现数据重复问题。
  3. Failsafe Cluster:失败安全,出现异常时,直接忽略异常。
  4. Failback Cluster:失败后自动回复,在后台记录失败请求,定时重新发起。这种适用于消息通知操作,保证最终能发送成功。
  5. Forking Cluster:并行调用集群中的多个服务,只要其中一个成功就返回,可以通过forks=2修改最大并行数。
  6. Boardcast Cluster:广播模式。任意一个服务报错则表示服务调用失败。常用于通知所有服务提供者更新缓存或者更新本地资源。

配置方式,如下:

@Service(cluster="failfast")
public class UserServiceImpl implements IUserService{
    @Value("${dubbo.application.name}")
    private String serviceName;

    @Override
    public String getUserDetail(Stirng name){
        return String.format("[%s]:Hello,%s, detail info is not found.",serviceName,name)
    }
}

在实际应用中,查询语句容错建议使用默认的Failover Cluster,而增删改操作建议使用Failfast Cluster或者使用Failover Cluster(retries="0")的策略,防止出现重复数据问题。

建议在涉及接口的时候把查询接口方法单独做成一个接口提供查询。

如果上述六种容错模式不能满足要求,也可以自行扩展。

负载均衡

负载均衡可以分为硬件负载(F5)和软件负载(Nginx)。

在Dubbo中提供了四种负载均衡策略,默认是random。同样如果四种不能满足要求,也可以基于Dubbo的SPI机制来进行拓展。

  • Random:随机算法,可以针对性能较好的服务器设置较大的权重值,权重值与随机概率成正比。
  • RoundRobin:轮询。按照公约后的权重设置轮询比例。
  • LeastActive:最少活跃调用数,处理较慢的节点将会收到更少的请求。
  • ConsistentHash:一致性hash。相同参数的请求总是发送到同一个服务提供者。

配置方式,如下:

@Service(cluster="failfast",loadbalance="roundrobin")

服务降级

服务降级是一种系统保护策略。当服务器访问压力较大时,可以把一些不必要的功能在流量较大的时间段关闭。

有多个层面的分类:

  • 按照是否自动化可分为自动降级和人工降级
  • 按照功能可分为读服务降级和写服务降级

人工降级一般具有一定的前置性,比如关闭评价、推荐等。

而系统降级多是由于系统出现了某些异常而自动触发的“兜底的流畅”,比如:

  • 故障降级,调用的远程服务“挂了”,网络故障或者RPC服务返回异常,在业务允许的情况下可以通过设置兜底数据相应给客户端;
  • 限流降级,当流量达到阙值时,后续的请求会被拦截,这类请求可以进入排队系统,比如12306,也可以直接返回降级页面,比如稍后重试等。

Dubbo提供了一种Mock配置来实现服务降级,也就是说服务提供方出现网络异常无法访问,客户端不抛出异常,而是通过降级配置返回兜底数据,操作步骤如下:

  • 创建实现自动降级的接口的类,重写接口中的抽象方法实现本地数据的返回。
public class MockHelloService implements IHelloService{
    @Override
    public String sayHello(String s){
        return "Sorry,服务暂时无法访问,返回降级数据.";
    }
}
  • 修改@Reference注解增加Mock参数,其中设置了属性cluster="failfast"
@RestController
public class HelloController{
    @Reference(mock="com.socool.mock.MockHelloService",cluster="failfast")
    private IHelloService helloService;
    
    @GetMapping("/say")
    public String sayHello(){
        return helloService.sayHello("socool");
    } 
}
  • 在不启动Dubbo服务端或者服务端返回的数据超过默认的超时时间,接口会相应Mock中返回的数据。

主机绑定规则

表示的是Dubbo服务对外发布的IP地址,默认情况下,Dubbo会按照以下顺序来查找并绑定主机IP地址:

  • 查找环境变量中DUBBO_IP_TO_BIND属性配置的IP地址;
  • 查找dubbo.protocol.host属性配置的IP地址,默认是空,如果没有配置或者不合法,则继续向下找;
  • 通过LocalHost.getHostAddress获取本机IP地址,如果获取失败,继续向下找;
  • 如果配置了注册中心的地址,则使用Socket通信连接到注册中心的地址后,使用for循环通过socket.getLocalAddress().getHostAddress()扫描各个网卡获取网卡IP地址;

上述过程中,任意一个步骤检测到合法的IP地址,便会默认返回将其作为对外暴露的服务IP地址。需要注意的是,获取的IP地址并不是写入注册中心的地址,默认情况下,写入注册中心的IP地址优先选择环境变量中DUBBO_IP_TO_REGISTER属性配置的IP地址,这个地址没有写入的情况下才会选择前面获取的地址并写入注册中心。

使用默认的主机绑定规则,可能会存在获取的IP地址不准确的情况,导致服务消费者与注册中心拿到的URL地址进行通信。因为Dubbo检测本地IP地址的策略是优先调用LocalHost.getHostAddress,这个方法原理是通过获取本机的hostname映射IP地址,如果它指向的是一个错误地址,那么这错误的地址会将作为注册发布的地址注册到ZooKeeper节点上,虽然Dubbo能够正常启动,但是消费者无法调用。可以通过以下方式来解决:

  • 修改hosts文件中的hostname,配置正确的IP地址映射;
  • 在环境变量中增加DUBBO_IP_TO_BIND或者DUBBO_IP_TO_REGISTER属性,value值为绑定的主机地址;
  • 通过dubbo.protocol.host设置主机地址。

Dubbo针对不同的协议提供了默认的端口号:

  • dubbo协议使用默认的是20880;
  • Webservice协议使用默认的是80;


版权声明:本文为woyaochange原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。