Dubbo

Dubbo

RPC Dubbo

为什么需要Dubbo?

前期是单体应用、垂直应用框架、SOA架构

image-20210717201709912

RPC

  • RPC(Remote Procedure Call)远程过程调⽤,简单的理解是⼀个节点请求另⼀个节点提供的服务
  • 本地过程调⽤:如需将本地student对象age+1,可以实现⼀个addAge()⽅法,将student对象传⼊,对年龄进⾏更新之后返回即可。
  • 远程过程调⽤:上述操作的过程中,如果addAge()这个⽅法在服务端,执⾏函数的函数体在远程机器上。

// Client端 Student student = Call(ServerAddr, addAge, student)

  1. 将这个调⽤映射为Call ID。

  2. 将Call ID,student(params)序列化,以⼆进制形式打包

  3. 把2中得到的数据包发送给ServerAddr,这需要使⽤⽹络传输层(server端第一步开始)

  4. 等待服务器返回结果

  5. 如果服务器调⽤成功,那么就将结果反序列化,并赋给student,年龄更新

// Server端

  1. 在本地维护⼀个Call ID到函数指针的映射call_id_map,可以⽤Map<String, Method>

callIdMap

  1. 等待客户端请求

  2. 得到⼀个请求后,将其数据包反序列化,得到Call ID

  3. 通过在callIdMap中查找,得到相应的函数指针

  4. 将student(params)反序列化后,在本地调⽤addAge()函数,得到结果

  5. 将student结果序列化后通过⽹络返回给Client

RPC调用过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XP7KFBpg-1629195447417)(/Users/apple/Library/Application Support/typora-user-images/image-20210717202405705.png)]

  • 客户端(Client):服务调⽤⽅。
  • 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成⽹络消息,再通过⽹络传输发送给服务端。
  • 服务端存根(Server Stub):接收客户端发送过来的请求消息并进⾏解包,然后再调⽤本地服务进⾏处理。
  • 服务端(Server):服务的真正提供者。
  • Network Service:底层传输,可以是 TCP 或 HTTP。

一次性服务过程

1.服务消费者(Client 客户端)通过本地调⽤的⽅式调⽤服务。

2.客户端存根(Client Stub)接收到调⽤请求后负责将⽅法、⼊参等信息序列化(组装)成能够进⾏⽹络传

输的消息体。

3.客户端存根(Client Stub)找到远程的服务地址,并且将消息通过⽹络发送给服务端。

4.服务端存根(Server Stub)收到消息后进⾏解码(反序列化操作)。

5.服务端存根(Server Stub)根据解码结果调⽤本地的服务进⾏相关处理

6.服务端(Server)本地服务业务处理。

7.处理结果返回给服务端存根(Server Stub)。

8.服务端存根(Server Stub)序列化结果。

9.服务端存根(Server Stub)将结果通过⽹络发送⾄消费⽅。

10.客户端存根(Client Stub)接收到消息,并进⾏解码(反序列化)。

11.服务消费⽅得到最终结果。

完整的RPC进程图

  • 在⼀个典型 RPC 的使⽤场景中,包含了服务发现、负载、容错、⽹络传输、序列化等组件,其中“RPC 协议”就指明了程序如何进⾏⽹络传输和序列化。
image-20210717202824621

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-42XyTS0F-1629195447419)(/Users/apple/Library/Application Support/typora-user-images/image-20210717203159469.png)]

