问题小记(一):Eureka DS Replicas

最近工作中开始搭建工程,发现一个很迷惑的地方 DS Replicas。 之前接触Eureka也只是简单搭建。

现象描述:

eureka在k8s环境起了两台。回家后本地搭建配置文件如下:application-peerA/peerB.yml,外加本地host修改。
application-peerA.yml


EUREKA_INSTANCE_HOSTNAME: peerA
EUREKA_SERVER: http://peerB:8081/eureka/,http://peerA:8080/eureka/
PORT: 8080

server:
  port: ${PORT}
spring:
  application:
    name: eureka-server
eureka:
  server:
    enable-self-preservation: false
    use-read-only-response-cache: false
    eviction-interval-timer-in-ms: 5000
  client:
    registry-fetch-interval-seconds: 5
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: ${EUREKA_SERVER:http://127.0.0.1:${server.port}/eureka/}
  instance:
    hostname: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}
    lease-renewal-interval-in-seconds: 5
    lease-expiration-duration-in-seconds: 10
    instance-id: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}:${server.port}@${random.long(1000000,9999999)}

application-peerB.yml

EUREKA_INSTANCE_HOSTNAME: peerB
EUREKA_SERVER: http://peerA:8080/eureka/,http://peerB:8081/eureka/
PORT: 8081

server:
  port: ${PORT}
spring:
  application:
    name: eureka-server
eureka:
  server:
    #关闭自我保护
    enable-self-preservation: false
    use-read-only-response-cache: false
    #设置自动清理时间
    eviction-interval-timer-in-ms: 5000
  client:
    registry-fetch-interval-seconds: 5
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: ${EUREKA_SERVER:http://127.0.0.1:${server.port}/eureka/}
  instance:
    hostname: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}
    lease-renewal-interval-in-seconds: 5
    lease-expiration-duration-in-seconds: 10
    instance-id: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}:${server.port}@${random.long(1000000,9999999)}

本地host修改如下。

127.0.0.1  peerB
127.0.0.1  peerA

两台服务启动效果如下,只看到peerA页面下DS Replicas只有peerB, peerB下的DS只有peerA。
image


线上环境中两台下面都是这样的。peerA和peerB。


image

现象清楚了,就是本地模拟环境上k8s两台服务时候, DS Replicas展示不一样。

探究现象背后的原因

因为对SpringBoot包括Eureka没有特别深入学习过,所以只能自己尝试看代码发现问题。

localhost:8080页面是怎么渲染出来的

1.在IDEA的帮助下找到了这个接口对应的handler,可以发现两个结论:1. EurekaController就是我们要找的;2.可以通过eureka.dashboard.path配置修改eureka dashboard的地址,默认是/。
image

2.然后就在该Controller中验证了猜想。可以得出结论:方法返回值为String,应该是使了JSP或Freemarker等模板。
image

3.通过IDEA的帮助,定位Class所在包,如左图。可以得出结论:1.确实是使用了freemarker模板;2.status.ftlh就是我们要找的首页模板了。
image

4.发现status.ftlh中没有DS Replicas关键字,在navbar.ftlh中找到的。可以得出结论:replicas这个就是页面渲染使用到的数据,是一个列表。
image

5.于是返回RequestMapping中查找replicas是怎么填充的。可以猜测:PeerEurekaNode这个对象有几个决定页面的DS Replicas。
image


6.到这里也只是发现了DS Replicas和PeerEurekaNode有很大关系,具体是什么还完全没头绪。

PeerEurekaNode是啥?

上一步分析到这里。通过分析调用关系,发现:serverContext是DefaultEurekaServerContext,PeerEurekaNodes具体是RefreshablePeerEurekaNodes。下面只要分析RefreshablePeerEurekaNodes的getPeerNodesView方法即可。
image


1.RefreshablePeerEurekaNodes继承自PeerEurekaNodes,其内部维护一个列表,PeerEurekaNode的集合。 首页用到的就是这个列表的副本。这个属性只有在updatePeerEurekaNodes方法中有修改操作。
image


2.IDEA中查看上述方法只有如下两处调用:第二处可以理解为是环境刷新时候调用,第一处才是最常调用的地方。
image


3.start方法是DefaultEurekaServerContext对象生成完毕后调用,只调用一次。start方法内部用单个专门线程去定期调用一次updatePeerEurekaNodes方法,频率为固定10分钟。
image


4. updatePeerEurekaNodes方法入参为resolvePeerUrls,解析伙伴的URL。其中isThisMyUrl会比较URL的host与本机host相比较,如果相同就会去除掉。

image


5. 继续研究下去发现了InstanceInfo、EurekaInstanceConfigBean、InetUtils、findFirstNonLoopbackHostInfo, 大概明白了主要是k8s环境中eureka的网卡信息上查找到的主机名 和 yml中`eureka.instance.hostname` 天然不一样,所以就导致了DS出现多个结果。 这点在k8s POD中通过 ip addr得到了证实,涉及敏感数据、IP就不贴图了。

image

总结:

小白尝试着查看了代码,分析得到了本地启动的多个eureka中DS不同的原因; 原因是:K8S中eureka是通过statefulset方式部署的,service-url也是用StatefulSet写法写的,POD的环境天生和本地不一样,也算有点收获吧,再深入的话得不偿失了。

posted @ 2021-09-04 17:27  吕彬彬  阅读(1530)  评论(0编辑  收藏  举报