基础
可以设置zk地址等信息;超时时间,重试次数,失败策略,负载均衡(random,roundrobin)
注册中心:有新的提供方等zk的provider目录变更,zk会通知到消费方,更新数据
监控中心:成功数,失败数,耗时会上报
基于SPI,通过 ExtensionLoader 中的 getExtension 方法,拿到指定扩展点名称的实现类
特色篇(实用技巧)
线程池耗尽,异步化
RpcContext内部的AsyncContext的future对象来实现
用异步线程来处理,增大吞吐量
dubbo线程池总数默认200个
开启异步模式、衔接上下文信息、将结果写入到上下文中CompletableFuture。
异步化占用新开辟线程的资源而不是dubbo本身的线程池,所以对于比较耗时且异步后不影响主业务的可以使用异步处理
首先通过 RpcContext.startAsync 方法定义线程池对象开启异步模式;然后在异步线程中,通过 asyncContext.signalContextSwitch 同步父线程的上下文信息;最后将异步结果通过 asyncContext.write 写入到异步线程的上下文信息中,而存储异步结果的核心关键类是 CompletableFuture。
查询一次请求的所有日志
拦截器,信息放入RpcContext中
泛化调用(网关使用,通过类名,方法名统一调用)
Web 服务器其实是在做一些透传性质的事情
获取下游接口的代理对象
通过传入类名,然后用ReferenceConfig(dubbo的服务信息,注册地址等配置信息)从dubbo中获得类信息,反射生成代理对象;然后通过方法名,参数类型,参数来调用invoke方法
OpenFeign spring cloud工程,封装了远程调用的代码,通过生成代理对象注入spring,调用时代理对象发起远程调用
产线后门的万能管控
泛化调用,通过类名,方法名等请求一个通用方法,调用接口(通过传入类的代码,用Groovy编译成字节码,生成单例对象放入Spring中)
注解(@DubboService)
事件通知(methods)
如支付后续很多事件处理,通过事件通知,避免一个大方法
@DubboReference(
/** 接口调研超时时间,1毫秒 **/
timeout = 10000,
/** 启动时不检查 DemoFacade 是否能正常提供服务 **/
check = false,
/** 为 DemoFacade 的 sayHello 方法设置事件通知机制 **/
methods = {@Method(
name = "sayHello",
oninvoke = "eventNotifyService.onInvoke",
onreturn = "eventNotifyService.onReturn",
onthrow = "eventNotifyService.onThrow")}
)
@DubboReference 注解上添加事件通知的 @Method 相关属性配置。
参数校验(validation)
@DubboReference(timeout = 6000,retries = 2,check = false,validation = "jvalidation")
@DubboService(validation = "true")
接口缓存(cache)
@DubboReference(timeout = 6000,retries = 2,check = false,validation = "jvalidation",cache = "lru")
上面使用的是内存缓存
也可以使用redis
cache = “jcache”,需要基于SPI引入相关的包
自定义Filter
流量控制
org.apache.dubbo.rpc.Filter
org.apache.dubbo.rpc.Filter 接口,META_INF.dubbo目录下创建org.apache.dubbo.rpc.Filter文件,内容是实现类的路径userNameFilter
需要用到拦截的地方加上下面的注解
@DubboService(validation = “jvalidation”,filter = “userNameFilter”)
鉴权
源码
分层设计
dubbo注解
一般引入外部的接口,自己都会包一层integration层,屏蔽下游接口差异性
dubbo,通过注解,扫描路径下定义的接口,创建BeanDefinition对象,进而创建Proxy对象,然后使用
如果这些接口是同类性质的,而且 Spring 还无法通过注解修饰接口直接使用的话,都可以采取扫描机制统一处理共性逻辑
SPI(桥接模式,service provider interface)
jdk spi的问题
- 如果多次load,会生成多个重复的对象,占用内存,效率低,占用磁盘io,ServiceLoader.load
- 不能指定创建实现类,只能循环的方式并比较(ExtensionLoader 是dubbo的自定义类加载器,@SPI)
解决方式:缓存到map中,即dubbo spi的思想
dubbo使用方式类似,接口用注解@SPI
Wrapper(动态生成代理类,try)
JDK的动态代理,JDK 代理是动态生成了一个继承 Proxy 的代理类; 反射生成被代理类,Class.forname,clz.getDeclaredMethod等(比较耗时)
Cglib的动态代理,Cglib 代理是动态生成了一个继承被代理类的派生代理类;核心实现是自动生成了各种 if…else 代码来调用被代理类的方法,但是这块生成代理的逻辑不够灵活,难以自主修改。代理类中执行被代理类的方法(字节码增强)
Wrapper的动态代理,通过Wrapper 机制获取一个继承 Wrapper 的代理类,使用生成的 wrapper 代理类调用通用的 invokeMethod (自动生成if…else 逻辑代码来识别调用源对象的不同方法,自动生成java代码的方式创建代理类)方法获取结果
dubbo 的 wrapper:
创建扩展点对象的时候,不但会通过 setter 方法进行实例注入,而且还会通过包装类层层包裹
编译(生成字节码,了解,看Javassist)
Javassist 编译
ASM编译(高性能),属于非常底层的插件了,操作该插件的技术难度相当高
JavaCompiler:是 JDK 提供的一个工具包
适配(不学)
ExtensionLoader类加载
@Adaptive 注解
想动态地指定 URL 中的参数,来动态切换实现类去执行业务逻辑,把一堆根据参数获取实现类的重复代码,全部封装到了代理类中,以达到充分灵活扩展的效果。
发布流程
调用流程
@DubboReference
private DemoFacade demoFacade
实际是一个代理对象,包含远程调用的的ReferenceConfig信息
拓展
SpringMvc 的拦截过滤器HandlerInterceptor
看25
dubbo线程池有固定,最大(涨了后不降低),有生命周期的最大,EagerThreadPool(核心满后直接到空闲线程池创建,不用先进入阻塞队列,重写阻塞队列的offer方法和execute方法)
控制应用上下线:
了解
dubbo.application.register-mode 只接口级注册,只应用级注册,all
特别放送实践