当前位置: 首页 > 后端技术 > Java

Dubbo2.X详解【1】

时间:2023-04-01 19:04:38 Java

Dubbo是什么?可以说是一个RPC通信调用+服务治理框架。RPC通信调用:远程发现和通信能力,基于Dubbo协议,同时支持Rmi等其他协议。服务治理:服务发现、负载均衡、流量调度等服务治理。Dubbo特性启动时检查:dubbo.reference.check=false,强制更改所有引用的校验值,即使配置中有语句也会被覆盖。dubbo.consumer.check=false是check的默认值。如果配置中有显式声明,如:,则不受影响。dubbo.registry.check=false,前两个表示订阅成功,但是provider列表是否为空或者是否报错,注册订阅失败也允许启动,这个选项需要使用,并且会在后台定期重试。集群容错Failfast集群故障快速,只发起一次调用,故障发生后立即报错。通常用于非幂等的写操作,比如添加新记录。FailsafeCluster是failsafe的,发生异常时直接忽略。通常用于写入审计日志等操作。FailbackCluster自动从故障中恢复,在后台记录失败的请求,并定期重新发送。通常用于消息通知操作。ForkingCluster并行调用多台服务器,一个成功就返回。通常用于实时性要求高的读操作,但需要浪费更多的服务资源。最大并行度可以通过forks="2"设置。BroadcastCluster广播调用所有的provider,一个一个的调用,任何一个报错,就会报错。通常用于通知所有提供者更新本地资源信息,如缓存或日志。现在在广播调用中,可以通过broadcast.fail.percent配置节点调用的失败率。当达到这个比例时,BroadcastClusterInvoker将不再调用其他节点,直接抛出异常。broadcast.fail.percent取值范围为0到100。默认情况下,所有调用失败时抛出异常。broadcast.fail.percent只控制失败后是否继续调用其他节点,不改变结果(任何节点报错都会报错)。broadcast.fail.percent参数在dubbo2.7.10及以上版本生效。广播集群配置broadcast.fail.percent。broadcast.fail.percent=20表示当20%的节点调用失败时,抛出异常,不再调用其他节点。配置方法:Service中clusterReference中的集群重试次数。尝试调用一次Dubbo服务后,如果出现非业务异常(服务突然不可用、超时等),Dubbo默认最多额外重试2次。重试次数可以通过配置修改,以上均在集群容错模式为:FailoverCluster时有效。LoadBalanceRandomLoadBalance默认负载均衡随机,根据权重设置随机概率。一个section的碰撞概率高,但是调用量越大,分布越均匀,使用概率后权重也越均匀,有利于动态调整provider权重。RoundRobinLoadBalance轮询,按照约定后的权重设置轮询比例。有一个慢provider积累请求的问题,比如:第二台机器很慢,但是没有挂掉,当请求转到第二台机器的时候卡在那里。久而久之,所有的请求都卡在了第二台机器上。LeastActiveLoadBalance是最少的活跃调用数,相同的活跃数是随机的,活跃数是指调用前后的计数差值。让慢的提供者接收更少的请求,因为对于慢的提供者来说,调用前后的计数差异会更大。ConsistentHashLoadBalance一致的Hash,具有相同参数的请求总是发送给同一个提供者。当某个provider宕机时,原本发送给该provider的请求会基于虚拟节点扩散到其他provider,不会引起剧烈变化。算法见:http://en.wikipedia.org/wiki/...默认只有第一个参数Hash,如果要修改,请配置默认使用160个虚拟节点。如果要修改,请配置线程模型,如果事件处理逻辑可以快速完成,不会发起新的IO请求,比如由于只是在内存中记录一个标记,直接在IO线程上处理会更快,因为减少了线程池调度。但是如果事件处理逻辑比较慢,或者需要发起新的IO请求,比如查询数据库,就必须调度到线程池中。否则会阻塞IO线程,无法接收到其他请求。如果使用IO线程处理事件,在事件处理过程中发起新的IO请求,比如在连接事件中发起登录请求,会报“可能导致死锁”的异常,但不会是真正的死锁。Dispatcherall将所有消息派发到线程池,包括请求、响应、连接事件、断开事件、心跳等。Direct所有消息都不派发到线程池,全部直接在IO线程上执行。message只将请求响应消息派发到线程池,其他连接断开事件、心跳等消息直接在IO线程上执行。execution只派发请求消息到线程池,不包括response、response等连接断开事件、心跳等消息,直接在IO线程上执行。connection在IO线程上,将连接断开事件放入队列中,有序的一条条执行,其他消息派发到线程池。ThreadPool固定大小的线程池。线程在启动时创建并一直保持而不关闭。(默认)cached缓存的线程池空闲一分钟后会自动删除,需要时重建。limited可扩展的线程池,但是池中的线程数只会增长不会缩减。只增长不收缩的目的是为了避免收缩时突发大流量带来的性能问题。eager先创建Worker线程池。当任务数大于corePoolSize但小于maximumPoolSize时,首先创建worker来处理任务。当任务数大于maximumPoolSize时,将任务放入阻塞队列。当阻塞队列已满时抛出RejectedExecutionException。(相对于cached:cached在任务数超过maximumPoolSize时直接抛出异常,而不是将任务放入阻塞队列)Dubbo还支持什么?直连提供商绕过注册中心,只测试指定的服务提供商。这时可能需要点对点直连。点对点直连方式会以服务接口为单位,忽略注册中心的提供商列表。A接口配置点对点,不影响B接口从注册表中获取列表。只订阅不注册允许服务商开发者只订阅服务(开发的服务可能依赖其他服务),不注册开发中的服务,通过直连测试开发中的服务。多协议Dubbo允许配置多种协议。不同的业务在性能上适合不同的协议进行传输。比如大数据使用短连接协议,小数据大并发使用长连接协议。多注册中心将同一个服务注册到Dubbo中的多个注册中心。不同的服务使用不同的注册表。多个注册表引用。服务分组当一个接口有多个实现时,可以通过分组来区分。--注册--消费--组可以对于*staticservice,服务提供者在第一次注册时是禁用的,需要手动启用。断开连接时,不会自动删除,需要手动禁用。多版本在Dubbo中配置同一个服务的多个版本。分组聚合通过分组聚合结果,返回聚合后的结果,例如菜单服务。组用于区分同一接口的多个实现。现在消费者需要从每组中选择调用一次并返回结果,合并结果后返回,这样就可以实现聚合菜单项。指定的方法合并结果,其他未指定的方法只会调用一个Group参数校验基于JSR303实现参数校验功能,用户只需识别JSR303标准校验注解,通过声明filter实现校验。泛化调用对于Dubbo的泛化调用,提供了一种新的方式:直接传递一个字符串来完成一次调用。即用户直接传递参数对象的json字符串即可完成一次Dubbo泛化调用。Provider超时中断适用场景:对于一个provider,如果一个操作执行超时,则中断(释放)执行线程,而不是仅仅打印超时日志。超时参数resultcache结果缓存用于加快流行数据的访问速度。Dubbo提供声明式缓存,减少用户添加缓存的工作量。缓存类型lru根据最近最少使用原则删除冗余缓存,保留最热的数据缓存。threadlocal目前的线程缓存,比如一个页面渲染,用到的入口很多,每个入口都要检查用户信息。通过线程缓存,可以减少这种冗余访问。jcache与JSR107集成以桥接各种缓存实现。收集dubbo广播响应适用场景:对于一个dubbo消费者,广播调用多个dubbo提供者,消费者可以收集到所有服务提供者的响应结果。@Reference(interfaceClass=DubboHealthService.class,cluster="broadcast2")#--------Mapm=RpcContext.getServerContext().getAttachments();泛化调用GenericServicebarService=(GenericService)applicationContext.getBean("barService");Objectresult=barService.$invoke("sayHello",newString[]{"java.lang.String"},newObject[]{"World"});上下文信息RpcContext是一个ThreadLocal的临时状态记录器,当收到RPC请求或者发起RPC请求时,RpcContext的状态会发生变化。例如:A调B,B再调C,那么在B机上,B调C之前,RpcContext记录了A调给B的信息,B调C之后,RpcContext记录了B调给C的信息。隐式参数传递Dubbo中通过Attachment在服务消费者和提供者之间隐式传递参数RpcContext.getContext().setAttachment("index","1");//隐式传参,后续远程调用这些参数会隐式发送给服务器,类似于cookies,用于框架集成。一般业务不建议使用异步调用。使用CompletableFuture签名的接口publicinterfaceAsyncService{CompletableFuturesayHello(Stringname);}使用RpcContext//这里的调用会立即返回nullasyncService.sayHello("world");//获取调用的Future引用,以及当返回结果时,会通知并设置为这个FutureCompletableFuturehelloFuture=RpcContext.getContext().getCompletableFuture();//为Future添加回调字符串>未来=RpcContext.getContext().asyncCall(()->{asyncService.sayHello("onewaycallrequest1");});未来.get();重载服务接口publicinterfaceGreetingsService{StringsayHi(Stringname);//AsyncSignal是完全可选的,你可以使用任何参数类型,只要java允许你这样做。默认CompletableFuturesayHi(Stringname,AsyncSignalsignal){returnCompletableFuture.completedFuture(sayHi(name));}}parametercallback参数回调方式与调用本地回调或监听器一样,只需要在Spring配置文件中声明哪个参数是回调类型即可。Dubbo会根据长连接生成一个反向代理,从而可以从服务端调用客户端逻辑。可以参考dubbo项目中的示例代码。等等等等……