• RPC远程调用框架Dubbo


    一、分布式服务调用_什么是RPC

    RPC(Remote Procedure Call)远程过程调用,它是一种通过网络从远程计算机程序上请求服务。

    大白话理解就是:RPC让你用别人家的东西就像自己家的一样。

    RPC两个作用:

    • 屏蔽远程调用跟本地调用的区别,让我们感觉就是调用项目内的方法
    • 隐藏底层网络通信的复杂性,让我们更加专注业务逻辑。

    常用的RPC框架

    RPC是一种技术思想而非一种规范或协议。

    常见 RPC 技术和框架:

    • 阿里的 Dubbo/Dubbox、Google gRPC、Spring Cloud。

    二、Dubbo是什么

    Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang、Rust 等多语言 SDK 实现。

    2.1 为什么需要Dubbo,它能做什么?

    按照微服务架构的定义,采用它的组织能够很好的提高业务迭代效率与系统稳定性,但前提是要先能保证微服务按照期望的方式运行,要做到这一点需要解决服务拆分与定义、数据通信、地址发现、流量管理、数据一致性、系统容错能力等一系列问题。

    Dubbo 可以帮助解决如下微服务实践问题:

    • 微服务编程范式和工具

    Dubbo 支持基于 IDL 或语言特定方式的服务定义,提供多种形式的服务调用形式(如同步、异步、流式等)

    • 高性能的 RPC 通信

    Dubbo 帮助解决微服务组件之间的通信问题,提供了基于 HTTP、HTTP/2、TCP 等的多种高性能通信协议实现,并支持序列化协议扩展,在实现上解决网络连接管理、数据传输等基础问题。

    • 微服务监控与治理

    Dubbo 官方提供的服务发现(可用nacos)、动态配置(可用nacos)、负载均衡、流量路由等基础组件可以很好的帮助解决微服务基础实践的问题。除此之外,您还可以用 Admin 控制台监控微服务状态,通过周边生态完成限流降级、数据一致性、链路追踪等能力。

    • 部署在多种环境

    Dubbo 服务可以直接部署在容器、Kubernetes、Service Mesh等多种架构下。

    • 活跃的社区

    Dubbo 项目托管在 Apache 社区,有来自国际、国内的活跃贡献者维护着超 10 个生态项目,贡献者包括来自海外、阿里巴巴、工商银行、携程、蚂蚁、腾讯等知名企业技术专家,确保 Dubbo 及时解决项目缺陷、需求及安全漏洞,跟进业界最新技术发展趋势。

    • 庞大的用户群体

    Dubbo3 已在阿里巴巴成功取代 HSF 框架实现全面落地,成为阿里集团面向云原生时代的统一服务框架,庞大的用户群体是 Dubbo 保持稳定性、需求来源、先进性的基础。

    2.2 Dubbo 不是什么?

    • 不是应用开发框架的替代者

    Dubbo 设计为让开发者以主流的应用开发框架的开发模式工作,它不是各个语言应用开发框架的替代者,如它不是 Spring/Spring Boot 的竞争者,当你使用 Spring 时,Dubbo 可以无缝的与 Spring & Spring Boot 集成在一起。

    • 不仅仅只是一款 RPC 框架

    Dubbo 提供了内置 RPC 通信协议实现,但它不仅仅是一款 RPC 框架。首先,它不绑定某一个具体的 RPC 协议,开发者可以在基于 Dubbo 开发的微服务体系中使用多种通信协议;其次,除了 RPC 通信之外,Dubbo 提供了丰富的服务治理能力与生态。

    • 不是 gRPC 协议的替代品

    Dubbo 支持基于 gRPC 作为底层通信协议,在 Dubbo 模式下使用 gRPC 可以带来更好的开发体验,享有统一的编程模型和更低的服务治理接入成本

    • 不只有 Java 语言实现

    自 Dubbo3 开始,Dubbo 提供了 Java、Golang、Rust、Node.js 等多语言实现,未来会有更多的语言实现。

    2.3 任意通信协议

    Dubbo 微服务间远程通信实现细节,支持 HTTP、HTTP/2、gRPC、TCP 等所有主流通信协议。与普通 RPC 框架不同,Dubbo 不是某个单一 RPC 协议的实现,它通过上层的 RPC 抽象可以将任意 RPC 协议接入 Dubbo 的开发、治理体系。

    2.4 多语言 SDK

    Dubbo 提供几乎所有主流语言的 SDK 实现,定义了一套统一的微服务开发范式。Dubbo 与每种语言体系的主流应用开发框架做了适配,总体编程方式、配置符合大多数开发者已有编程习惯。

    三、项目所需要引入的依赖

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-webartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>org.apache.dubbogroupId>
    7. <artifactId>dubbo-spring-boot-starterartifactId>
    8. dependency>
    9. <dependency>
    10. <groupId>org.apache.dubbogroupId>
    11. <artifactId>dubbo-registry-nacosartifactId>
    12. dependency>

    四、启动时检查

    @DubboReference注解:

    • 使用在调用者处.
    • 如果配置check为false(默认为true),表示在启动时检查服务是否可用, 如果不可用, 则抛出异常. 设置为false, 表示不检查.即使服务不可用也可以正常启动服务.
    @DubboReference(check = false)
    

     

    五、Dubbo地址缓存

    如果当Nacos突然故障,是否还能够保证Dubbo远程调用服务的正常使用(远端服务没有故障,只是nacos出现了问题).

    答案是可以正常访问的,这也是Dubbo的强大之处.

    Dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后在调用则不会访问注册中心。服务提供者地址发生变化时注册中心会通知服务消费者

    六、服务发布

    dubbo的服务要 被nacos检测,首先需要在对应服务接口加上@DubboService注解.这样我们将在nacos中看见dubbo所属服务的接口.

    1. @DubboService
    2. public class IPaymentServiceImpl implements IPaymentService {
    3. @Override
    4. public String payment(Integer id) throws InterruptedException {
    5. return " hello world";
    6. }
    7. }

    七、超时时间

    在其注解当中加入timeout属性.单位为毫秒ms.

    1. @DubboReference(check = false,timeout = 1000)
    2. //对于某个方法也可以设置超时
    3. @DubboReference(methods = {@Method(name = "payment",timeout = 1000)})

    服务端也是可以设置超时时间的

    @DubboService(timeout = 1000)

    超时是针对消费端,为什么服务端也可以设置超时呢?

    这其实是一种策略,其实服务端的超时配置是消费端的缺省配置,即如果服务端设置了超时,任务消费端可以不设置超时时间,简化了配置。另外针对控制的粒度,Dubbo支持了接口级别也支持方法级别,可以根据不同的实际情况精确控制每个方法的超时时间。

    但是如果你实际去测试,会发现一个奇怪的事情,你设计了1s的超时时间,但是你去请求一个超过1秒的服务(可利用Thread.sleep()制造一个异常).你会发现实际请求的时间却是大于1s的.大概在3s左右.这是为什么呢?

    这就跟后面的超时重试有关啦.

    八、超时重试

    dubbo中默认会重试两次,所以在刚刚的示例当中,请求了一次,重试了两次.最后结果就是三次,也就是过了3秒后就结束啦.

    但注意的是,不是在3秒内这个接口能够完成业务并返回结果就可以了,就不会抛出异常了.这是不正确的.

    超时时间针对的是每一次的请求,你一次请求超过了1秒那就会进入第二次重试,重试后还是超过了1秒那接着就是最后一次.也就是设置超时时间表明了这一次请求需要在你设置的超时时间内完成.

    我们可以通过其属性retries配置其重试次数(默认为2次)

    @DubboReference(retries = 0)
    

    九、多版本机制

    服务发布是可以多版本的,在@DubboService中配置version属性

    @DubboService(version = "1.0.0")

    调用者可以指定使用哪个版本的服务

    @DubboReference(version = "1.0.0")


    多版本的作用:

    可以不停机更新服务, 而不影响客户端的调用.少量的放入新版本,慢慢的切换到新版本.实现平滑升级.灰度发布.当出现新功能时,会让一部分用户先使用新功能,用户反馈没问题时,再将所有用户迁移到新功能。

    (一) 版本迁移步骤

    1. 在低压力时间段,先升级一半提供者为新版本
    2. 再将所有消费者升级为新版本
    3. 然后将剩下的一半提供者升级为新版本

    十、负载均衡

    在调用远程服务时,可能存在多个远程服务的实例.这个时候我们需要负载均衡.其实也就是跟Nginx,openFeign的负载均衡都是一个样子.

    牵扯到负载均衡,那么dubbo提供了哪些常用的负载均衡的算法呢?

    • random: 随机
    • roundrobin: 轮询
    • leastactive: 最少活跃调用数(也就是哪个服务器压力小)
    • consistenthash: 参数一致性hash
      • 将服务实例经过hash运算放入到散列表中,然后调用服务的接口,经过hash计算看落在哪个位置对应的服务就调用哪个服务.如果所落在位置没有实例(服务出了故障),则将会向后移动,直到找到对应的实例.
         

    如果记不住这些也没关系,通过Idea双击shift,查找loadbalance关键字,找到所属dubbo包下的loadbalance

    然后通过接口上按下ctrl+h即可查看到所有的实例.

    随便点击一个负载均衡实现的类.里面显示的NAME属性就是我们需要配置的名称.

    落实到代码层面怎么配置呢,像下面这样

    @DubboReference(loadbalance = "roundrobin")

    其属性名的值就是按上述方法当中查找.

    十一、集群容错

    当调用处出了问题时,我们要以何种方法进行容错处理呢?

    dubbo默认是失败了重试,即Failover机制.它还提供了其他的容错策略

    1. Failover(失败自动切换)
    • 策略说明:当调用失败时,自动切换到其他服务器重试。这是Dubbo的默认容错策略,适用于读操作或幂等性的写操作。
    • 举例说明:假设有一个商品查询服务,当查询第一个服务器失败时,Dubbo会自动将请求切换到另一个服务器进行重试,直到查询成功或达到重试次数上限。
    • 配置示例,其中retries表示重试次数,不包括第一次调用。
    2. Failfast (快速失败)
    • 策略说明:只发起一次调用,失败立即报错。适用于非幂等性的写操作,如新增记录,以避免重复处理。
    • 举例说明:在订单生成场景中,如果第一次调用创建订单服务失败,Dubbo会立即报错,不再重试,以防止生成重复的订单。
    3. Failsafe(失败安全)
    • 策略说明:调用失败时,直接忽略错误,继续执行后续逻辑。适用于记录日志等非核心业务逻辑。
    • 举例说明:在写入审计日志的场景中,如果日志服务调用失败,Dubbo会忽略该错误,继续执行后续操作,以保证主业务流程不受影响。
    4. Failback(失败自动恢复)
    • 策略说明:调用失败后,不会立即报错,而是将失败请求缓存起来,定时重试,直到请求成功。适用于那些偶尔出现故障但期望未来可以恢复的服务调用。
    • 举例说明:在发送消息通知的场景中,如果第一次发送失败,Dubbo会将失败的消息缓存起来,并在后台定时重试,直到消息成功发送。
    • 需要注意的是,Failback策略目前有一些局限,如失败调用列表没有上限可能导致堆积,异步重试的执行间隔无法调整等
    5. Broadcast(广播)
    • 策略说明:向所有服务提供者广播调用,逐个调用,任意一个报错则报错。适用于通知所有提供者更新缓存或日志文件等场景。
    • 举例说明:在缓存更新场景中,Dubbo会向所有缓存服务提供者广播更新请求,以确保所有缓存都得到更新。

    记不住也可以同样查找cluster关键字,找到对应的接口,从这样我们也可以看见默认为什么是Failover

    其他的策略接口

    代码配置

        @DubboReference(cluster = "failover")
    

    十二、序列化协议

    网络传输的数据必须是二进制数据,但调用方请求的出入参数都是对象。此时对象需要实现Serializable接口,否则将会报错.

  • 相关阅读:
    Spring6--IOC反转控制 / 基于XML管理bean
    Spring常见问题解决 - @PathVariable 解析带 / 的参数值报404
    第七章:最新版零基础学习 PYTHON 教程—Python 列表(第二节 -Python 创建具有给定范围的数字列表)
    路由器本地docker 下载node容器部署 thressjs文档
    10_光速学会docker用法:80分钟一口气学完docker+k8s!带你掌握docker+k8s所有核心知识点,全程干货,无废话!
    flume 通过syslog协议读取系统日志
    HTML5 游戏开发实战 | 推箱子
    python爬虫之protobuf协议介绍
    Android Radio实战——打开Tuner(十八)
    11月25日:tp框架中的架构,配置,路由,控制器
  • 原文地址:https://blog.csdn.net/m0_65013257/article/details/140963080