Dubbo服务治理规范

Dubbo服务治理规范

关于超时时间,一律配置在服务提供者Provider端,时间根据业务的需要设置不同的时间,推荐保持默认的1秒,或者可以设置为2秒,再高不推荐,RPC调用很短,理论不会超过1秒。
关于重试次数,根据接口的幂等性来设置,如果业务允许数据重复的情况或者就是查询操作,一般保持默认的2就可以,如果是不能保持幂等性的接口,重试次数设置为0
关于最大并发调用限制建议都设置在Provider端。在Provider端,设置参数actives,消费者端的最大并发调用限制,默认情况下是0也就是不限制,该参数可以设置为一个合理值,目前公司没有大并发的情况下180左右绝对够了(秒杀除外)。设置参数threads以及executes。threads参数默认值是200,一般情况下只要不是高并发200线程绝对够了,自然需要配合超时,如果超时时间太长,导致200个线程池用完了肯定就挂了。所以第一点的超时时间是重点。executes表示一个服务提供者并行执行请求上限,这个参数不建议超过threads的大小(目前线程池在高并发下有一定问题后续补充)。
版本号。每个接口都应定义版本号,为后续不兼容升级提供可能。建议使用两位版本号,因为第三位版本号通常表示兼容升级,只有不兼容时才需要变更服务版本。
当不兼容时,先升级一半提供者为新版本,再将消费者全部升为新版本,然后将剩下的一半提供者升为新版本。

注意:一旦加上版本号,服务提供者和服务消费者都需要加上版本号,而且必须版本一致,不然调用不到。
参考配置(没有一个配置能适合所有场景,不同的场景需要调节不同的参数,如果有疑问可以交流):
Provider端

threads参数的设置

在配置文件配置,默认的200一般足够,如果调用量大可以考虑添加机器,或者改为500,这个和机器cpu核数也有关系,和io密集以及cpu密集也有关系。一般保持默认是足够的

dubbo:
protocol:
threads: 300

在服务级别限制:

@Service(timeout = 1500,retries = 2,executes = 400,version =“1.0.0”,actives = 200)
public class CustomizationServiceImpl implements CustomizationService {

在方法级别限制

@Service(timeout = 1500, retries = 2, actives = 400,version =“1.0.0”,executes = 200,
methods = @Method(timeout = 1100, executes = 50,retries = 0, actives = 100, name = “batchHandelCustomization”))

参数含义以及说明
timeout:服务方法调用超时时间(毫秒)
retries:失败重试次数,缺省是 2
loadbalance:负载均衡算法,缺省是随机 random。还可以配置轮询 roundrobin、最不活跃优先leastactive 和一致性哈希 consistenthash 等
actives:消费者端的最大并发调用限制,即当 Consumer 对一个服务的并发调用到上限后,新调用会阻塞直到超时,在方法上配置 dubbo:method 则针对该方法进行并发限制,在接口上配置 dubbo:service,则针对该服务进行并发限制

注意:上面的四个参数如果在Consumer端进行配置之后会覆盖掉Provider端的配置。这在实际场景很不推荐。理由如下

作为服务的提供方,比服务消费方更清楚服务的性能参数,如调用的超时时间、合理的重试次数等
在 Provider 端配置后,Consumer 端不配置则会使用 Provider 端的配置,即 Provider 端的配置可以作为 Consumer 的缺省值 。否则,Consumer 会使用 Consumer 端的全局设置,这对于 Provider 是不可控的,并且往往是不合理的
threads:服务线程池大小。该参数其实还有一个配合参数threadpool,不过这部分其实还有问题,后续在补充
executes:一个服务提供者并行执行请求上限,即当 Provider 对一个服务的并发调用达到上限后,新调用会阻塞,此时 Consumer 可能会超时。在方法上配置 dubbo:method 则针对该方法进行并发限制,在接口上配置 dubbo:service,则针对该服务进行并发限制

version:服务版本,与服务提供者的版本一致。该参数Provider端Consumer 端建议都设置,保持版本一致可以调用,这样为以后升级有帮助。

不同的设置参数的说明
比如timeout设置的较大,actives参数未设置。这种情况下就会导致线程池爆满,然后服务挂掉。如果timeout设置过大,actives参数也设置之后,至少会保持一个合理的资源可用范围,不会导致服务挂掉,但是调用可能会超时,但是还是那句话RPC的调用耗时是很短的,注意:timeout的设置一定要设置在Provider端并且Consumer 端不设置。
如果线程池满了会报类似于WARN 2021-07-29 WARN AbortPolicyWithReport:65 - [DUBBO] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler, Pool Size: 500 (active: 500, core: 500, max: 500, largest: 500), Task: 1285578 (completed: 1285135), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false)的错误,这个时候不能处理心情求。线程池的大小和qps有关系,但是如果线上线程池真满了,需要排查满了的原因而不是无限制增加线程池大小,所谓的线程池不代表越大性能越好。
多次说到RPC调用短,看下官方的数据https://dubbo.apache.org/zh/docsv2.7/user/capacity-plan/
使用 Dubbo 的会员服务项目
每天接收 4 亿次远程调用
使用 12 台网站标配机器提供服务(8 核 CPU,8G 内存)
平均负载在 1 以下(对于 8 核 CPU 负载很低)
平均响应时间 2.3 到 2.5 毫秒,网络开销约占 1.5 到 1.6 毫秒(和数据包大小有关)
使用 Dubbo 的产品授权服务项目
每天接收 3 亿次远程调用
使用 8 台网站标配机器提供服务(8 核CPU,8G 内存)
平均负载在 1 以下(对于 8 核 CPU 负载很低)
平均响应时间 1.4 到 2.8 毫秒,网络开销约占 1.0 到 1.1 毫秒(和数据包大小有关)
retries参数在很多时候我们需要设置为0,为什么呢?现在假设有这么一个场景,我们需要在数据库插入一个订单数据,会调用订单服务,假设这个时候调用失败,我会重试。这个时候可能有两种情况,第一是真的调用订单服务失败了,重试一下没毛病,不过呢这个时候会造成调用时间加长了,有可能会导致超时的问题。还有一种情况是其实调用服务没失败,只是网络的抖动造成的,这个时候再重试代表着我插入了两条订单数据(假设接口没做幂等,如果有幂等性校验的话不会造成这个情况)。一般的建议是查询的接口可以设置重试这个参数,增加服务的健壮性,但是可能造成调用的延长。
关于线程池的问题,为啥建议保持默认,第一是目前没高并发默认是够得,其次是目前的dubbo在线程池的设计上有毛病,不过并发不高没事。具体可以参考官方的issues。
Dubbo 常见错误及解决方法
地址找不到:No provider available

