💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

  • 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
  • 导航
    • 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
    • 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
    • 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

一.架构演进介绍

1.互联网项目特点

  • 用户多流量大
  • 并发高
  • 海量数据易
  • 受攻击
  • 功能繁琐
  • 变更快

2.衡量网站的性能指标

  • 响应时间:指执行一个请求从开始到最后收到响应数据所花费的总体时间。

  • 并发数:指系统同时能处理的请求数量。

    • 并发连接数:指的是客户端向服务器发起请求,并建立了 TCP 连接。每秒钟服务器连接的总 TCP 数量
    • 请求数:也称为 QPS(Query Per Second) 指每秒多少请求.
    • 并发用户数:单位时间内有多少用户
  • 吞吐量:指单位时间内系统能处理的请求数量。

    • QPS:Query Per Second 每秒查询数。

    • TPS:Transactions Per Second 每秒事务数。

    • 一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。

    • 一个页面的一次访问,只会形成一个 TPS;但一次页面请求,可能产生多次对服务器的请求,就会有多个 QPS

大小关系:

QPS >= 并发连接数 >= TPS

3.项目架构目标

  • 高性能:提供快速的访问体验。
  • 高可用:网站服务一直可以正常访问。
  • 可伸缩:通过硬件增加/减少,提高/降低处理能力。
  • 高可扩展:系统间耦合低,方便的通过新增/移除方式,增加/减少新的功能/模块。
  • 安全性:提供网站安全访问和数据加密,安全存储等策略。
  • 敏捷性:随需应变,快速响应。

4.架构演进

单一应用架构:

当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。

垂直应用架构:

当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的 Web 框架(MVC)是关键。

分布式服务架构:

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。

流动计算架构:

当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

image-20230519185318252

image-20230519200036312

5.SOA 架构

  • SOA:(Service-Oriented Architecture,面向服务的架构)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和契约联系起来。
  • ESB:(Enterparise Servce Bus) 企业服务总线,服务中介。主要是提供了一个服务于服务之间的交互。ESB 包含的功能如:负载均衡,流量控制,加密处理,服务的监控,异常处理,监控告急等等。

image-20230519185514617

6.集群和分布式

  • 集群:很多“人”一起 ,干一样的事。
    • 一个业务模块,部署在多台服务器上。
  • 分布式:很多“人”一起,干不一样的事。这些不一样的事,合起来是一件大事。
    • 一个大的业务系统,拆分为小的业务模块,分别部署在不同的机器上。

image-20230519185132844

image-20230519185205728

7.RPC 与 REST

  • 应用级的 RPC 框架:Dubbo、Google gRPC
  • 通信框架:Netty
  • 远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)

image-20230519202417668

8.RPC 框架

RPC 的调用流程:

  1. 服务消费者(Client 客户端)通过本地调用的方式调用需要消费的服务

  2. 客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体

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

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

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

  6. 服务端(Server)执行具体的业务逻辑,并将处理结果返回给服务端存根(Server Stub)

  7. 服务端存根(Server Stub)将返回结果序列化,并通过网络发送给消费方

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

  9. 服务消费方得到最终结果;

img

二.dubbo 入门

1.dubbo 概念

Dubbo(读音[ˈdʌbəʊ])是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成。

  • Dubbo 是阿里巴巴公司开源的一个高性能、轻量级的 Java RPC 框架。
  • 致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。
  • Dubbo 官方推荐使用 Zookeeper 作为注册中心
  • 官网:http://dubbo.apache.org

Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:

  • 面向接口的远程方法调用,
  • 智能容错和负载均衡,
  • 以及服务自动注册和发现

2.dubbo 架构图

节点角色说明:

节点角色说明
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心
Container服务运行容器

其实 Dubbo 的架构也是很简单的(其实现细节是复杂的),为什么这么说呢,有没有发现,其实很像生产者-消费者模型。只是在这种模型上,加上了注册中心和监控中心,用于管理提供方提供的url,以及管理整个过程。``

image-20230519202718998

那么,整个发布-订阅的过程就非常的简单了。

  • 启动容器,加载,运行服务提供者
  • 服务提供者在启动时,在注册中心发布注册自己提供的服务
  • 服务消费者在启动时,在注册中心订阅自己所需的服务

