这不是教程,只是个人总结,有兴趣的童鞋可以搭配源码看看:acuprpc
eureka client每隔30s向注册中心发送心跳来给自己续命,当注册中心长时间没收到client的信号,就会认为它挂掉了,把它提出群聊。再加上其它服务也按照一定频率更新本地缓存,因此往往不会那么及时地发现曾经的小伙伴已经下线了。导致的后果就是,会向不再存在的节点发送请求,结果连接异常。
对此,我们可以从框架层面加入一个重试机制,spring里面类似的机制也有,但既然在写自己的框架,那就自己实现一个。
在第一章里已经实现了通过动态代理执行远程调用,那么直接从这里入手,通过判断捕获的异常来判断是否需要重试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| @Override public Object invoke(Object proxy, Method method, Object[] args) { if ("toString".equals(method.getName()) && (args == null || args.length == 0)) { return rpcServiceInfo.toString(); } RpcRequest rpcRequest = new RpcRequest(rpcServiceInfo.getAppName(), rpcServiceInfo.getServiceName(), method.getName()); if (args != null && args.length > 0) { rpcRequest.setOrderedParameter(Arrays.stream(args).map(JsonUtil::toJson).collect(Collectors.toList())); } int n = 3; int i = 0; RpcClient client = null; while (i++ < n) { try { client = getRpcClient(); String res = client.invoke(rpcRequest); return JsonUtil.fromJson(res, TypeFactory.defaultInstance().constructType(method.getGenericReturnType())); } catch (Exception e) { if (client == null) { throw e; } boolean rediscover = needRediscover(e) && i < n; log.error("invoke {}/{} {} {} error={} msg={} rediscover={}", i, n, rpcRequest.getKey(), client.getNodeInfo(), e.getClass().getName(), e.getMessage(), rediscover); if (rediscover) { try { NodeInfo nodeInfo = rpcClientManager.selectNode(rpcServiceInfo, client.getNodeInfo()); client.reconnect(nodeInfo); continue; } catch (RpcNotFoundException e1) { e.addSuppressed(e1); } } throw e; } } throw new RuntimeException("invoke error"); }
private boolean needRediscover(Throwable e) { while (e != null) { if (e instanceof HttpStatusException) { if (((HttpStatusException) e).getStatus() == NOT_AVAILABLE) { return true; } } else if (e instanceof ConnectException) { return true; } e = e.getCause(); } return false; }
|
有了重试机制,就不怕某些家伙突然掉链子了,当然如果全部掉链子那就没得玩了。