RPC的核心功能

  • 服务寻址

    1、服务寻址可以使⽤ Call ID 映射。在本地调⽤中,函数体是直接通过函数指针来指定的,但是在远程调⽤中,函数指针是不⾏的,因为两个进程的地址空间是完全不⼀样的。

    2、所以在 RPC 中,所有的函数都必须有⾃⼰的⼀个 ID。这个 ID 在所有进程中都是唯⼀确定的。

    3、客户端在做远程过程调⽤时,必须附上这个 ID。然后我们还需要在客户端和服务端分别维护⼀个函数和Call ID的对应表。

    4、当客户端需要进⾏远程调⽤时,它就查⼀下这个表,找出相应的 Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调⽤的函数,然后执⾏相应函数的代码。

    实现方式:服务注册中心

    要调⽤服务,⾸先你需要⼀个服务注册中⼼去查询对⽅服务都有哪些实例。Dubbo 的服务注册中⼼是可以配置的,官⽅推荐使⽤ Zookeeper。

  • 数据流的序列化和反序列化

    客户端怎么把参数值传给远程的函数呢?

    在本地调⽤中,我们只需要把参数压到栈⾥,然后让函数⾃⼰去栈⾥读就⾏。

    但是在远程过程调⽤时,客户端跟服务端是不同的进程,不能通过内存来传递参数。

    这时候就需要客户端把参数先转成⼀个字节流,传给服务端后,再把字节流转成⾃⼰能读取的格式。

    只有⼆进制数据才能在⽹络中传输,序列化和反序列化的定义是:

    • 将对象转换成⼆进制流的过程叫做序列化
    • 将⼆进制流转换成对象的过程叫做反序列化

    常见的序列化方式:

    • Hessian 是动态类型、⼆进制、紧凑的,并且可跨语⾔移植的⼀种序列化框架。Hessian 协议要⽐JDK、JSON 更加紧凑,性能上要⽐ JDK、JSON 序列化⾼效很多,⽽且⽣成的字节数也更⼩。
    • Protobuf 是 Google 公司内部的混合语⾔数据标准,是⼀种轻便、⾼效的结构化数据存储格式,可以⽤于结构化数据序列化,⽀持 Java、Python、C++、Go 等语⾔。序列化后体积相⽐ JSON、Hessian ⼩很多;
    • Thrift是Facebook开源提供的⼀个⾼性能,轻量级RPC服务框架,其产⽣正是为了满⾜当前⼤数据量、分布式、跨语⾔、跨平台数据通讯的需求。
  • 网络传输

    ⽹络传输:远程调⽤往往⽤在⽹络上,客户端和服务端是通过⽹络连接的。

    所有的数据都需要通过⽹络传输,因此就需要有⼀个⽹络传输层。⽹络传输层需要把 Call ID 和序列化

    后的参数字节流传给服务端,然后再把序列化后的调⽤结果传回客户端。

    只要能完成这两者的,都可以作为传输层使⽤。因此,它所使⽤的协议其实是不限的,能完成传输就

    ⾏。 ⼤部分 RPC 框架都使⽤ TCP 协议,但其实 UDP 也可以。

    TCP 的连接是最常⻅的,简要分析基于 TCP 的连接:通常 TCP 连接可以是按需连接(需要调⽤的时候就

    先建⽴连接,调⽤结束后就⽴⻢断掉),也可以是⻓连接(客户端和服务器建⽴起连接之后保持⻓期持

    有,不管此时有⽆数据包的发送,可以配合⼼跳检测机制定期检测建⽴的连接是否存活有效),多个远程

    过程调⽤共享同⼀个连接。

    所以,要实现⼀个 RPC 框架,只需要把以下三点实现了就基本完成了:

    • Call ID 映射:可以直接使⽤函数字符串,也可以使⽤整数 ID。映射表⼀般就是⼀个哈希表。
    • 序列化反序列化:可以⾃⼰写,也可以使⽤ Protobuf 或者 FlatBuffers 之类的。
    • ⽹络传输库:可以⾃⼰写 Socket,或者⽤ Asio,ZeroMQ,Netty 之类。

Dubbo有哪些能力?

  • ⾯向接⼝代理的⾼性能RPC调⽤

提供⾼性能的基于代理的远程调⽤能⼒,服务以接⼝为粒度,为开发者屏蔽远程调⽤底层细节

  • 智能负载均衡

内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调⽤延迟,提⾼系统吞吐量

  • 服务⾃动注册与发现

⽀持多种注册中⼼服务,服务实例上下线实时感知

  • ⾼度可扩展能⼒

遵循微内核+插件的设计原则,所有核⼼能⼒如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现和第三⽅实现

  • 运⾏期流量调度

内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能

  • 可视化的服务治理与运维

提供丰富服务治理、运维⼯具:随时查询服务元数据、服务健康状态及调⽤统计,实时下发路由策略、调整配置参数

  • 地址维护(当服务越来越多时,服务 URL 配置管理变得⾮常困难);这时候需要⼀个服务注册中⼼,动态的注册和发现服务,使服务的位置透明

  • 负载均衡(当服务越来越多时,F5 硬件负载均衡器的单点压⼒也越来越⼤);通过在消费⽅获取服务提供⽅地址列表,实现软负载均衡和 Failover

  • 限流/容错/降级;

  • 链路监控;监控: 服务的调⽤量越来越⼤,服务的容量问题就暴露出来,这个服务需要多少机器⽀撑?什么时候该加机器?为了解决这些问题,第⼀步,要将服务现在每天的调⽤量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重⼀直加⼤,并在加⼤的过程中记录响应时间的变化,直到响应时间到达阈值,记录此时的访问量,再以此访问量乘以机器数反推总容量。

