Dubbo与Zookeeper
Dubbo与Zookeeper
CalyeeDubbo
Dubbo官网 Dubbo 文档 | Apache Dubbo
了解 Dubbo 核心概念和架构
以上是 Dubbo 的工作原理图,从抽象架构上分为两层:服务治理抽象控制面 和 Dubbo 数据面 。
服务治理控制面。服务治理控制面不是特指如注册中心类的单个具体组件,而是对 Dubbo 治理体系的抽象表达。控制面包含协调服务发现的注册中心、流量管控策略、Dubbo Admin 控制台等,如果采用了 Service Mesh 架构则还包含 Istio 等服务网格控制面。
Dubbo 数据面
。数据面代表集群部署的所有 Dubbo 进程,进程之间通过 RPC 协议实现数据交换,Dubbo 定义了微服务应用开发与调用规范并负责完成数据传输的编解码工作。
- 服务消费者 (Dubbo Consumer),发起业务调用或 RPC 通信的 Dubbo 进程
- 服务提供者 (Dubbo Provider),接收业务调用或 RPC 通信的 Dubbo 进程
Dubbo 数据面
从数据面视角,Dubbo 帮助解决了微服务实践中的以下问题:
- Dubbo 作为 服务开发框架 约束了微服务定义、开发与调用的规范,定义了服务治理流程及适配模式
- Dubbo 作为 RPC 通信协议实现 解决服务间数据传输的编解码问题
服务开发框架
微服务的目标是构建足够小的、自包含的、独立演进的、可以随时部署运行的分布式应用程序,几乎每个语言都有类似的应用开发框架来帮助开发者快速构建此类微服务应用,比如 Java 微服务体系的 Spring Boot,它帮 Java 微服务开发者以最少的配置、最轻量的方式快速开发、打包、部署与运行应用。
微服务的分布式特性,使得应用间的依赖、网络交互、数据传输变得更频繁,因此不同的应用需要定义、暴露或调用 RPC 服务,那么这些 RPC 服务如何定义、如何与应用开发框架结合、服务调用行为如何控制?这就是 Dubbo 服务开发框架的含义,Dubbo 在微服务应用开发框架之上抽象了一套 RPC 服务定义、暴露、调用与治理的编程范式,比如 Dubbo Java 作为服务开发框架,当运行在 Spring 体系时就是构建在 Spring Boot 应用开发框架之上的微服务开发框架,并在此之上抽象了一套 RPC 服务定义、暴露、调用与治理的编程范式。
Dubbo 作为服务开发框架包含的具体内容如下:
- RPC 服务定义、开发范式。比如 Dubbo 支持通过 IDL 定义服务,也支持编程语言特有的服务开发定义方式,如通过 Java Interface 定义服务。
- RPC 服务发布与调用 API。Dubbo 支持同步、异步、Reactive Streaming 等服务调用编程模式,还支持请求上下文 API、设置超时时间等。
- 服务治理策略、流程与适配方式等。作为服务框架数据面,Dubbo 定义了服务地址发现、负载均衡策略、基于规则的流量路由、Metrics 指标采集等服务治理抽象,并适配到特定的产品实现。
通信协议
Dubbo 从设计上不绑定任何一款特定通信协议,HTTP/2、REST、gRPC、JsonRPC、Thrift、Hessian2 等几乎所有主流的通信协议,Dubbo 框架都可以提供支持。 这样的 Protocol 设计模式给构建微服务带来了最大的灵活性,开发者可以根据需要如性能、通用型等选择不同的通信协议,不再需要任何的代理来实现协议转换,甚至你还可以通过 Dubbo 实现不同协议间的迁移。
Dubbo Protocol 被设计支持扩展,您可以将内部私有协议适配到 Dubbo 框架上,进而将私有协议接入 Dubbo 体系,以享用 Dubbo 的开发体验与服务治理能力。比如 Dubbo3 的典型用户阿里巴巴,就是通过扩展支持 HSF 协议实现了内部 HSF 框架到 Dubbo3 框架的整体迁移。
Dubbo 还支持多协议暴露,您可以在单个端口上暴露多个协议,Dubbo Server 能够自动识别并确保请求被正确处理,也可以将同一个 RPC 服务发布在不同的端口(协议),为不同技术栈的调用方服务。
Dubbo 提供了两款内置高性能 Dubbo2、Triple (兼容 gRPC) 协议实现,以满足部分微服务用户对高性能通信的诉求,两者最开始都设计和诞生于阿里巴巴内部的高性能通信业务场景。
- Dubbo2 协议是在 TCP 传输层协议之上设计的二进制通信协议
- Triple 则是基于 HTTP/2 之上构建的支持流式模式的通信协议,并且 Triple 完全兼容 gRPC 但实现上做了更多的符合 Dubbo 框架特点的优化。
总的来说,Dubbo 对通信协议的支持具有以下特点:
- 不绑定通信协议
- 提供高性能通信协议实现
- 支持流式通信模型
- 不绑定序列化协议
- 支持单个服务的多协议暴露
- 支持单端口多协议发布
- 支持一个应用内多个服务使用不同通信协议
Dubbo 服务治理
服务开发框架解决了开发与通信的问题,但在微服务集群环境下,我们仍需要解决无状态服务节点动态变化、外部化配置、日志跟踪、可观测性、流量管理、高可用性、数据一致性等一系列问题,我们将这些问题统称为服务治理。
Dubbo 抽象了一套微服务治理模式并发布了对应的官方实现,服务治理可帮助简化微服务开发与运维,让开发者更专注在微服务业务本身。
服务治理抽象
以下展示了 Dubbo 核心的服务治理功能定义
- 地址发现
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 网关、限流降级、数据一致性、认证鉴权等场景的适配支持。
Dubbo Admin
Admin 控制台提供了 Dubbo 集群的可视化视图,通过 Admin 你可以完成集群的几乎所有管控工作。
- 查询服务、应用或机器状态
- 创建项目、服务测试、文档管理等
- 查看集群实时流量、定位异常问题等
- 流量比例分发、参数路由等流量管控规则下发
服务网格
将 Dubbo 接入 Istio 等服务网格治理体系。
编码实现
代码结构及其专业术语
我们需要编码开发之前,需要了解代码结构及其专业术语
- provider 功能提供者
- consumer 功能消费者 [功能调用者]
- commons-api 通用内容 entity+service接口
- registry 注册中心 (服务注册 可使用Nacos/Zookeeper)
注册中心的作用就是管理provider和consumer的集群的,方便后续的水平拓展。可以进行健康检查,检查provider是否可以正常健康,保证服务提供正常强大的服务。
环境搭建
JDK17,dubbo3.2.0
1 | <dependencies> |
其中项目结构为:
1 | dubbo |
Provider
在common下创建entity.user类,并且添加业务接口 UserService (里面创建方法login),在·dubbo-provider·下创建UserServiceImpl并且实现UserService 接口
在dubbo-provider的resource下创建spring.xml(applicationContext-provider.xml)
1 |
|
在provider创建主函数入口ProviderApplication
1 | public class ProviderApplication { |
最核心的是最后一行,最后一行一出现,代表我们的Dubbo服务一定启动好,可以对外提供服务了
关键日志分析:
1 | 22:03:05.432 [main] INFO org.apache.dubbo.config.deploy.DefaultApplicationDeployer - [DUBBO] Dubbo Application[1.1](dubbo-provider) is ready., dubbo version: 3.2.0, current host: 172.18.83.51 |
其中还有日志 (截取主要的,次要在此不列出)
1 | 22:03:05.271 [main] INFO org.apache.dubbo.config.ServiceConfig - [DUBBO] Export dubbo service com.calyee.service.UserService to local registry url : injvm://127.0.0.1/com.calyee.service.UserService?anyhost=true&application=dubbo-provider&background=false&bind.ip=172.18.83.51&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&exporter.listener=injvm&file-cache=true&generic=false&interface=com.calyee.service.UserService&methods=login&pid=2856&prefer.serialization=fastjson2,hessian2&release=3.2.0&side=provider×tamp=1713362584412, dubbo version: 3.2.0, current host: 172.18.83.51 |
那么当前的服务已经可以提供服务了(后续consumer需要使用该段内容),Export 导出、暴露 Dubbo服务这个接口到如下的URL地址:dubbo是协议名:ip端口号,后面是具体的接口地址。
Consumer
其中Consumer的创建和Provider大同小异,首先都需要导入公共模块
applicationContext-consumer.xml
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
测试
1 | public class ClientApplication { |
消费者控制台
1 | 22:18:18.218 [main] DEBUG org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult - [DUBBO] Decoding in thread -- [main#1], dubbo version: 3.2.0, current host: 172.18.83.51 |
服务提供者控制台
1 | 22:18:18.207 [DubboServerHandler-172.18.83.51:20880-thread-5] DEBUG org.apache.dubbo.remoting.transport.DecodeHandler - [DUBBO] Decode decodeable message org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation, dubbo version: 3.2.0, current host: 172.18.83.51 |
消费者端 Qos问题报错
Qos:Quality of Service
1 | 22:18:17.351 [main] ERROR org.apache.dubbo.qos.server.Server - [DUBBO] qos-server can not bind localhost:22222, dubbo version: 3.2.0, current host: 172.18.83.51, error code: 7-4. This may be caused by , go to https://dubbo.apache.org/faq/7/4 to find instructions. |
为什么会出现 22222会被占用?
Qos=Quality of Service,qos是Dubbo的在线运维命令,可以对服务进⾏动态的配置、控制及查询,qos也是一个服务,启动需要占用端口。
Dubboo2.5.8新版本重构了telnet(telnet是从Dubbo2.0.5开始⽀持的)模块,提供了新的telnet命令⽀持,新版本的telnet端⼝与dubbo协议的端⼝是不同的端⼝,默认为22222。正是因为这个问题:如果在⼀台服务器⾥⾯,启动provider时22222端⼝,⽽consumer启动时就会报错了。
qos只要是dubbo服务,无论是消费者还是提供者都会默认启动的,只不过先启动的没问题,后启动的就不行了,端口已经被占用了。
解决方案(在consumer中加入):(此命令需要添加在application标签内部,即给容器起名的标签内)
1 | <!--是否开启在线运维命令 --> |
1 | dubbo.application.qos.enable=true |
最终:
1 | <dubbo:application name="dubbo-consumer"> |
然后再次启动则不会报错了,效果还是一样的
基于SpringBoot实现
导入依赖
(Consumer和Provider都需要导入)
1 | <dependency> |
启动类
1 |
|
Provider
application.yml
1 | spring: |
还是一样,在provider中创建UserServiceImpl
1 | // Dubbo服务标识 |
Consumer
application.yml
1 | spring: |
服务调用
1 |
|
@EnableDubbo注解的作用
- @EnableDubbo用于扫描@DubboService并把对应的对象实例化,发布成RPC服务。
扫描路径:引用这个注解的类(启动类)所在的包及其子包。
- 如果@DubboService注解修饰的类没有放到@EnableDubbo注解修饰类当前包及其子包,还希望能够扫描到它该如何处理?
@DubboComponentScan(basePackages = {}),显示的指定扫描路径
@DubboService注解的作用
- 应用@DubboService注解修饰类型,SpringBoot会创建这个类型的对象,并发布成Dubbo服务。
- @DubboService等同于@Component(@Service)@Bean注解的创建对象的作用。
通过源码SingletonObjects可以验证 - @DubboService
a.创建对象等同于@Component(@Service)@Bean
b.发布成RPC服务 - 后续开发过程中如果考虑兼容性建议实现类不仅仅要加入DubboService注解,同时也要加入**@Service**注解
@DubboReferencec注解的作用
- 在Consumer端,通过@DubboReference,注入远端服务的代理对象。
- @DubboReference类似于原始Spring开发中@Autowired注解的作用
RPC直连
前面说讲述的都是dubbo RPC直连,也就是类似于SpringCloud的OpenFeign。
在没有引入注册中心都是RPC直连。
- Provider 服务提供
- Consumer 服务消费
- 网络通信
其中服务提供和服务消费都是在不同的虚拟机,那么就需要进行网络通信
其中consume和provider之间就是通过网络通信建立的
需要完成网络通信那么不可缺少的有:
- 协议:consumer与provider在传输数据时双方的约定
- 通信方式:consumer与provider如何进行通信
- 序列化:数据的传输的一种格式
协议
网络传输过程中传输数据的一种格式约定调用者和被调用者.
其中分为:应用层协议:HTTP1.x HTTP2.x
传输层协议:私有协议 例如 dubbo: 既支持私有协议也支持共用协议HTTP
服务器(通信方式)
传输层 通信方式:BIO、NIO、Netty、Mina …
dubbo内置默认通信netty4
应用层 通信方式:Tomcat、Resin、Jetty
(可以通过transporter替换不同的通信方式<dubbo:protocol name=”dubbo” port=’’-1’’ transporter=”Xxxx”>)
序列化
数据传输格式:好序列化方案:传输的数据体量小
不好序列化方案:传输的数据居体量大默认:hassian,还是在刚刚那个标签内添加serialization即可替换。例如serialization=”hassian”
序列化
序列化:是Dubbo进行RPC中,非常重要的一个组成部分其核心作用就是把网络传输中的数据按照特定的格式进行传输。减小数据
的体积,从而提高传输效率。‘
Dubbo中序列化的实现方式
实际上,Dubbo在设计序列化的时候就定义了接口Serialization
,其就是利用SPI机制给使用者进行自定义扩展的。
其中常见的序列化方式:
Hessian Dubbo协议中默认的序列化实现方案
Java Serialization JDK序列化方式
Dubbo序列化 阿里尚未开发成熟的高效java序列化实现,阿里不建议在生产环境使用它。
Json序列化 目前有两种实现,一种是采用的阿里的fastjson库,另一种是采用dubbo中自己实现的简单json
库。Kryo Java序列化方式,后续替换Hessian2,是一种非常成熟的序列化实现,已经在Twitter、
Groupon、Yahoo以及多个著名开源项目(如Hive、Storm)中广泛的使用。FST Java序列化方式,后续替换Hessian2,是一种较新的序列化实现,目前还缺乏足够多的成熟使用
案例。跨语言序列化方式 ProtoBuf,Thrift,Avro,MsgPack(MessagePack是一种高效的二进制序列化格式。它允许您在
多种语言(如JSON)之间交换数据。但它更快更小。短整型被编码成一个字节)
如何在Boot中使用
1 | dubbo: |
SPI拓展
Dubbo SPI 扩展实现说明 | Apache Dubbo