如果考虑失败或变更的情况,就需要考虑下面的过程。

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

3.dubbo-admin

核心功能:

  • 查询服务、应用或机器状态

  • 创建项目、服务测试、文档管理等

  • 查看集群实时流量、定位异常问题等

  • 流量比例分发、参数路由等流量管控规则下发

  • 路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能

image-20230523150103393

4.dubbo 协议

dubbo 暴露的 url

dubbo://10.57.242.17:20880/com.yuanzi.dubbo.ProviderService?
anyhost=true
&application=provider
&bean.name=com.yuanzi.dubbo.ProviderService
&bind.ip=10.57.242.17
&bind.port=20880
&dubbo=2.0.2
&generic=false
&interface=com.yuanzi.dubbo.ProviderService
&methods=SayHello
&owner=yuanzi
&pid=85445
&qos.accept.foreign.ip=false
&qos.enable=true
&qos.port=55555
&side=provider
&timestamp=1622446147717

5.配置名称

标签用途解释
dubbo:service/服务配置用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心
dubbo:reference/引用配置用于创建一个远程服务代理,一个引用可以指向多个注册中心
dubbo:protocol/协议配置用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受
dubbo:application/应用配置用于配置当前应用信息,不管该应用是提供者还是消费者
dubbo:module/模块配置用于配置当前模块信息,可选
dubbo:registry/注册中心配置用于配置连接注册中心相关信息
dubbo:monitor/监控中心配置用于配置连接监控中心相关信息,可选
dubbo:provider/提供方配置当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选
dubbo:consumer/消费方配置当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选
dubbo:method/方法配置用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息
dubbo:argument/参数配置用于指定方法参数配置

6.配置覆盖关系

以 timeout 为例,下图显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似:

  • 方法级优先,接口级次之,全局配置再次之。
  • 如果级别一样,则消费方优先,提供方次之。

其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。

image-20230519200827390

但是这里有一个问题:建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的超时设置

7.@EnableDubbo 分析

  • 通过 @EnableDubbo 指定在 com.yuanzi.dubbo.provider.service.annotation 下扫描所有标注有 @Service 的类

  • 通过 @Configuration 将 DubboConfiguration 中所有的 @Bean 通过 Java Config 的方式组装出来并注入给 Dubbo 服务,也就是标注有 @Service 的类。这其中就包括了:

    • ProviderConfig:服务提供方配置
    • ApplicationConfig:应用配置
    • RegistryConfig:注册中心配置
    • ProtocolConfig:协议配置
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
    @AliasFor(
        annotation = DubboComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = DubboComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};

    @AliasFor(
        annotation = EnableDubboConfig.class,
        attribute = "multiple"
    )
    boolean multipleConfig() default true;
}

8.dubbo 整体架构

  1. 服务接口层(Service):该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
  2. 配置层(Config):对外配置接口,以 ServiceConfig 和 ReferenceConfig 为中心,可以直接 new 配置类,也可以通过 spring 解析配置生成配置类。
  3. 服务代理层(Proxy):服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton,以 ServiceProxy 为中心,扩展接口为 ProxyFactory。
  4. 服务注册层(Registry):封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory、Registry 和 RegistryService。可能没有服务注册中心,此时服务提供方直接暴露服务。
  5. 集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster、Directory、Router 和 LoadBalance。将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。
  6. 监控层(Monitor):RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory、Monitor 和 MonitorService。
  7. 远程调用层(Protocol):封将 RPC 调用,以 Invocation 和 Result 为中心,扩展接口为 Protocol、Invoker 和 Exporter。Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
  8. 信息交换层(Exchange):封装请求响应模式,同步转异步,以 Request 和 Response 为中心,扩展接口为 Exchanger、ExchangeChannel、ExchangeClient 和 ExchangeServer。
  9. 网络传输层(Transport):抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel、Transporter、Client、Server 和 Codec。
  10. 数据序列化层(Serialize):可复用的一些工具,扩展接口为 Serialization、 ObjectInput、ObjectOutput 和 ThreadPool。

image-20230519203000080