Dubbo架构图

image-20210717204745935

节点说明:

prodiver:暴露服务的服务提供⽅、

consumer:调⽤远程服务的服务消费⽅

registry:服务注册与发现的注册中⼼

monitor:统计服务的调⽤次数和调⽤时间的监控中⼼

container:服务运⾏容器

调用关系说明:

  1. 服务容器负责启动,加载,运⾏服务提供者。

  2. 服务提供者在启动时,向注册中⼼注册⾃⼰提供的服务。

  3. 服务消费者在启动时,向注册中⼼订阅⾃⼰所需的服务。

  4. 注册中⼼返回服务提供者地址列表给消费者,如果有变更,注册中⼼将基于⻓连接推送变更数据给消费者。

  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选⼀台提供者进⾏调⽤,如果调⽤失败,再选另⼀台调⽤。

  6. 服务消费者和提供者,在内存中累计调⽤次数和调⽤时间,定时每分钟发送⼀次统计数据到监控中⼼。

Dubbo架构特点

  • 连通性(zookeeper)

    • 注册中⼼负责服务地址的注册与查找,相当于⽬录服务,服务提供者和消费者只在启动时与注册中⼼交互,注册中⼼不转发请求,压⼒较⼩
    • 监控中⼼负责统计各服务调⽤次数,调⽤时间等,统计先在内存汇总后每分钟⼀次发送到监控中⼼服务器,并以报表展示
    • 服务提供者向注册中⼼注册其提供的服务,并汇报调⽤时间到监控中⼼,此时间不包含⽹络开销
    • 服务消费者向注册中⼼获取服务提供者地址列表,并根据负载算法直接调⽤提供者,同时汇报调⽤时间到监控中⼼,此时间包含⽹络开销
    • 注册中⼼,服务提供者,服务消费者三者之间均为⻓连接,监控中⼼除外
    • 注册中⼼通过⻓连接感知服务提供者的存在,服务提供者宕机,注册中⼼将⽴即推送事件通知消费者
    • 注册中⼼和监控中⼼全部宕机,不影响已运⾏的提供者和消费者,消费者在本地缓存了提供者列表
    • 注册中⼼和监控中⼼都是可选的,服务消费者可以直连服务提供者
  • 健壮性

    • 监控中⼼宕掉不影响使⽤,只是丢失部分采样数据

    • 数据库宕掉后,注册中⼼仍能通过缓存提供服务列表查询,但不能注册新服务注册中⼼对等集群,任意⼀台宕掉后,将⾃动切换到另⼀台

    • 注册中⼼全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯

    • 服务提供者⽆状态,任意⼀台宕掉后,不影响使⽤

    • 服务提供者全部宕掉后,服务消费者应⽤将⽆法使⽤,并⽆限次重连等待服务提供者恢复

  • 伸缩性

    • 注册中⼼为对等集群,可动态增加机器部署实例,所有客户端将⾃动发现新的注册中⼼
  • 服务提供者⽆状态,可动态增加机器部署实例,注册中⼼将推送新的服务提供者信息给消费者

SpringBoot中使用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">
  <parent> 
    <artifactId>dubbo-demo-other</artifactId>
    <groupId>com.end</groupId>
    <version>1.0.0-SNAPSHOT</version>
</parent>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.end</groupId> 
  <artifactId>dubbo-demo-other-provider</artifactId> 
  <version>1.0.0-SNAPSHOT</version>
  <dependencies> 
    <dependency> 
      <groupId>com.end</groupId>
      <artifactId>dubbo-demo-api</artifactId>
      <version>1.0.0-SNAPSHOT</version>
</dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbospring-boot-starter -->
  <dependency>
    <groupId>org.apache.dubbo</groupId> 
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.3</version>
  </dependency>
  <!--https://mvnrepository.com/artifact/org.springframework.boot/spring-bootstarter -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.3.0.RELEASE</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubboregistry-zookeeper -->
  <dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-zookeeper</artifactId>
    <version>2.7.3</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbometadata-report-zookeeper -->
  <dependency>
    <groupId>org.apache.dubbo</groupId> 
    <artifactId>dubbo-metadata-report-zookeeper</artifactId>
    <version>2.7.3</version>
  </dependency>
