服务端下线接口
@GetMapping(path = "/shutdown")
public String shutdown() {
//主动将自身从eureka服务器注销
DiscoveryManager.getInstance().shutdownComponent();
return "ok";
}
客户端
获取可用服务信息
@Resource
private CachingSpringLoadBalancerFactory lbClientFactory;
@Value("${spring.application.name}")
private String applicationName;
@GetMapping(path = "/serverList")
public Map<String, List<MachineDTO>> getServerList() {
DiscoveryClient discoveryClient = DiscoveryManager.getInstance().getDiscoveryClient();
List<Application> applications = discoveryClient.getApplications().getRegisteredApplications();
if (CollectionUtils.isEmpty(applications)) {
return Collections.emptyMap();
}
List<MachineDTO> machineList;
Map<String, List<MachineDTO>> result = Maps.newHashMap();
for (Application application : applications) {
// 过滤掉自身服务信息
if (application.getName().equalsIgnoreCase(applicationName)) {
continue;
}
machineList = application.getInstances().stream()
.map(item -> new MachineDTO(item.getIPAddr(), String.valueOf(item.getPort())))
.collect(Collectors.toList());
result.put(application.getName(), machineList);
}
return result;
}
/**
* 机器信息
* @author liuyong
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MachineDTO {
private String ip;
private String port;
}
触发下线与刷新本地缓存
@GetMapping(path = "/offline")
@SuppressWarnings({"rawtypes"})
public String offlineFormService(@RequestParam String ip, String port) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InterruptedException {
// 给服务端发送请求,要求下线
URL url = new URL("http://" + ip + ":" + port + "/quickform/shutdown");
URLConnection connection = url.openConnection();
connection.connect();
String responseStr = new BufferedReader(new InputStreamReader(connection.getInputStream())).lines()
.collect(Collectors.joining());
String success = "ok";
if (!success.equals(responseStr)) {
return "下线远程服务失败";
}
FeignLoadBalancer feignLoadBalancer = lbClientFactory.create(InterfaceService.SERVICE_NAME);
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) feignLoadBalancer.getLoadBalancer();
// ribbion负载均衡操作时,从balancer中获取可用的服务地址,因此可以用来判断是否更新成功
int curAvailableCount = loadBalancer.getReachableServers().size();
do {
//触发下线后,不能eureka服务端信息更新也有延迟,因此需要重试
TimeUnit.SECONDS.sleep(1);
//更新eureka
updateEurekaInfo();
//调用更新ribbon环境的机器信息
loadBalancer.updateListOfServers();
} while (curAvailableCount == loadBalancer.getReachableServers().size());
return "下线成功!";
}
// eureka缓存的机器信息
private void updateEurekaInfo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
DiscoveryClient discoveryClient = DiscoveryManager.getInstance().getDiscoveryClient();
Method fetchRegistry = DiscoveryClient.class.getDeclaredMethod("fetchRegistry", boolean.class);
fetchRegistry.setAccessible(true);
fetchRegistry.invoke(discoveryClient, true);
}
总结
本文为单机测试代码,对于线上的实际情况,需要在触发服务器下线后,给所有客户端机器广播下线消息,从而让所有的客户端进行都刷新操作!!!
网友评论