9.dubbo 远程调用

  1. 首先服务提供者会启动服务,然后将服务注册到服务注册中心;
  2. 服务消费者会定时拉取服务提供者列表;
  3. 当服务消费者需要调用服务提供者接口的时候,因为他不能直接远程调用提供者的接口,所以需要生成一个动态代理对象,然后通过这个代理对象去调用远程接口。
  4. 生成代理对象之后会走到 Cluster 层,这里会获取服务提供者列表的数据,感知到目前所能调用的服务提供者有哪些;
  5. 然后 Cluster 会根据指定的算法做负载均衡,选出要调用的服务提供者;
  6. 选择好服务提供者之后,再选择指定的协议格式;
  7. Exchange 会根据指定的协议格式进行请求数据封装,封装成 request 请求;
  8. 请求封装好之后,就会通过网络通信框架,将请求发送出去;
  9. 服务提供者那边同样会有网络通信框架,他会监听指定的端口号,当接收到请求之后会将请求进行反序列化;
  10. 反序列化之后,再根据 Exchange 根据指定协议格式将请求解析出来; 11.然后再通过动态代理对象调用服务提供者的对应接口。

image-20230519203412398

三.官网学习

1.工作原理

下图是 Dubbo 的工作原理图,从抽象架构上分为两层:服务治理抽象控制面Dubbo 数据面

  • 服务治理控制面。服务治理控制面不是特指如注册中心类的单个具体组件,而是对 Dubbo 治理体系的抽象表达。控制面包含协调服务发现的注册中心、流量管控策略、Dubbo Admin 控制台等,如果采用了 Service Mesh 架构则还包含 Istio 等服务网格控制面。

  • Dubbo 数据面

    。数据面代表集群部署的所有 Dubbo 进程,进程之间通过 RPC 协议实现数据交换,Dubbo 定义了微服务应用开发与调用规范并负责完成数据传输的编解码工作。

    • 服务消费者 (Dubbo Consumer),发起业务调用或 RPC 通信的 Dubbo 进程
    • 服务提供者 (Dubbo Provider),接收业务调用或 RPC 通信的 Dubbo 进程

image-20230523144855203

2.通信协议

Dubbo 从设计上不绑定任何一款特定通信协议,HTTP/2、REST、gRPC、JsonRPC、Thrift、Hessian2 等几乎所有主流的通信协议,Dubbo 框架都可以提供支持。 这样的 Protocol 设计模式给构建微服务带来了最大的灵活性,开发者可以根据需要如性能、通用型等选择不同的通信协议,不再需要任何的代理来实现协议转换,甚至你还可以通过 Dubbo 实现不同协议间的迁移。

image-20230523145125335

总的来说,Dubbo 对通信协议的支持具有以下特点:

  • 不绑定通信协议
  • 提供高性能通信协议实现
  • 支持流式通信模型
  • 不绑定序列化协议
  • 支持单个服务的多协议暴露
  • 支持单端口多协议发布
  • 支持一个应用内多个服务使用不同通信协议

3.服务治理

以下展示了 Dubbo 核心的服务治理功能定义

image-20230523145846481

  • 地址发现

Dubbo 服务发现具备高性能、支持大规模集群、服务级元数据配置等优势,默认提供 Nacos、Zookeeper、Consul 等多种注册中心适配,与 Spring Cloud、Kubernetes Service 模型打通,支持自定义扩展。

  • 负载均衡

Dubbo 默认提供加权随机、加权轮询、最少活跃请求数优先、最短响应时间优先、一致性哈希和自适应负载等策略

  • 流量路由

Dubbo 支持通过一系列流量规则控制服务调用的流量分布与行为,基于这些规则可以实现基于权重的比例流量分发、灰度验证、金丝雀发布、按请求参数的路由、同区域优先、超时配置、重试、限流降级等能力。

  • 链路追踪

Dubbo 官方通过适配 OpenTelemetry 提供了对 Tracing 全链路追踪支持,用户可以接入支持 OpenTelemetry 标准的产品如 Skywalking、Zipkin 等。另外,很多社区如 Skywalking、Zipkin 等在官方也提供了对 Dubbo 的适配。

  • 可观测性

Dubbo 实例通过 Prometheus 等上报 QPS、RT、请求次数、成功率、异常次数等多维度的可观测指标帮助了解服务运行状态,通过接入 Grafana、Admin 控制台帮助实现数据指标可视化展示。

Dubbo 服务治理生态还提供了对 API 网关限流降级数据一致性认证鉴权等场景的适配支持。

