}
if (ttlScheduler != null) {
ttlScheduler.remove(serviceId);
}
log.info(“Deregistering service with consul: {}”, serviceId);
client.agentServiceDeregister(serviceId);
}
…
}
我们可以看到,当应用关闭时候的注销操作是通过调用client.agentServiceDeregister(serviceId)
来实现的。其中client
是consul-api的com.ecwid.consul.v1.ConsulClient
实例。而agentServiceDeregister
方法则是对/v1/agent/service/deregister/<serviceID>
接口的实现,该接口主要用来从Consul Agent
中根据serviceId
来注销实例。
以此实现为范例,于是开始的思路是这样的:
-
先通过
consulClient.getHealthServices(serviceId, false, null)
根据serviceId
来获取服务实例清单 -
遍历实例清单中有不是PASSING状态的实例,就调用
client.agentServiceDeregister(serviceId)
来剔除
具体实现如下:
@RestController
public class ApiController {
@Autowired
private ConsulClient consulClient;
@RequestMapping(value = “/unregister/{id}”, method = RequestMethod.POST)
public String unregisterServiceAll(@PathVariable String id) {
List response = consulClient.getHealthServices(id, false, null).getValue();
for(HealthService service : response) {
service.getChecks().forEach(check -> {
if(!check.getStatus().name().equals(Check.CheckStatus.PASSING.name())) {
logger.info(“unregister : {}”, check.getServiceId());
consulClient.agentServiceDeregister(check.getServiceId());
}
});
}
return null;
}
}
但是,在测试后发现该方法只能剔除同一个agent上的非PASSING实例。
Catalog误区
继续搜索了一下Consul的文档,发现了这个接口:/v1/catalog/deregister
: Deregisters a node, service, or check。于是,尝试了用该接口来替换之前的consulClient.agentServiceDeregister(check.getServiceId());
实现。
CatalogDeregistration catalogDeregistration = new CatalogDeregistration();
catalogDeregistration.setDatacenter(“dc1”);
catalogDeregistration.setNode(check.getNode());
catalogDeregistration.setServiceId(check.getServiceId());
catalogDeregistration.setCheckId(check.getCheckId());
consulClient.catalogDeregister(catalogDeregistration);
经过测试,该方法可以实现短暂的剔除,但是过一段时间之后这些被剔除的实例又都恢复回来了……也就是说这个接口完全没有什么卵用!
那么为什么会出现这种情况呢?我们可以在Github中找到这个维持了一年多的问题讨论:https://github.com/hashicorp/consul/issues/1188
。整个讨论过程非常曲折,虽然当前该问题还依然在open状态,但是一些回复也基本够我们去理解它的原因了。比如下面这条评论:
You cannot deregister a service from the agent on a different node, service only exists on the agent you have registered with. It also exists in the catalog on all nodes, but that is not related to the agent itself. And to be honest I don’t understand why there is a catalog/deregister endpoint at all, in my opinion catalog should be a read-only service list.
从该评论中,我们可以知道一个重要信息:**服务实例只能在注册的Agent上进行注销!**另外,对于/v1/catalog/deregister
接口,目前还是有不少争议的,因为根本没啥用。
最终实现