dubbo 路由过滤
官网:https://dubbo.apache.org/zh/docs/advanced/routing-rule/
路由过滤
路由过滤:消费端调用服务时,根据自定义规则过滤服务调用列表
消费端服务调用流程
消费端应用启动时,创建clusterInvoker对象(默认为failoverClusterInvoker) # 消费端发起服务调用时,依次执行如下过程:获取所有可用invoker列表(directory#list) * dynamicDirectory:动态invoker列表,从注册中心获取 * staticDirectory:静态invoker列表,创建staticDirectory对象时传入的invoker列表对所有可用列表进行路由过滤(routerChain#route)使用负载均衡算法(loadbalance#select)在路由过滤后的invoker列表选择一个invoker,发起远程服务调用; # 服务调用结果处理如果调用正常,消费端收到服务端返回的结果(如果有结果返回);如果调用异常,执行容错策略:重试(failover,默认)、忽略异常(failsafe)等;如果设置了mock,服务调用异常时,可进行服务降级;
路由分类
条件路由:使用dubbo定义的语法规则在dubbo-admin中写路由规则;文件路由:将路由规则写在文件中,读取文件提取路由规则;脚本路由:使用jdk支持的引擎解析路由脚本,默认使用javascript引擎标签路由:给服务(provider)打标签,后续如果consumer调用时携带标签, 标签如果匹配则优先调用,如果不匹配则调用不携带标签的provider服务
StateRouteFactory
@SPIpublic interface StateRouterFactory { @Adaptive("protocol")
***********
条件路由
应用粒度条件路由
# app1的消费者只能消费所有端口为20880的服务实例# app2的消费者只能消费所有端口为20881的服务实例---scope: applicationforce: trueruntime: trueenabled: truekey: governance-conditionrouter-consumerconditions: - application=app1 => address=*:20880 - application=app2 => address=*:20881
接口粒度条件路由
# 服务粒度示例# DemoService的sayHello方法只能消费所有端口为20880的服务实例# DemoService的sayHi方法只能消费所有端口为20881的服务实例---scope: serviceforce: trueruntime: trueenabled: truekey: org.apache.dubbo.samples.governance.api.DemoServiceconditions: - method=sayHello => address=*:20880 - method=sayHi => address=*:20881
参数说明
scope:application(应用粒度)、service(服务粒度)force:路由结果为空时,是否强制执行,默认false true:强制执行,路由结果为空,则返回空结果 false:路由结果为空时,返回所有服务列表runtime:是否在每次调用时执行路由规则,默认false true:每次调用时执行路由规则,如果使用参数路由,必须设置为true false:只有在服务者列表更新后执行路由规则,如果没有更新,使用缓存的列表enabled:是否启用路由规则,默认truepriority:路由规则优先级,值越大越靠前执行,默认为0key:路由规则作用的应用名(scope为application)、服务名(scope为service) scope为application时,key:应用名 scope为service时,key:[{group}]{service}[{version}],group、version可缺省conditions:路由条件规则设置(whenRule => thenRule)
conditions 路由规则:whenRule ==> thenRule
whenRule:消费者匹配条件,消费者满足匹配条件时,执行后面的过滤规则thenRule:服务提供者匹配条件,返回满足匹配条件的服务者列表whenRule为空,表示对所有消费者都应用后面的匹配规则(thenRule),如:=> host != 10.20.153.11thenRule为空,表示禁止访问,如:host = 10.20.153.10 => whenRule、thenRule格式:key = value、key != valuekey为服务调用信息(method、argument等)暂不支持参数路由、 url本身字段(protocol, host, port 等)、 url上的所有参数,如:application, organization value可包含特殊字符:*(通配符),如host != 10.20.* ,(分隔符),如host != 10.20.153.10,10.20.153.11 $(引用消费者参数),如host = $host # 路由规则示例=> host != 172.22.3.91:所有消费者均不调用172.22.3.91上的服务register.ip != 10.20.153.10,10.20.153.11 =>:注册地址不在指定地址的服务不得调用任何服务application != kylin => host != 172.22.3.95,172.22.3.96:应用名不为指定名称的不得调用不为指定host的服务
***********
标签路由
动态标签:dubbo admin中设置
# 动态标签,动态标签优先级更高,同时包含动态标签、静态标签,以动态标签为准# governance-tagrouter-provider应用增加了两个标签分组tag1和tag2# tag1包含一个实例 127.0.0.1:20880# tag2包含一个实例 127.0.0.1:20881--- force: false runtime: true enabled: true key: governance-tagrouter-provider tags: #可以给应用(该应用下用多个服务实例)打多个标签 - name: tag1 #name标签名称,addresses表示数组中的实例都打上该标签 addresses: ["127.0.0.1:20880"] #地址为127.0.0.1:20880的实例打标签tag1 - name: tag2 addresses: ["127.0.0.1:20881"] #地址为127.0.0.1:20881的实例打标签tag2
静态标签:服务端注册服务时设置
消费端标签过滤:调用时在上下文中设置标签
# 消费端调用标签tag1的服务RpcContext.getContext().setAttachment(Constants.REQUEST_TAG_KEY,"tag1");
***********
文件路由
FileStateRouterFactory
public class FileStateRouterFactory implements StateRouterFactory { public static final String NAME = "file"; private StateRouterFactory routerFactory; public void setRouterFactory(StateRouterFactory routerFactory) { this.routerFactory = routerFactory; } @Override public
***********
脚本路由
scriptStateRouterFactory
public class scriptStateRouterFactory implements StateRouterFactory { public static final String NAME = "script"; @Override public
消费端标签过滤
@DubboReference:消费端服务调用注解
@documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})public @interface DubboReference { Class<?> interfaceClass() default void.class; String interfaceName() default ""; String group() default ""; //服务分组 String version() default ""; //服务版本 String url() default ""; //直连服务提供端(如果配置了,则不使用注册中心) String client() default ""; //客户端传输方式,默认为netty @Deprecated boolean generic() default false; //已禁用 @Deprecated boolean injvm() default true; //已禁用 boolean check() default true; boolean init() default true; boolean lazy() default false; boolean stubevent() default false; String reconnect() default ""; boolean sticky() default false; String proxy() default ""; String stub() default ""; String cluster() default ClusterRules.EMPTY; int connections() default -1; int callbacks() default -1; String onconnect() default ""; String ondisconnect() default ""; String owner() default ""; String layer() default ""; int retries() default -1; String loadbalance() default LoadbalanceRules.EMPTY; boolean async() default false; int actives() default -1; boolean sent() default false; String mock() default ""; String validation() default ""; int timeout() default -1; String cache() default ""; String[] filter() default {}; String[] listener() default {}; String[] parameters() default {}; @Deprecated String application() default ""; String module() default ""; String consumer() default ""; String monitor() default ""; String[] registry() default {}; String protocol() default ""; String tag() default ""; //标签设置 String merger() default ""; Method[] methods() default {}; String id() default ""; @Deprecated String[] services() default {}; String[] providedBy() default {}; String scope() default ""; boolean referAsync() default false;}
HelloController
@RestControllerpublic class HelloController { @DubboReference(tag = "tag1") //调用含有标签tag1的服务 private HelloService helloService; @RequestMapping("/hello") public String hello(){ helloService.hello().forEach(System.out::print); return "hello consumer 2"; }}