4.SpringCloud 和 dubbo

Dubbo 和 Spring Cloud 有很多相似之处,它们都在整个架构图的相同位置并提供一些相似的功能。

  • Dubbo 和 Spring Cloud 都侧重在对分布式系统中常见问题模式的抽象(如服务发现、负载均衡、动态配置等),同时对每一个问题都提供了配套组件实现,形成了一套微服务整体解决方案,让使用 Dubbo 及 Spring Cloud 的用户在开发微服务应用时可以专注在业务逻辑开发上。
  • Dubbo 和 Spring Cloud 都完全兼容 Spring 体系的应用开发模式,Dubbo 对 Spring 应用开发框架、Spring Boot 微服务框架都做了很好的适配,由于 Spring Cloud 出自 Spring 体系,在这一点上自然更不必多说。

image-20230523150312960

Spring Cloud 的优势在于:

  • 同样都支持 Spring 开发体系的情况下,Spring Cloud 得到更多的原生支持
  • 对一些常用的微服务模式做了抽象如服务发现、动态配置、异步消息等,同时包括一些批处理任务、定时任务、持久化数据访问等领域也有涉猎。
  • 基于 HTTP 的通信模式,加上相对比较完善的入门文档和演示 demo 和 starters,让开发者在第一感觉上更易于上手

Spring Cloud 的问题有:

  • 只提供抽象模式的定义不提供官方稳定实现,开发者只能寻求类似 Netflix、Alibaba、Azure 等不同厂商的实现套件,而每个厂商支持的完善度、稳定性、活跃度各异
  • 有微服务全家桶却不是能拿来就用的全家桶,demo 上手容易,但落地推广与长期使用的成本非常高
  • 欠缺服务治理能力,尤其是流量管控方面如负载均衡、流量路由方面能力都比较弱
  • 编程模型与通信协议绑定 HTTP,在性能、与其他 RPC 体系互通上存在障碍
  • 总体架构与实现只适用于小规模微服务集群实践,当集群规模增长后就会遇到地址推送效率、内存占用等各种瓶颈的问题,但此时迁移到其他体系却很难实现
  • 很多微服务实践场景的问题需要用户独自解决,比如优雅停机、启动预热、服务测试,再比如双注册、双订阅、延迟注册、服务按分组隔离、集群容错等

而以上这些点,都是 Dubbo 的优势所在:

  • 完全支持 Spring & Spring Boot 开发模式,同时在服务发现、动态配置等基础模式上提供与 Spring Cloud 对等的能力。
  • 是企业级微服务实践方案的整体输出,Dubbo 考虑到了企业微服务实践中会遇到的各种问题如优雅上下线、多注册中心、流量管理等,因此其在生产环境的长期维护成本更低
  • 在通信协议和编码上选择更灵活,包括 rpc 通信层协议如 HTTP、HTTP/2(Triple、gRPC)、TCP 二进制协议、rest 等,序列化编码协议 Protobuf、JSON、Hessian2 等,支持单端口多协议。
  • Dubbo 从设计上突出服务服务治理能力,如权重动态调整、标签路由、条件路由等,支持 Proxyless 等多种模式接入 Service Mesh 体系
  • 高性能的 RPC 协议编码与实现,
  • Dubbo 是在超大规模微服务集群实践场景下开发的框架,可以做到百万实例规模的集群水平扩容,应对集群增长带来的各种问题
  • Dubbo 提供 Java 外的多语言实现,使得构建多语言异构的微服务体系成为可能

5.Dubbo 与 gRPC

Dubbo 与 gRPC 最大的差异在于两者的定位上:

  • gRPC 定位为一款 RPC 框架,Google 推出它的核心目标是定义云原生时代的 rpc 通信规范与标准实现;
  • Dubbo 定位是一款微服务开发框架,它侧重解决微服务实践从服务定义、开发、通信到治理的问题,因此 Dubbo 同时提供了 RPC 通信、与应用开发框架的适配、服务治理等能力。

Dubbo 不绑定特定的通信协议,即 Dubbo 服务间可通过多种 RPC 协议通信并支持灵活切换。因此,你可以在 Dubbo 开发的微服务中选用 gRPC 通信,Dubbo 完全兼容 gRPC,并将 gRPC 设计为内置原生支持的协议之一