找不到服务,这时候可能有这么几种情况:

Provider 服务没启动,或者注册中心(比如 ZooKeeper,Nacos,Consul)宕机了。
Dubbo 的服务配置有误差,必须保证服务名,组别(默认是 Dubbo ),version 三者都正确。
访问的环境有误:通常我们会有开发环境、测试环境、线上生产环境等多套环境。有时候发布的服务到了测试环境,而访问调用时却走了开发环境。

排查步骤

访问注册中心的 Ops 系统,查询对应的服务是否有提供者列表;同时检查调用者应用所在服务器的日志(一般每种注册服务的客户端都会有对应的日志记录),查看是否有地址信息的推送/拉取记录。

如无,则表明发布者发布服务失败,检查发布者的应用启动是否成功。

如有服务,则检查调用者应用所连接的注册中心,确认跟预期的环境要匹配。

如上述都没有问题,检查是否配置了路由过滤的规则等。

调用超时:client-side timeout

一般超时是调用端发生在请求发出后,无法在指定的时间内获得对应的响应。原因大概有以下几种情况:

服务端确实处理比较慢,无法在指定的时间返回结果,调用端就自动返回一个超时的异常响应来结束此次调用。
服务端如果响应的比较快,但当客户端 Load 很高,负载压力很大的时候,会因为客户端请求发不出去、响应卡在 TCP Buffer 等问题,造成超时。因为客户端接收到服务端发来的数据或者请求服务端的数据,都会在系统层面排队,如果系统负载比较高,在内核态的时间占比就会加长,从而造成客户端获取到值时已经超时。
通常是业务处理太慢,可在服务提供方机器上执行:jstack [PID] > jstack.log 分析线程都卡在哪个方法调用上,这里就是慢的原因。如果不能调优性能,请调高 timeout 阈值。

排查和解决步骤

两边可能有 GC ,检查服务端和客户端 GC 日志,耗时很长的 GC,会导致超时。超时的发生很可能意味着调用端或者服务端的资源(CPU,内存或者网络)出现了瓶颈,需要检查服务端的问题还是调用端的问题来排除GC抖动等嫌疑。

检查服务端的网络质量,比如重传率来排除网络嫌疑。

借助链路跟踪的分析服务(比如阿里的 ARMS,开源的 OpenTracing 系的实现 Zipkin、SkyWalking 等)来分析下各个点的耗时情况。

服务端的线程资源耗尽:Thread pool is EXHAUSTED

Dubbo 服务端的业务线程数是 200 个,如果多个并发请求量超过了 200,就会拒绝新的请求,抛出此错误。这种问题有这么几种解决办法:
排查和解决步骤

调整 Provider 端的 dubbo.provider.threads 参数的大小,调大一些即可。
调整 Consumer 端的 dubbo.consumer.actives 参数的大小,调小一些即可。
增加 Provider 服务的数量,分担压力。

Hessian 序列化失败:HessianRuntimeException

检查服务方法的传入传出参数是否实现 Serializable 接口。
检查服务方法的传入传出参数是否继承了 Number、Date、ArrayList、HashMap 等 Hessian 特殊化处理的类
启动时 Configuration problem: Unable to locate Spring NamespaceHandler for XML schema

表示 Spring 找不到 <dubbo:…> 配置的解析处理器。通常是 Dubbo 的 jar 包没有被引入,请添加对 Dubbo 的依赖;或者是 ClassLoader 隔离,查看是否有使用 OSGI 或其它热加载机制。

参考链接
服务化最佳实践:https://dubbo.apache.org/zh/docsv2.7/user/best-practice/
官方的推荐用法:https://dubbo.apache.org/zh/docsv2.7/user/recommend/#fnref:4
官方容量规划以及调用延迟:https://dubbo.apache.org/zh/docsv2.7/user/capacity-plan/
Dubbo 常见错误及解决方法:https://mp.weixin.qq.com/s/B6YkP7UeS-fNBeDvknQeyA
https://github.com/apache/dubbo/issues/7054
https://github.com/apache/dubbo/issues/8172
https://github.com/apache/dubbo/pull/7081
携程的Dubbo升级经历:https://mp.weixin.qq.com/s/rLklcgRY5NRT1WZk4k5_BA

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值