dubbo3.0的变化:
1.服务发现模型:
2.0采用基于接口粒度的服务发现机制,3.0基于应用粒度的服务发现机制,有利于提高系统资源利用率,降低 Dubbo 地址的单机内存消耗(50%),降低注册中心集群的存储与推送压力(90%), Dubbo 可支持集群规模步入百万实例层次;
打通与其他异构微服务体系的地址互发现障碍。新模型使得 Dubbo3 能实现与异构微服务体系如Spring Cloud、Kubernetes Service、gRPC 等,在地址发现层面的互通,为连通 Dubbo 与其他微服务体系提供可行方案。
2.采用新的RPC通信协议:
Triple(基于http2构建RPC协议,兼容GRPC,扩展语义丰富),更容易于网关、mesh架构结合使用;
多语言友好,配合protubuf编码业务数据;
支持流式通信:Triple 协议支持 Request Stream、Response Stream、Bi-direction Stream
3.云原生:Dubbo3 构建的业务应用可直接部署在 Container、Kubernetes 等平台,很好的解决了 Dubbo 服务与调度平台之间的生命周期对齐,服务发现地址 与容器平台绑定的问题。
Dubbo3 规划了两种形态的 Service Mesh 方案:经典的基于 Sidecar 的 Service Mesh无 Sidecar 的 Proxyless Mesh。
4.扩展点分离:Dubbo3 的 maven 也发生了一些变化,org.apache.dubbo:dubbo:3.0.0 将不再是包含所有资源的 all-in-one 包,一些可选的依赖已经作为独立组件单独发布, 因此如果用户使用了不在 dubbo 核心依赖包中的独立组件,如 registry-etcd、rpc-hessian 等,需要为这些组件在 pom.xml 中单独增加依赖包。
5.服务柔性:
Dubbo3.0 的柔性增强以面向失败设计为理念,提供包括精准容量评估、自适应限流、自适应负载均衡的支持,自底向上的分步构建大规模可靠应用。 从单一服务的视角看,服务是压不垮的,稳定的。从分布式视角看,复杂的拓扑不会带来性能的下降,分布式负载均衡能够以最优的方式动态分配流量,保证异构系统能够根据运行时的准确服务容量合理分配请求,从而达到性能最优。
TLS 保证传输安全
dubbo访问日志:
将访问日志输出到当前应用的log4j日志:
<dubbo:protocol accesslog="true" />
将访问日志输出到指定文件:
<dubbo:protocol accesslog="http://10.20.160.198/wiki/display/dubbo/foo/bar.log" />
dubbo导出线程堆栈信息:dubbo 通过 Jstack 自动导出线程堆栈来保留现场,方便排查问题。
默认策略:
导出路径,user.home标识的用户主目录
导出间隔,最短间隔允许每隔10分钟导出一次
指定导出路径:
# dubbo.properties
dubbo.application.dump.directory=/tmp
dubbo api doc:dubbo 接口文档、测试工具,根据注解生成文档,并提供测试功能.
dubbo提供者项目引入 dubbo-api-docs-core ,dubbo-api-docs-annotations
@EnableDubboApiDocs 以启用Dubbo Api Docs功能.
@ApiModule: 类注解, dubbo接口模块信息,用于标注一个接口类模块的用途
value: 模块名称
apiInterface: 提供者实现的接口
version: 模块版本
@ApiDoc: 方法注解,dubbo 接口信息,用于标注一个接口的用途
value: 接口名称
description: 接口描述(可使用html标签)
version: 接口版本
responseClassDescription: 响应的数据的描述
@RequestParam: 类属性/方法参数注解,标注请求参数
value: 参数名
required: 是否必传参数
description: 参数描述
example: 参数示例
defaultValue: 参数默认值
allowableValues: 允许的值,设置该属性后界面上将对参数生成下拉列表
注:使用该属性后将生成下拉选择框
boolean 类型的参数不用设置该属性,将默认生成 true/false 的下拉列表
枚举类型的参数会自动生成下拉列表,如果不想开放全部的枚举值,可以单独设置此属性.
@ResponseProperty: 类属性注解, 标注响应参数
value: 参数名
example: 示例
dubbo使用seata完成对分布式事务的支持
dubbo线程模型,通过不同的派发策略和不同的线程池配置的组合来应对不同的场景。
<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
Dispatcher
all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
direct 所有消息都不派发到线程池,全部在 IO 线程上直接执行。
message 只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
execution 只有请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
connection 在 IO 线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
ThreadPool
fixed 固定大小线程池,启动时建立线程,不关闭,一直持有。(缺省)
cached 缓存线程池,空闲一分钟自动删除,需要时重建。
limited 可伸缩线程池,但池中的线程数只会增长不会收缩。只增长不收缩的目的是为了避免收缩时突然来了大流量引起的性能问题。
eager 优先创建Worker线程池。在任务数量大于corePoolSize但是小于maximumPoolSize时,优先创建Worker来处理任务。当任务数量大于maximumPoolSize时,将任务放入阻塞队列中。阻塞队列充满时抛出RejectedExecutionException。(相比于cached:cached在任务数量超过maximumPoolSize时直接抛出异常而不是将任务放入阻塞队列)
dubbo异步执行:Dubbo 服务提供方的异步执行;Provider端异步执行将阻塞的业务从Dubbo内部线程池切换到业务自定义线程,避免Dubbo线程池的过度占用,有助于避免不同服务间的互相影响。异步执行无益于节省资源或提升RPC响应性能,因为如果业务执行需要阻塞,则始终还是要有线程来负责执行。
Provider端异步执行和 Consumer 端异步调用是相互独立的,可以任意正交组合两端配置:
Consumer同步 - Provider同步
Consumer异步 - Provider同步
Consumer同步 - Provider异步
Consumer异步 - Provider异步
方法1 异步执行实现步骤:
1.定义 CompletableFuture 签名的服务接口
public interface AsyncService {
CompletableFuture<String> sayHello(String name);
}
2.服务实现:
public class AsyncServiceImpl implements AsyncService {
@Override
public CompletableFuture<String> sayHello(String name) {
RpcContext savedContext = RpcContext.getContext();
// 建议为supplyAsync提供自定义线程池,避免使用JDK公用线程池
return CompletableFuture.supplyAsync(() -> {
System.out.println(savedContext.getAttachment("consumer-key1"));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "async response from provider.";
});
}
}
通过 return CompletableFuture.supplyAsync() ,业务执行已从 Dubbo 线程切换到业务线程,避免了对 Dubbo 线程池的阻塞。
方法2异步执行实现步骤:使用AsyncContext 提供了类似 Serverlet 3.0 的异步接口AsyncContext,在没有 CompletableFuture 签名接口的情况下,也可以实现 Provider 端的异步执行。
1.服务接口定义:
public interface AsyncService {
String sayHello(String name);
}
服务暴露,和普通服务完全一致:
<bean id="asyncService" class="org.apache.dubbo.samples.governance.impl.AsyncServiceImpl"/>
<dubbo:service interface="org.apache.dubbo.samples.governance.api.AsyncService" ref="asyncService"/>
2.服务实现:
public class AsyncServiceImpl implements AsyncService {
public String sayHello(String name) {
final AsyncContext asyncContext = RpcContext.startAsync();
new Thread(() -> {
// 如果要使用上下文,则必须要放在第一句执行
asyncContext.signalContextSwitch();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 写回响应
asyncContext.write("Hello " + name + ", response from provider.");
}).start();
return null;
}
}
dubbo参数回调:通过参数回调从服务器端调用客户端逻辑
dubbo消费端线程模型:通过复用业务端被阻塞的线程,很好的解决消费端应用,当面临需要消费大量服务且并发数比较大的大流量场景时(典型如网关类场景),经常会出现消费端线程数分配过多的问题
Kubernetes生命周期对齐探针
三种探针对应的 SPI 接口如下:
livenessProbe(存活检测): org.apache.dubbo.qos.probe.LivenessProbe;由于 Dubbo 框架本身无法获取到应用的存活状态,因此本接口无默认实现,且默认返回成功。
readinessProbe(就绪检测): org.apache.dubbo.qos.probe.ReadinessProbe;目前 Dubbo 默认提供了两个检测维度,一是对 Dubbo 服务自身是否启停做判断,另外是对所有服务是否存在已注册接口,如果所有服务均已从注册中心下线(可以通过 QOS 运维进行操作)将返回未就绪的状态。
startupProbe(启动检测): org.apache.dubbo.qos.probe.StartupProbe;目前Dubbo 默认提供了一个检测维度,即是在所有启动流程(接口暴露、注册中心写入等)均结束后返回已就绪状态。