</dependencies>
</project>
Boot和Dubbo整合的方式:XML和注解
  • xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd">
    <dubbo:application name="demo-other-provider" />
    <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>
    <dubbo:registry id="registry" address="zookeeper://127.0.0.1:2181?
    registry-type=service"/>
    <dubbo:protocol name="dubbo" port="20881"/>
    <bean id="orderService" class="com.end.dubbo.service.OrderServiceImpl"/>
    <dubbo:service interface="com.end.dubbo.api.service.OrderService"
    timeout="3000" ref="orderService" registry="registry"/>
    </beans>
    

    主启动类

    package com.end.dubbo;
    import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.ImportResource;
    @ImportResource(locations = {"classpath:dubbo-other-provider.xml"})
    @SpringBootApplication
    public class DubboOtherProviderApplication {
     public static void main(String[] args) {
     SpringApplication.run(DubboOtherProviderApplication.class, args);
     }
    }
    
  • 注解

RPC分布式扩展

Dubbp 集群容错

  • Failover Cluster

    失败自动切换,当出现失败,重试其他服务器,。通常用与读操作,但重试会带来更长延迟。科通过retries = 2,来设置重试次数(不含第一次);

    <dubbo:reference retries = “2”>

  • Failfast Cluster

    快速失败,只发起⼀次调⽤,失败⽴即报错。通常⽤于⾮幂等性的写操作,⽐如新增记录。

    <dubbo:service cluster=“failfast” />

  • Failsafe Cluster

    失败安全,出现异常时,直接忽略。通常⽤于写⼊审计⽇志等操作。

    <dubbo:service cluster=“failsafe”/>

  • Failback Cluster

    失败⾃动恢复,后台记录失败请求,定时重发。通常⽤于消息通知操作。

    <dubbo:service cluster=“failback”/>

  • Forking Cluster

    并⾏调⽤多个服务器,只要⼀个成功即返回。通常⽤于实时性要求较⾼的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最⼤并⾏数。

    <dubbo:service cluster=“forking” forks=“2”>

  • Broadcast Cluster

    ⼴播调⽤所有提供者,逐个调⽤,任意⼀台报错则报错。通常⽤于通知所有提供者更新缓存或⽇志等本地资源信息。

    <dubbo:service cluster=“broadcast” forks=“2”>

Dubbo 负载均衡

  • Random LoadBalance

    随机,按权重设置随机概率。

    在⼀个截⾯上碰撞的概率⾼,但调⽤量越⼤分布越均匀,⽽且按概率使⽤权重后也⽐较均匀,

    有利于动态调整提供者权重。

  • RoundRobin LoadBalance

    轮询,按公约后的权重设置轮询⽐率。

    存在慢的提供者累积请求的问题,⽐如:第⼆台机器很慢,但没挂,当请求调到第⼆台时就卡

    在那,久⽽久之,所有请求都卡在调到第⼆台上。

  • LeastActive LoadBalance

    最少活跃调⽤数,相同活跃数的随机,活跃数指调⽤前后计数差。

    使慢的提供者收到更少请求,因为越慢的提供者的调⽤前后计数差会越⼤。

  • ConsistentHash LoadBalance

    ⼀致性 Hash,相同参数的请求总是发到同⼀提供者。

    当某⼀台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引

    起剧烈变动。

image-20210718205010613

hash偏滑问题

这⾥相同颜⾊的节点均属于同⼀个服务提供者,⽐如 Invoker1-1,Invoker1-2,……, Invoker1-160。

这样做的⽬的是通过引⼊虚拟节点,让 Invoker 在圆环上分散开来,避免数据倾斜问题。所谓数据倾斜是指,由于节点不够分散,导致⼤量请求落到了同⼀个节点上,⽽其他节点只会接收到了少量请求的情况。

例如:

image-20210718205556358

如上,由于 Invoker-1 和 Invoker-2 在圆环上分布不均,导致系统中75%的请求都会落到 Invoker-1上,只有 25% 的请求会落到 Invoker-2 上。解决这个问题办法是引⼊虚拟节点,通过虚拟节点均衡各个节点的请求量。

image-20210718205352097

