所有文章
https://www.cnblogs.com/lay2017/p/11908715.html
正文
入口
上文我们说到,eureka是使用jersey来对外提供restful风格的rpc调用的。我们得找到注册服务的Resource(对应springmvc的controller)
ApplicationResource类中的addInstance方法将作为服务端注册服务的入口
private final PeerAwareInstanceRegistry registry; @POST @Consumes({"application/json", "application/xml"}) public Response addInstance(InstanceInfo info, @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { //... registry.register(info, "true".equals(isReplication)); return Response.status(204).build(); }
可以看到,是调用了PeerAwareInstanceRegistry的register方法
跟进register方法
@Override public void register(final InstanceInfo info, final boolean isReplication) { // ... super.register(info, leaseDuration, isReplication); replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication); }
register方法主要做了两件事
1)注册实例信息
2)复制到其它节点
我们关注注册实例,跟进super.register方法
register方法很长,我们看看核心的流程
private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry = new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>(); public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) { try { Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName()); if (gMap == null) { final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap<String, Lease<InstanceInfo>>(); gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap); if (gMap == null) { gMap = gNewMap; } } Lease<InstanceInfo> lease = new Lease<InstanceInfo>(registrant, leaseDuration); gMap.put(registrant.getId(), lease); // 省略 } finally { // } }
看起来比较简单,其实就是将InstanceInfo给添加到了registry集合当中。我们重点关注一下registry的存储结构
它是由两层Map组合而成,我们用一个json示例来表示改registry结构
{ "商品服务": { // 服务名 "实例的唯一ID": { // 实例标识符 "lease": { // 持有实例信息 "instanceInfo": { // 实例信息 "appName": "商品服务", "instanceId": "实例的唯一ID", "ipAddr": "IP地址", "port": "调用端口" } } } } }
其实就是根据服务与实例一对多的结构来存放服务的集群信息的。
总结
eureka采用jersey来提供rpc服务,注册服务实际上就是向registry添加了一份实例信息。不过我们可以看到Eureka并没有对实例数据进行持久化,所以实例数据都是瞬时态的,这与zookeeper的做法存在区别。