6.流量管控

可以基于 Dubbo 支持的流量管控规则实现微服务场景中更丰富的流量管控,如:

  • 动态调整超时时间
  • 服务重试
  • 访问日志
  • 同区域优先
  • 灰度环境隔离
  • 参数路由
  • 按权重比例分流
  • 金丝雀发布
  • 服务降级
  • 实例临时拉黑
  • 指定机器导流

通常,在 Dubbo 中,多个路由器组成一条路由链共同协作,前一个路由器的输出作为另一个路由器的输入,经过层层路由规则筛选后,最终生成有效的地址集合。

  • Dubbo 中的每个服务都有一条完全独立的路由链,每个服务的路由链组成可能不通,处理的规则各异,各个服务间互不影响。
  • 对单条路由链而言,即使每次输入的地址集合相同,根据每次请求上下文的不同,生成的地址子集结果也可能不同。

image-20230523153116496

  • 标签路由规则
  • 条件路由规则
  • 动态配置规则
  • 脚本路由规则

7.扩展适配

Dubbo 扩展能力使得 Dubbo 项目很方便的切分成一个一个的子模块,实现热插拔特性。用户完全可以基于自身需求,替换 Dubbo 原生实现,来满足自身业务需求。

  • 协议与编码扩展。通信协议、序列化编码协议等
  • 流量管控扩展。集群容错策略、路由规则、负载均衡、限流降级、熔断策略等
  • 服务治理扩展。注册中心、配置中心、元数据中心、分布式事务、全链路追踪、监控系统等
  • 诊断与调优扩展。流量统计、线程池策略、日志、QoS 运维命令、健康检查、配置加载等

image-20230523153537456

扩展支持:

以夏是按架构层次划分的 Dubbo 内的一些核心扩展点定义及实现,从三个层次来展开:

  • 协议通信层
  • 流量管控层
  • 服务治理层

image-20230523153654384

image-20230523221636309

三.特色

1.序列化

  • dubbo 内部已经将序列化和反序列化的过程内部封装了
  • 我们只需要在定义 pojo 类时实现 Serializable 接口即可
  • 一般会定义一个公共的 pojo 模块,让生产者和消费者都依赖该模块。

image-20230519190234290

2.地址缓存

注册中心挂了,服务是否可以正常访问?

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

3.超时与重试

@Service
public class OrderServiceImpl implements OrderService {
    /**
     * 调用远程接口,指定接口,关闭自启动检查,失败重试3次
     */
    @DubboReference(interfaceClass = UserService.class, check = false, retries = 3, 						timeout = 5000)
    UserService userService;

    @Override
    public List<UserAddress> initOrder(String userId) {
        return userService.getUserAddressList(userId);
    }
}
  • 服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去。
  • 在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
  • dubbo 利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
  • 使用 timeout 属性配置超时时间,默认值 1000,单位毫秒。
  • 设置了超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
  • 如果出现网络抖动,则这一次请求就会失败。
  • Dubbo 提供重试机制来避免类似问题的发生。
  • 通过 retries 属性来设置重试次数。默认为 2 次。

image-20230519190350985

4.灰度发布

  • 灰度发布:当出现新功能时,会让一部分用户先使用新功能,用户反馈没问题时,再将所有用户迁移到新功能。
  • dubbo 中使用 version 属性来设置和调用同一个接口的不同版本
  • 不同的服务是有版本不同的,版本可以更新并且升级,同时,不同的版本之间是不可以调用的。
@Service
public class OrderServiceImpl implements OrderService {
    /**
     * 调用远程接口,指定接口,关闭自启动检查,version=*,表示随机调用,新版本和旧版本都可调用
     */
    @DubboReference(interfaceClass = UserService.class, check = false, version = "*")
    UserService userService;


    @Override
    public List<UserAddress> initOrder(String userId) {
        return userService.getUserAddressList(userId);
    }
}

image-20230519190618905

5.负载均衡

负载均衡策略(4 种)

  • Random :按权重随机,默认值。按权重设置随机概率。
  • RoundRobin :按权重轮询。
  • LeastActive:最少活跃调用数,相同活跃数的随机。
  • ConsistentHash:一致性 Hash,相同参数的请求总是发到同一提供者。
