错误编码:HSF-0024
HSF 支持用户使用 Groovy 脚本配置服务的路由规则。
路由规则的配置方式,请参见 Routing Rule Wiki,在完成路由规则的配置后,您可能会发现路由规则没生效,这些没生效一般就是指调用并没有被路由到预期的机器上,然而这些没生效有可能是其他因素引起的,例如路由规则没写对、路由规则里的 IP 没有提供服务等。
这里,就来介绍下如何排查路由规则没有生效,共包含以下几步:
1. 客户端是否为本地调用、泛化调用
如果客户端通过本地调用、泛化调用的方式消费服务的话,那么是不会使用路由规则逻辑的,自然也就出现了路由规则不生效这种表象。
- 本地调用:指的是一个进程即是一个服务的发布者,又是这个服务的消费者,这个时候 HSF 默认优先走本地调用,即进程内的 Java 调用,而非 RPC 调用。这种情况,是不走路由规则的逻辑的。
- 泛化调用:指的是不依赖服务的二方包,直接通过 GenericService 通过服务描述进行消费的场景,这个时候 HSF 由于没有服务的 Class,无法执行路由规则里调用业务类的逻辑,因此也不走路由规则的逻辑。
HSFOPS 上的服务测试功能走的是泛化调用,因此也不会生效路由规则。
2. 客户端是否收到路由规则
HSF 的路由规则存放在 Diamond 上,在客户端启动时,会从 Diamond 上拉取服务对应的路由规则。
在 hsf.log
(一般的路径是 HSF 2.2:${user.home}/logs/hsf/hsf-config.log
或 HSF 2.1:${user.home}/logs/hsf/hsf.log
)中搜索服务名,如果正确收到路由规则,会看到类似如下的日志:
01 2015-10-09 13:20:06.402 WARN [com.taobao.diamond.client.Worker.default:t.hsf] [] [] [] [Metadata Component] Received rule for service [com.alibaba.dt.op.authclient.api.ResourceAPI:1.0.0.daily]: Groovy_v200907@package hqm.test.groovy
public class RoutingRule{
Map<String, List<String>> routingRuleMap(){
return [
"G1":["100.69.161.201:*"]
]
}
String interfaceRoutingRule(){
return "G1";
}
}
如果没有收到路由规则,请检查:
- 路由规则的命名是否与服务名对应,具体请参见 Routing Rule Wiki。
- 路由规则配置在 diamond 上的环境和客户端所在的环境是否一致。
3. 路由规则是否正确解析
在 hsf.log
中搜索服务名,如果 HSF 的路由规则解析正确,会看到类似如下的日志:
01 2015-10-09 13:20:06.761 INFO [com.taobao.diamond.client.Worker.default:t.hsf] [] [] [] Parse route rule successed, RouteRule:com.taobao.hsf.route.service.RouteRule@4441ec5a{
keyedRules={G1=[100.69.161.201:*]},
interfaceRule=G1,
methodRule={},
argsRule={}
}
如果 HSF 的路由规则解析失败,会看到相关的失败信息,请对照日志和 Routing Rule Wiki 检查您的路由规则。
4. 路由规则的内容是否正确
路由规则收到了、也解析对了,如果路由规则执行的效果还与预期不同,请依次检查以下内容:
-
路由的目标机器是否真的提供了该服务
请在对应环境的 HSF 服务治理平台上查询服务,看路由的目标 IP 是否都在 Providers 列表中。
- 在老版本的 HSF 中,如果路由规则指定的 IP 没有提供服务,会报地址找不到错误
-
在新版本的 HSF 中(2.1.0.7 开始),如果路由规则指定的 IP 没提供服务,会提示开启空保护,那么此时路由规则就不再生效,HSF 会从 ConfigServer 存放的 Provider 地址列表中为客户端选取一个可用 IP 进行调用。在使用方法路由时,如果碰到算出的地址为空,这种情况下,在
hsf.log
中搜索服务名,会看到类似如下的日志。其中空保护开启的标志为倒数第二行的EmptyProtection triggered [true]
:01 2015-10-09 13:20:06.761 WARN [HSF-AddressAndRule-2-thread-1:t.hsf] [] [] [] [Address Component] isEmptyProtection: true 01 2015-10-09 13:20:06.761 WARN [HSF-AddressAndRule-1-thread-1:t.hsf] [] [] [] [Address Component] isEmptyProtection: true 01 2015-10-09 13:20:06.761 WARN [HSF-AddressAndRule-2-thread-1:t.hsf] [] [] [] [Address Component] newAllAvailableAddresses is emtpy for service : com.alibaba.dt.op.authclient.api.ResourceAPI:1.0.0.daily 01 2015-10-09 13:20:06.761 INFO [HSF-AddressAndRule-2-thread-1:t.hsf] [] [] [] [AddressBucket-com.alibaba.dt.op.authclient.api.ResourceAPI:1.0.0.daily] Refresh: all amount [0], available amount [0], local preferred switch [off].Unit=UNIT 01 2015-10-09 13:20:06.761 INFO [HSF-AddressAndRule-1-thread-1:t.hsf] [] [] [] [Address Component] route result com.alibaba.dt.op.authclient.api.ResourceAPI:1.0.0.daily, addresses remain[1], EmptyProtection triggered [true] 01 2015-10-09 13:20:06.762 INFO [HSF-AddressAndRule-1-thread-1:t.hsf] [] [] [] [AddressBucket-com.alibaba.dt.op.authclient.api.ResourceAPI:1.0.0.daily] Refresh: all amount [1], available amount [1], local preferred switch [off].
-
路由规则是否正确
仔细检查您的接口路由、方法路由、参数路由,是否真的写对了。
-
地址计算优先级
如果开启了同机房规则,那么同机房的地址优先于路由规则的地址,路由规则的地址在同机房规则结果的地址集合里再计算。
路由规则分为接口级 > 方法级 > 参数级,若某一级的路由规则不存在,即其返回的 key 为 null,或在
routingRuleMap
中找不到相应值,则认为这一级对路由地址不做限制,地址取上一级的全部地址。总体的计算过程如下:
- 接口级路由规则(正则式)最终地址列表会和同机房规则结果地址列表作交集
- 方法级路由规则(正则式)最终地址列表会和接口级地址列表作交集
- 参数级路由规则(正则式)最终地址列表会和方法级地址列表作交集
5. 路由规则是否真的被调用
如果按照以上内容排查后,都没有问题,请再确认路由规则指定的服务/方法是否真的被调用了? 如果相应的方法没有被调用,则在目标机器上肯定也搜不到调用日志。
可以通过 System.out.println()
在路由规则中打印内容来确认,同时注意返回的内容必须为一个闭包。例如:
ovy_v200907@package hqm.test.groovy
public class RoutingRule {
Map<String, List<String>> routingRuleMap() {
return [
"BSeller_address_filter_Key":["10.177.75.54:*"],
"ASeller_address_filter_Key":["10.97.94.33:*"]
]
}
Object argsRoutingRule(String methodName, String[] paramTypeStrs) {
if (methodName.startsWith("checkUrlPermission")) {
System.out.println("Match the checkUrlPermission method.");
return {
Object[] args ->
if(args[1] % 2 == 1 ) {
System.out.println("Route to BSeller_address_filter_Key");
return "BSeller_address_filter_Key.";
} else {
System.out.println("Route to ASeller_address_filter_Key");
return "ASeller_address_filter_Key.";
}
}
}
}
}
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。
评论