Categories
程式開發

RPC实战与核心原理学习第三天学习


09健康检测:这个节点都挂了,为啥还要疯狂发请求?

服务发现的作用就是实时感知集群 IP 的变化,实现接口跟服务集群节点 IP 的映射。

在超大规模集群实战中,我们更多需要考虑的是保证最终一致性

终极的解决方案是让调用方实时感知到节点的状态变化,这样他们才能做出正确的选择

画外音:就是心跳检查,这里面有什么特别地方吗?我确实想不到有什么注意地方。

在进一步讲解服务健康检测之前,我想先和你分享一个我曾经遇到过的线上问题

RPC实战与核心原理学习第三天学习 1

接口调用某台机器的时候已经出现不能及时响应了,

那为什么 RPC 框架还会继续把请求发到这台有问题的机器上呢?

RPC 框架还会把请求发到这台机器上,也就是说从调用方的角度看,它没有觉得这台服务器有问题。”

我们发现,其实更大的问题是我们的服务检测机制有问题,有的服务本来都已经病危了,但我们还以为人家只是个感冒。

健康检测的逻辑

RPC实战与核心原理学习第三天学习 2

我又发现了新的麻烦:

调用方每个接口的调用频次不一样,有的接口可能 1 秒内调用上百次,有的接口可能半个小时才会调用一次,所以我们不能把简单的把总失败的次数当作判断条件。服务的接口响应时间也是不一样的,有的接口可能 1ms,有的接口可能是 10s,所以我们也不能把 TPS 至来当作判断条件。

和同事讨论之后,我们找到了可用率这个突破口,应该相对完美了。

可用率的计算方式是某一个时间窗口内接口调用成功次数的百分比(成功次数 / 总调用次数)。

当可用率低于某个比例就认为这个节点存在问题,把它挪到亚健康列表,

这样既考虑了高低频的调用接口,也兼顾了接口响应时间不同的问题。

RPC实战与核心原理学习第三天学习 3

10 | 路由策略:怎么让请求按照设定的规则发到不同的节点上?

关键字:RPC 中的路由策略

为什么选择路由策略?

问题:

服务提供方是以集群的方式对外提供服务,那就要考虑一些实际问题。

要知道我们每次上线应用的时候都不止一台服务器会运行实例,那上线就涉及到变更,只要变更就可能导致原本正常运行的程序出现异常,尤其是发生重大变动的时候,导致我们应用不稳定的因素就变得很多。

疑问

那对于我们的 RPC 框架来说,有什么的办法可以减少上线变更导致的风险吗?

这就不得不提路由在 RPC 中的应用。具体好在哪里,怎么实现,我们接着往下看。

如何实现路由策略?参数路由

改造注册中心服务发现 不合适灰度发布功能作为 RPC 路由功能的一个典型应用场景

其核心思想都是一样的,就是让请求按照我们设定的规则发送到目标节点上,从而实现流量隔离的效果。

RPC实战与核心原理学习第三天学习 4

RPC实战与核心原理学习第三天学习 5

RPC实战与核心原理学习第三天学习 6

其关键点就是调用端收集服务端每个节点的指标数据,再根据各方面的指标数据进行计算打分,最后根据每个节点的分数,将更多的流量打到分数较高的节点上

12 | 异常重试:在约定时间内安全可靠地重试

问题描述:为什么需要异常重试?

我们可以考虑这样一个场景。

我们发起一次 RPC 调用,去调用远程的一个服务,比如用户的登录操作,我们会先对用户的用户名以及密码进行验证,验证成功之后会获取用户的基本信息。

当我们通过远程的用户服务来获取用户基本信息的时候,恰好网络出现了问题,比如网络突然抖了一下,导致我们的请求失败了,而这个请求我们希望它能够尽可能地执行成功,那这时我们要怎么做呢?

我们需要重新发起一次 RPC 调用,那我们在代码中该如何处理呢?

是在代码逻辑里 catch 一下,失败了就再发起一次调用吗?这样做显然不够优雅吧。

这时我们就可以考虑使用 RPC 框架的重试

机制。

重试机制是在设置的超时时间到了之后没有返回结果或者服务端出现异常后服务调用端进行再次调用。首先,不是所有接口都适合重试,如果一个服务是不等幂,那么不适合重试的机制,因为会存在重复提交的问题

Dubbo 集群容错策略 ?

RPC实战与核心原理学习第三天学习 7

Failover – 失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries=”2″ 来设置重试次数(不含第一次)。Failfast – 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。Failsafe – 失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。Failback – 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。Forking – 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=”2″ 来设置最大并行数。Broadcast – 播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

RPC 框架的重试机制

在使用 RPC 框架的时候,我们要确保被调用的服务的业务逻辑是幂等的,

这样我们才能考虑根据事件情况开启 RPC 框架的异常重试功能。

这一点你要格外注意,这算是一个高频误区了。

只有符合重试条件的异常才能触发重试,比如网络超时异常、网络连接异常等等。

RPC实战与核心原理学习第三天学习 8

根据异常触发重试,重新通过负载均衡选择一个节点发送请求消息,并且记录请求的重试次数,

当重试次数达到用户配置的重试次数的时候,就返回给调用端动态代理一个失败异常,否则就一直重试下去

问题2

有没有想到连续重试对请求超时时间的影响?

继续考虑这样一个场景:我把调用端的请求超时时间设置为 5s,结果连续重试 3 次,每次都耗时 2s,那最终这个请求的耗时是 6s,那这样的话,调用端设置的超时时间是不是就不准确了呢?

在每次重试后都重置一下请求的超时时间

如何在约定时间内安全可靠地重试?

RPC实战与核心原理学习第三天学习 9

当调用端发起 RPC 请求时,如果发送请求发生异常并触发了异常重试,我们可以先判定下这个请求是否已经超时,如果已经超时了就直接返回超时异常,否则就先重置下这个请求的超时时间,之后再发起重试。

比如这个场景:服务端的业务逻辑是对数据库某个数据的更新操作,更新失败则抛出个更新失败的异常,调用端可以再次调用,来触发服务端重新执行更新操作。那这个时候对于调用端来说,它接收到了更新失败异常,虽然是服务端抛回来的业务异常,但也是可以进行重试的。RPC 框架是不会知道哪些业务异常能够去进行异常重试的,我们可以加个重试异常的白名单,用户可以将允许重试的异常加入到这个白名单中只有 RPC 框架中特定的异常才会如此,比如连接异常、超时异常。在使用 RPC 框架的重试机制时,我们要确保被调用的服务的业务逻辑是幂等的,这样才能考虑是否使用重试,这一点至关重要。

画外音:

那如果这个服务业务逻辑不是幂等的,比如插入数据操作,那触发重试的话会不会引发问题呢?会的。