INDEX
- §1 Dubbo 与 web 容器的关系
- §2 注册发现流程
- §3 服务配置
- §3.1 注册方式 & 订阅方式
- §3.2 服务导出
- §3.3 配置参数
- §4 底层技术
- §4.1 Dubbo 的 spi 机制
- §4.2 Dubbo 的线程池
- §4.3 Dubbo 的负载均衡策略
- §4.3 Dubbo 的协议
§1 Dubbo 与 web 容器的关系
- dubbo 本质上是一个 RPC 框架,常用于服务间调用
- web 容器是服务的容器,主要用来响应 http 请求
- dubbo 和 web 没有直接联系,dubbo 也不依赖于 web 容器
§2 注册发现流程
无论 provider 还是 consumer
- 都被容器代理
- 都通过协议与注册中心交互
工作流程
- provider 向注册中心注册自己
- consumer 向注册中心订阅服务
- Dubbo 默认在启动时开启服务可用性检查
若 provider 无可用节点会启动失败,报No provider available for the service ...
也可以通过配置@DubboReference(check=false)
关闭这个特性
- Dubbo 默认在启动时开启服务可用性检查
- 注册中心定时通知 consumer 服务变更
- comsumer 通过订阅到的信息调用服务
- Dubbo 启动后,若注册中心宕机,不影响 consumer 调用 provider
因为调用是依赖 consumer 订阅的服务信息,consumer 会有本地缓存
- Dubbo 启动后,若注册中心宕机,不影响 consumer 调用 provider
- privider/comsumer 统计自己的调用次数、调用时间,每分钟通知 monitor
§3 服务配置
§3.1 注册方式 & 订阅方式
版本 | 注册中心 | 配置方式 |
---|---|---|
< 2.7 | zk | 接口注册 |
> 2.7 | zk / nacos | 接口注册 |
>= 2.7.6 | zk / nacos | 接口注册/应用注册 |
> 3 | zk / nacos2.0 | 接口注册/应用注册 |
Dubbo 2.7.6 开始,支持 3 种注册方式
- interface,经典配置方式,接口级注册
- instance,新配置方式,应用级注册,可以有效减少注册信息
- all,即 interface + instance,默认,便于服务迁移
与之相对的,Dubbo 的订阅方式也有 3 种
- FORCE_INTERFACE:只按接口级注册消费
- FORCE_INSTANCE:只按应用级注册消费
- APPLICATION_FIRST:默认,优先按应用级注册消费
§3.2 服务导出
Dubbo 的服务导出机制,其实就是从服务启动到注册到注册中心的过程,在官网有详细解释(放心看,中文的)
Dubbo 3.0
Spring 启动后发送的 ContextRefreshEvent
事件,
Dubbo 会通过 DubboDeployApplicationListener
监听这个事件,
并通过 DefaultModuleDeploy.startSync()
开始同步
Dubbo 2.7
入口在 ServiceBean.onApplicationEvent(ContextRefreshEvent event)
,分为如下几步
- 前置准备
- 配置检查
- 检查
<dubbo:service interface>
属性 ProviderConfig
、ApplicationConfig
等配置对象- 检查泛化服务与普通服务
- 检查本地存根配置
ApplicationConfig
、RegistryConfig
等配置对象
- 检查
- 多协议多配置中心导出支持
- URL 装配:主要是找到、适配各种参数
- 配置检查
- 导出服务
- 创建
Invoker
,这是 Dubbo 的核心模块,所有组件都是以此为核心的 - 根据配置
scope
参数决定是导出到本地还是远端- 导出到本地时,仅通过
InjvmProtocol.export
创建InjvmExporter
- 导出到远端时
- 调用
doLocalExport
导出服务 - 向注册中心注册
- 向注册中心订阅 override 数据
- 创建并返回
DestroyableExporter
- 调用
- 导出到本地时,仅通过
- 创建
- 服务注册
- 根据 url 从缓存获取注册器,如果没有就创建并加入缓存
- 连接注册中心服务,创建注册中心客户端对象
- 通过注册中心客户端对象向注册中心创建节点(写入节点数据)
§3.3 配置参数
@DubboReference(check=false)
关闭 consumer 启动时检查 provider 是否可用
当不配置时,若 provider 无可用节点会报 No provider available for the service ...
启动失败
@DubboServide(group="xx")
@DubboReference(group="xx")
同接口多实现配置,消费者只会调用同组提供者
@DubboServide(version="xx")
@DubboReference(version="xx")
同接口有多个版本需要兼容,消费者只会调用同组提供者
§4 底层技术
§4.1 Dubbo 的 spi 机制
spi 是 JDK 已经实现了的规范,Dubbo 独立实现了一套
其目的在于在多实现接口中仅实例化需要的实现
§4.2 Dubbo 的线程池
线程池位置
线程池类型
- fixed:固定大小线程池,启动时建立线程,不关闭,一直持有,默认
- cached:缓存线程池,空闲一分钟自动删除,需要时重建。
任务数量超过maximumPoolSize
时直接抛出异常而不是将任务放入阻塞队列 - limited:可伸缩线程池,但池中的线程数只会增长不会收缩。
只增长不收缩的目的是为了避免收缩时突然来了大流量引起的性能问题。 - eager:优先创建Worker线程池。
在任务数量大于corePoolSize
但是小于maximumPoolSize
时,优先创建Worker来处理任务。
当任务数量大于maximumPoolSize
时,将任务放入阻塞队列中。阻塞队列充满时抛出RejectedExecutionException
线程池满载
dubbo 的线程池是在服务节点上全服务共享的,默认最大线程数 200,超出后会拒绝请求并提示类似如下信息:
Server side(ip,port) thread pool is exhausted, detail msg: Thread pool is EXHAUSTED! Thread name: xx-ip:port, Pool Size: 200(active: 200,core: 200, max: 200,largest:200), Task 207(completed: 7), Executor status: (isShutdown: false, isTerminated:false, isTerminating:false), in dubbo:ip:port
解决方式:
- 优化逻辑链路,降低处理时间
- 增加服务节点
- 服务拆分,剥离专享节点给流量极大服务
- 服务限流,配合链路限流模式
§4.3 Dubbo 的负载均衡策略
官网原文在此,中文的,随便看
- random:加权随机,默认
- round-robin:加权轮询,按服务节点新能进行加权
- least-active:最小活跃数,活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求
- consistent-hash:一致性 hash,直接确定了 provider 和 consumer 的对应关系
- shortest-response:加权最短响应
- P2C:随机挑选两个节点,然后选择连接数小的
- adaptive:随机挑选两个节点,然后选择负载小的
§4.3 Dubbo 的协议
基于 http 的
- dubbo
- hessian
- http
基于缓存的
- redis
- memcached
基于二进制序列化的(快)
- thrift
- gRPC
基于 java 规范的
- rest
- rmi
- webservice