Dubbo的最佳实践

  • 分包

    建议将服务接⼝、服务模型、服务异常等均放在 API 包中,因为服务模型和异常也是 API 的⼀部分,这样做也符合分包原则:重⽤发布等价原则(REP),共同重⽤原则(CRP)。

    如果需要,也可以考虑在 API 包中放置⼀份 Spring 的引⽤配置,这样使⽤⽅只需在 Spring 加载过程中引⽤此配置即可。配置建议放在模块的包⽬录下,以免冲突,如: com/alibaba/china/xxx/dubbo-reference.xml 。

  • 粒度

    服务接⼝尽可能⼤粒度,每个服务⽅法应代表⼀个功能,⽽不是某功能的⼀个步骤,否则将⾯临分布式事务问题,Dubbo 暂未提供分布式事务⽀持。

    服务接⼝建议以业务场景为单位划分,并对相近业务做抽象,防⽌接⼝数量爆炸。

    不建议使⽤过于抽象的通⽤接⼝,如: Map query(Map) ,这样的接⼝没有明确语义,会给后期维护带来不便。

  • 版本

    每个接⼝都应定义版本号,为后续不兼容升级提供可能,如:<dubbo:service interface=“com.xxx.XxxService” version=“1.0” /> 。

    建议使⽤两位版本号,因为第三位版本号通常表示兼容升级,只有不兼容时才需要变更服务版本。

    当不兼容时,先升级⼀半提供者为新版本,再将消费者全部升为新版本,然后将剩下的⼀半提供者升为新版本。

  • 兼容性

    服务接⼝增加⽅法,或服务模型增加字段,可向后兼容,删除⽅法或删除字段,将不兼容,枚举类型新增字段也不兼容,需通过变更版本号升级。

  • 枚举值(不建议使用

    如果是完备集,可以⽤ Enum ,⽐如: ENABLE , DISABLE 。

    如果是业务种类,以后明显会有类型增加,不建议⽤ Enum ,可以⽤ String 代替。

    如果是在返回值中⽤了 Enum ,并新增了 Enum 值,建议先升级服务消费⽅,这样服务提供⽅不会返回新值。

    如果是在传⼊参数中⽤了 Enum ,并新增了 Enum 值,建议先升级服务提供⽅,这样服务消费⽅不会传⼊新值。

  • 序列化

    服务参数及返回值建议使⽤ POJO 对象,即通过 setter , getter ⽅法表示属性的对象。

  • 调用

    不要只是因为是 Dubbo 调⽤,⽽把调⽤ try…catch 起来。 try…catch 应该加上合适的回滚边界上。

    Provider 端需要对输⼊参数进⾏校验。如有性能上的考虑,服务实现者可以考虑在 API 包上加上服务Stub 类来完成检验。

Dubbo推荐用法

  • 在provider端尽量多配置consumer端的属性

    原因:

    1、作服务的提供⽅,⽐服务消费⽅更清楚服务的性能参数,如调⽤的超时时间、合理的重试次数等

    2、在 Provider 端配置后,Consumer 端不配置则会使⽤ Provider 端的配置,即 Provider 端的配置可以作为 Consumer 的缺省值 1。否则,Consumer 会使⽤ Consumer 端的全局设置,这对于Provider 是不可控的,并且往往是不合理的

    Provider 端尽量多配置 Consumer 端的属性,让 Provider 的实现者⼀开始就思考 Provider 端的服务特点和服务质量等问题。

<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" timeout="300" retries="2" loadbalance="random" actives="0" />
<dubbo:service interface="com.alibaba.hello.api.WorldService" version="1.0.0" ref="helloService" timeout="300" retries="2" loadbalance="random" actives="0" >
  <dubbo:method name="findAllPerson" timeout="10000" retries="9" loadbalance="leastactive" actives="5" />
 <dubbo:service/>

建议在provider端配置的consumer端的属性

  1. timeout :⽅法调⽤的超时时间

  2. retries :失败重试次数,缺省是 2 2

  3. loadbalance :负载均衡算法 3,缺省是随机 random 。还可以配置轮询 roundrobin 、最不活跃优先 4 leastactive 和⼀致性哈希 consistenthash 等

  4. actives :消费者端的最⼤并发调⽤限制,即当 Consumer 对⼀个服务的并发调⽤到上限后,新调⽤会阻塞直到超时,在⽅法上配置 dubbo:method 则针对该⽅法进⾏并发限制,在接⼝上配置dubbo:service ,则针对该服务进⾏并发限制

在provider端配置合理的provider的属性

<dubbo:protocol threads="200" />
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" executes="200" > 
<dubbo:method name="findAllPerson" executes="50" />
</dubbo:service>
  1. threads :服务线程池⼤⼩

  2. executes :⼀个服务提供者并⾏执⾏请求上限,即当 Provider 对⼀个服务的并发调⽤达到上限后,新调⽤会阻塞,此时 Consumer 可能会超时。在⽅法上配置 dubbo:method 则针对该⽅法进⾏并发限制,在接⼝上配置 dubbo:service ,则针对该服务进⾏并发限制

配置管理信息

⽬前有负责⼈信息和组织信息⽤于区分站点。以便于在发现问题时找到服务对应负责⼈,建议⾄少配置两个⼈以便备份。负责⼈和组织信息可以在运维平台 (Dubbo Ops) 上看到。

在应⽤层⾯配置负责⼈、组织信息:

<dubbo:application owner=”ding.lid,william.liangf” organization=”intl” />

在服务层⾯(服务端)配置负责⼈:

<dubbo:service owner=”ding.lid,william.liangf” />

在服务层⾯(消费端)配置负责⼈:

<dubbo:reference owner=”ding.lid,william.liangf” />

配置Dubbo缓存文件

提供者列表缓存⽂件:

<dubbo:registry file=”${user.home}/output/dubbo.cache” />

注意:

  1. 可以根据需要调整缓存⽂件的路径,保证这个⽂件不会在发布过程中被清除;

  2. 如果有多个应⽤进程,请注意不要使⽤同⼀个⽂件,避免内容被覆盖;

该⽂件会缓存注册中⼼列表和服务提供者列表。配置缓存⽂件后,应⽤重启过程中,若注册中⼼不可⽤,应⽤会从该缓存⽂件读取服务提供者列表,进⼀步保证应⽤可靠性。

监控配置

  1. 使⽤固定端⼝暴露服务,⽽不要使⽤随机端⼝这样在注册中⼼推送有延迟的情况下,消费者通过缓存列表也能调⽤到原地址,保证调⽤成功。

  2. 使⽤ Dubbo Admin 监控注册中⼼上的服务提供⽅使⽤ Dubbo Admin 监控服务在注册中⼼上的状态,确保注册中⼼上有该服务的存在。

  3. 服务提供⽅可使⽤ Dubbo Qos 的 telnet 或 shell 监控项监控服务提供者端⼝状态: echo status | nc -i 1 20880 | grep OK | wc -l ,其中 20880 为服务端⼝

  4. 服务消费⽅可通过将服务强制转型为 EchoService,并调⽤ e c h o ( ) 测 试 该 服 务 的 提 供 者 是 可 ⽤ 如 a s s e r t E q a u l s ( “ O K ” , ( ( E c h o S e r v i c e ) m e m b e r S e r v i c e ) . echo() 测试该服务的提供者是可⽤如 assertEqauls(“OK”, ((EchoService)memberService). echo()assertEqauls(OK,((EchoService)memberService).echo(“OK”));

Dubbo常见面试题

分布式事务

为什么会有分布式事务的问题?

image-20210718212618927

分布式理论基础

  • CAP理论

    image-20210718212744428

C: 强⼀致性(⼤部分互联⽹公司会牺牲强⼀致性)

A:可⽤性 (绝⼤部份互联⽹公司需要考虑的)

P:分区容错性(绝⼤部份互联⽹公司需要考虑的)

  • BASE
  • Zookeeper满足CAP理论的那些? CP

分布式事务常见方案

  • 2CP(XA)【两阶段提交】
  • TCC(事务补偿)【try、comfire、cancel】
  • 本地消息事件+消息队列【使用最多】

工作中常用的解决方案

常见的业务流程:

  • 先创建订单,再发送消息?

    public void processOrder() {
     // 订单处理(业务操作)
     orderService.process();
     // 发送订单处理成功消息(发送消息)
     sendBizMsg ();
     }
    
  • 先发送消息,再创建订单?

    public void processOrder() {
     // 发送订单处理成功消息(发送消息)
     sendBizMsg ();
     // 订单处理(业务操作)
     orderService.process();
     }
    
  • 两步放在一个事务里,做回滚?

    @Transactionnal
     public void processOrder() {
       try{
       // 订单处理(业务操作)
       orderService.process();
       // 发送订单处理成功消息(发送消息)
       sendBizMsg ();
       }
       catch(Exception e){
          //事务回滚; 
       }
     }
    

基于本地消息的最终一致性解决方案

如何做好系统设计确保最终一致性?

  • 消息记录本地事件表
  • 定时服务轮训事件状态表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值