报错信息
使用Groovy脚本配置服务的路由规则未生效。
可能原因
上述报错信息表明调用没有被路由到预期的机器上,可能原因是规则配置错误,例如路由规则填写错误、路由规则里的IP没有提供服务等。路由规则的配置方式,请参见 Routing Rule Wiki。
解决方案
您可以通过以下步骤,排查路由规则是否生效。
步骤一:客户端是否为本地调用、泛化调用
如果客户端通过本地调用、泛化调用的方式消费服务,将不会使用路由规则逻辑,因此会出现路由规则不生效的情况。
- 本地调用:指一个进程既是一个服务的发布者,又是这个服务的消费者。此时,HSF默认优先使用本地调用,即进程内的Java调用,而非RPC调用。这种情况不使用路由规则的逻辑。
- 泛化调用:指不依赖服务的二方包,直接通过GenericService通过服务描述进行消费的场景。此时,HSF由于没有服务的Class,无法执行路由规则里调用业务类的逻辑,因此也不使用路由规则的逻辑。
HSFOPS上的服务测试功能使用的是泛化调用,因此路由规则也不会生效。
步骤二:客户端是否收到路由规则
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上的环境和客户端所在的环境是否一致。
步骤三:路由规则是否正确解析
在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 ,检查您的路由规则。
步骤四:路由规则的内容是否正确
收到路由规则且解析正确后,如果路由规则执行的效果仍与预期不同,请依次检查以下内容。
- 确认路由的目标机器是否提供该服务。
请在对应环境的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 empty 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
中找不到相应值,则认为这一级对路由地址不做限制,地址取上一级的全部地址。总体的计算过程如下:- 接口级路由规则(正则式)最终地址列表会和同机房规则结果地址列表作交集。
- 方法级路由规则(正则式)最终地址列表会和接口级地址列表作交集。
- 参数级路由规则(正则式)最终地址列表会和方法级地址列表作交集。
步骤五:路由规则是否被调用
如果按照以上内容排查后均确认无误,请再确认路由规则指定的服务或方法是否被调用。如果相应的方法没有被调用,则在目标机器上肯定也搜不到调用日志。
可以通过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.";
}
}
}
}
}