@DubboReference(check = false, loadbalance = LoadbalanceRules.RANDOM)
UserService userService;

image-20230519190648635

6.集群容错

集群容错模式:

集群模式说明场景
Failover Cluster失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。
Failfast Cluster快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster失败安全,出现异常时,直接忽略。
Failback Cluster失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
Broadcast Cluster广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
/**
Broadcast Cluster 配置 broadcast.fail.percent。
broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常,不再调用其他节点。
*/
@reference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"})

image-20230519190806146

7.服务降级

image-20230519190851039

8.启动时检查

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

但是,有的时候,我们并不是都需要启动时就检查的,比如测试的时候,我们是需要更快速的启动,所以,这种场景的时候,我们是需要关闭这个功能的。

@Service
public class OrderServiceImpl implements OrderService {
    /**
     * 调用远程接口,指定接口,关闭自启动检查
     */
    @DubboReference(interfaceClass = UserService.class, check = false)
    UserService userService;

    @Override
    public List<UserAddress> initOrder(String userId) {
        return userService.getUserAddressList(userId);
    }
}

9.多协议支持

在前面我们使用的协议都是 dubbo 协议,但是 dubbo 除了支持这种协议外还支持其他的协议,

比如,rmi、hessian 等,另外,而且还可以用多种协议同时暴露一种服务。

通信协议说明
dubbo://tcp 长连接
rmi://tcp 短连接
hessian://http 短连接
webservice://http 段连接
thrift://Thrift 是 FaceBook 捐给 Apache 的一个 RPC 框架
grpc://谷歌的 grpc, 支持 HTTP/2 通信
redis://Redis 是一个高效的 KV 存储服务器
memcahed://memcahed 是一个高效的 KV 存储服务器
rest://JAX-RS 2.0 实现的 rest 调用

10.直连

现象:zookeeper 注册中心宕机,还可以消费 dubbo 暴露的服务。

OrderServiceImpl 配置

@Service
public class OrderServiceImpl implements OrderService {
    /**
     * 调用远程接口,关闭自启动检查,跳过注册中心
     */
    @DubboReference(check = false, url = "127.0.0.1:20882")
    UserService userService;


    @Override
    public List<UserAddress> initOrder(String userId) {
        return userService.getUserAddressList(userId);
    }
}

11.特色汇总

在 Dubbo 服务消费中,核心概念主要包括:

  1. 服务消费者:使用 Dubbo 框架调用服务的应用程序。
  2. 服务提供者列表:Dubbo 注册中心注册的可用服务提供者列表,服务消费者通过负载均衡选择其中一个服务提供者调用。
  3. 注册中心:服务提供者将自己注册到注册中心,服务消费者通过注册中心获得可用服务提供者列表。
  4. 负载均衡:在服务提供者列表中选择一个服务提供者,用于负责处理服务调用。
  5. 服务代理:Dubbo 消息代理将服务请求转发给服务提供者。
  6. 超时与重试:在特定的时间内等待服务提供者返回结果,如果等待时间超过指定的时间,则将重试服务提供者列表中的其他服务提供者。
  7. 熔断:Dubbo 在一段时间内检查服务提供者的状态,如果服务提供者的调用失败率超过阈值,则断开对该服务提供者的调用。
  8. 降级:当服务提供者无法正常提供服务时,Dubbo 会将服务降级为备用服务,保证服务可用性。

四.dubbo admin

1.什么是 dubbo-admin

dubbo-admin 是一个前后端分离的项目。前端使用 vue,后端使用 springboot,安装 dubbo-admin 其实就是部署该项目,dubbo-admin 是一个十分方便的工具。我们将 dubbo-admin 安装到开发环境上。要保证开发环境有 jdk,maven,nodejs

2.下载 Dubbo-Admin

下载地址

3.修改配置

在 dubbo-admin-server\src\main\resources 目录下,找到 application.properties

修改 zookeeper 地址

admin.registry.address=zookeeper://120.79.36.53:2181
admin.config-center=zookeeper://120.79.36.53:2181
admin.metadata-report.address=zookeeper://120.79.36.53:2181
  • admin.registry.address 注册中心

  • admin.config-center 配置中心

  • admin.metadata-report.address 元数据中心

4.打包启动

在 dubbo-admin-develop 目录执行打包命令

#打包
mvn  clean package

