这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战
SPI
流程:
- 引入pom
- 实现接口,接口上要有@SPI,并在resource/META-INF/dubbo下建立包名.接口名的文件,并在里面按照key=value的格式维护实现类
- 加载时用ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(.class)获取扩展加载类,extensionLoader.getSupportedExtensions()就可以获取所有扩展点名称, 通过extensionLoader.getExtension(name)就可以获取所有扩展点
目的
- JDK会一次性实例化所有扩展点
- 如果有扩展点失败,所有的都无法使用
- 提供了对扩展点包装功能, 还可以通过set方式进行注入
Adaptive:
动态的选择具体的扩展点, 通过url的方式选择
过滤器
Filter机制在执行目标程序前后执行指定的代码
- 实现 org.apache.dubbo.rpc.Filter
- 添加@Activate,并通过group指定是生产端还是消费端
- 在META-INF.dubbo下建立org.apache.dubbo.rpc.Filter文件, 内容是key=包名.类名
负载均衡
dubbo提供了多种负载均衡, 包含随机,轮询, 最少调用数,一致性hash,缺省为随机。
@Reference(loadbalance="random")
@Service(loadbalance="random")
自定义:
- 实现org.apache.dubbo.rpc.cluster.loadBalance
- 在META-INF.dubbo下建立org.apache.dubbo.rpc.cluster.loadBalance文件, 内容是key=包名.类名
异步调用
消费端利用Future异步等待和获取结果, 通过XML方式导入
<dubbo:reference id="" interface="">
<dubbo:method name="" async="true"/>
</dubbo:reference>
在调用完方法后,立刻用
Future<Object> future = RpcContext.getContext().getFuture();
线程池
dubbo已有
- fix创建固定大小线程池, 默认200,没有等待队列,一般会采用
- cache: 创建非固定大小的线程池
自定义
由于使用fix线程池可能导致具体某些业务因为线程数量不足发生错误,但是业务是无感知的,只有发生错误才能发现。需要通过某些手段进行监控。
public class WatchThreadPool extends FixedThreadPool implements Runable{
private static final double ALARM_PERCENT =0.9;
private final Map<URL, ThreadPoolExecutor> THREADPOOLS = new ConcurrentHashMap<>();
public void run (){
Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(this, 1, 3, TimeUnit.SECOND);
}
public Executor getExecutor(URL url){
final Executor executor = supper.getExecutor(url);
if(executor instanceof ThreadPoolExecutor){
THREADPOOLS.put(url, (ThreadPoolExecutor)executor);
}
return executor;
}
public void run(){
for(Map.Entry<URL, ThreadPoolExecutor> entry: THREADPOOLS){
final URL url = entry.getKey();
final ThreadPoolExecutor executor = entry.getValue();
final int activeCount = executor.getActiveCount();
final int poolSize = executor.getCorePoolSize();
double usedPercent = activeCount/ poolSize;
if(usedPercent > ALARM_PERCENT){
//TODO 日志等...
}
}
}
}
在META-INF.dubbo下建立org.apache.dubbo.common.threadpool.ThreadPool,内容是key=包名.类名。 在服务提供方引入依赖后,设置dubbo.provider.threadpool=watching
路由
决定请求的目标机器。 本质上通过在zk上保存一个节点数据,消费者通过监听服务路径,感知路由规则匹配
- route:// 表示路由规则, 支持条件路由和脚本路由, 必填
- ip: 对ip地址生效, 如果对所有ip生效,0.0.0.0, 必填
- com....: 指定服务 必填
- group=foo: 对指定服务的指定group生效
- version: 对指定服务的指定版本生效
- category=routes: 动态配置类型 必填
- dynamic=flase: 数据为持久数据 必填
- enabled=true 覆盖规则生效, 缺省生效
- force =false: 路由结果为空,是否强制执行,缺省为false
- runtime=false: 是否在每次调用执行路由规则, 如果用了参数路由必须为true, 缺省为false
- priority=1 优先级 用于排序,优先级越大越靠前执行,缺省0
- rule=URL.encoding("host=10.20.10.10=> host=10.20.10.11"), 路由规则内容,必填
服务降级
dubbo管理控制台配置
- mock=force:return null
- mock=fail:return null
返回简单值或null
@Reference(mock="force: return null")
@Reference(mock="return null")
Java代码
在registry.register的时候添加mock=foce:return+null