#启动
java -jar  dubbo-admin-0.1.jar
#启动:
DubboAdminApplication

image-20230519192842810

5.部署前端

在 dubbo-admin-ui 目录下执行命令

#构建
npm install

#没有权限的话用这个
sudo npm install

#启动
sudo npm run dev

#验证 用户名密码都是 root
localhost:8081

image-20230519194827975

6.使用

首页:

image-20230519194850131

启动服务:

image-20230519195025270

服务查询:

image-20230519195142248

在线测试接口:

image-20230519195302357

服务治理:

image-20230519195344688

服务统计:

image-20230519195521061

五.Java Api

1.接口模块

//用户接口
public interface UserService {
    int getCount();//获取当前网站在线人数
}
//枚举
public enum ResultConstant {
    /**
     * 系统异常
     */
    ERROR("-1", "系统异常"),
    /**
     * ok
     */
    SUCCESS("0", "ok");
    private String code;
    private String msg;

    private ResultConstant(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return this.code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return this.msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
//结果集
public class Payload<T> implements Serializable {
    private static final long serialVersionUID = -1549643581827130116L;
    private T payload;
    private String code;
    private String msg;

    public Payload() {
        this.code = ResultConstant.SUCCESS.getCode();
        this.msg = ResultConstant.SUCCESS.getMsg();
    }

    public Payload(T payload) {
        this.code = ResultConstant.SUCCESS.getCode();
        this.msg = ResultConstant.SUCCESS.getMsg();
        this.payload = payload;
    }

    public Payload(String code, String msg) {
        this.code = ResultConstant.SUCCESS.getCode();
        this.msg = ResultConstant.SUCCESS.getMsg();
        this.code = code;
        this.msg = msg;
    }

    public Payload(T payload, String code, String msg) {
        this.code = ResultConstant.SUCCESS.getCode();
        this.msg = ResultConstant.SUCCESS.getMsg();
        this.payload = payload;
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return this.code;
    }

    public String getMsg() {
        return this.msg;
    }

    public T getPayload() {
        return this.payload;
    }

    public boolean success() {
        return this.getCode().equals("0");
    }
}

2.服务端

pom:

<dependencies>
    <dependency>
        <groupId>org.kwan.shuyu</groupId>
        <artifactId>dubbo-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>5.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>5.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-x-discovery</artifactId>
        <version>5.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.0.7</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.0.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.0.1.RELEASE</version>
    </dependency>
</dependencies>

yml:

server:
  port: 8081
spring:
  application:
    name: dobbo-service

dubbo:
  registry:
    address: 120.79.36.53:2181,120.79.36.53:2182,120.79.36.53:2183
    protocol: zookeeper

management:
  endpoints:
    web:
      exposure:
        include: "*"

启动类:

@EnableDubbo
@SpringBootApplication
public class DubboServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DubboServerApplication.class, args);
    }
}

实现类:

@DubboService(interfaceClass = UserService.class)
public class UserServiceImpl implements UserService {

    @Override
    public int getCount() {
        //调用数据持久层
        return 1024;
    }
}

3.客户端

pom:

<dependencies>
    <dependency>
        <groupId>org.kwan.shuyu</groupId>
        <artifactId>dubbo-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>5.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>5.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-x-discovery</artifactId>
        <version>5.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.0.7</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.0.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.0.1.RELEASE</version>
    </dependency>
</dependencies>

yml:

server:
  port: 8083
spring:
  application:
    name: dobbo-client

dubbo:
  protocol:
    name: dubbo
    port: 20881
  registry:
    address: zookeeper://120.79.36.53:2181

management:
  endpoints:
    web:
      exposure:
        include: "*"

启动类:

@EnableDubbo
@SpringBootApplication
public class DubboClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(DubboClientApplication.class, args);
    }
}

控制层:

@RestController
@RequestMapping("/user")
public class UserController {

    @DubboReference(interfaceClass = UserService.class, check = false)
    private UserService userService;

    @RequestMapping("/count")
    public Payload<String> getCount() {
        int count = userService.getCount();
        return new Payload("当前在线的人数为:" + count);
    }
}

4.验证

postman 验证

image-20230518124206979

觉得有用的话点个赞 👍🏻 呗。

❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

Logo

前往低代码交流专区

更多推荐