【踩坑日常】解决Eureka启动报错:Network level connection to peer localhost;retrying after delay

🏆项目场景:

最近在使用Spring Cloud的Eureka服务时,遇到了一个线上问题:Eureka启动一直报错,提示Network level connection to peer localhost;retrying after delay。通过一番排查,发现问题的根本原因竟然是配置文件中的eureka defaultZone未生效,而造成这一情况的直接原因是spring.profiles未正确激活。

ERROR 3144 --- [et_localhost-12] c.n.e.cluster.ReplicationTaskProcessor   : Network level connection to peer localhost; retrying after delay

com.sun.jersey.api.client.ClientHandlerException: org.apache.http.conn.ConnectTimeoutException: Connect to localhost:8761 timed out
    at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar:1.19.1]
    at com.netflix.eureka.cluster.DynamicGZIPContentEncodingFilter.handle(DynamicGZIPContentEncodingFilter.java:48) ~[eureka-core-1.4.10.jar:1.4.10]
    at com.netflix.discovery.EurekaIdentityHeaderFilter.handle(EurekaIdentityHeaderFilter.java:27) ~[eureka-client-1.4.10.jar:1.4.10]
    at com.sun.jersey.api.client.Client.handle(Client.java:652) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.netflix.eureka.transport.JerseyReplicationClient.submitBatchUpdates(JerseyReplicationClient.java:116) ~[eureka-core-1.4.10.jar:1.4.10]
    at com.netflix.eureka.cluster.ReplicationTaskProcessor.process(ReplicationTaskProcessor.java:71) ~[eureka-core-1.4.10.jar:1.4.10]
    at com.netflix.eureka.util.batcher.TaskExecutors$BatchWorkerRunnable.run(TaskExecutors.java:187) [eureka-core-1.4.10.jar:1.4.10]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_92]
Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to localhost:8761 timed out

✨问题描述

在Eureka配置文件中,我们正常地配置了eureka defaultZone,但在启动应用后却一直报错,无法连接到Eureka服务器。初步怀疑是网络问题,但通过排查发现并非如此。最终,我们锁定了问题根源——spring.profiles未正确激活。

当时配置文件

spring:
  application:
    name: prod_eureka
server:
  port: 8810
security:
    basic:
      enabled: true
    user:
      name: admin
      password: 1q2w3e4r5t6y7U
eureka:
  environment: prod
  server:
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 30000
---
spring:
  profiles: jm-citymap-common-prod01
eureka:
  instance:
    hostname: jm-citymap-common-prod01
    instance-id: ${spring.cloud.client.ipAddress}:${server.port}
  client:
    register-with-eureka: true
    fetch-registry: true
    serviceUrl:
      defaultZone: http://admin:1q2w3e4r5t6y7U@jm-citymap-common-prod02:8810/eureka/


🔎原因分析:

  • defaultZone 配置

从配置文件看并没有出现localhost ,那从哪来的。查询eureka的服务注册发现相关源码剖析
EurekaClientConfigBean

    public EurekaClientConfigBean() {
        this.serviceUrl.put("defaultZone", "http://localhost:8761/eureka/");
		//...
    }

如果defaultZone没配置,默认就是http://localhost:8761/eureka/,而eureka server确实是配置了defaultZone。那会不会是配置的defaultZone 没生效。

  • Profiles 激活

从配置文件发现defaultZone配置是配置到了名为jm-citymap-common-prod01spring profiles 中。如果需要defaultZone 生效,必须激活名为jm-citymap-common-prod01spring profiles
查看配置和启动命令。都没有激活jm-citymap-common-prod01


✌解决方案:

在启动命令上加-Dspring.profiles.active=jm-citymap-common-prod01,激活jm-citymap-common-prod01.

nohup java -jar -Xms512m -Xmx512m -Dspring.profiles.active=jm-citymap-common-prod01 cloud-eureka.jar /opt/app/eureka/logs/ 2>&1 &

📜相关补充

Spring Profiles介绍

在 Spring Framework 中,Profile 是一种用于定义一组 Bean 定义和配置的机制,这些 Bean 定义和配置仅在特定的运行时环境或应用程序配置下生效。通过使用 Profile,你可以根据应用程序运行的环境,如开发环境、测试环境、生产环境等,来灵活地管理不同的配置。

在 Spring 中,可以通过以下方式使用 Profile:

  • 在 XML 配置文件中使用 Profile
<beans>
    <!-- Common bean definitions -->

    <beans profile="dev">
        <!-- Bean definitions for development environment -->
    </beans>

    <beans profile="prod">
        <!-- Bean definitions for production environment -->
    </beans>
</beans>

  • 在注解配置中使用 Profile
@Configuration
public class AppConfig {

    @Bean
    @Profile("dev")
    public DataSource dataSourceDev() {
        // DataSource for development environment
    }

    @Bean
    @Profile("prod")
    public DataSource dataSourceProd() {
        // DataSource for production environment
    }
}

  • 在属性文件中使用 Profile
# Common properties

---
spring:
  profiles: dev
# Properties for development environment

---
spring:
  profiles: prod
# Properties for production environment

profiles的激活方式

在Spring中,有多种方式可以激活profiles。以下是其中常用的几种方式:

  • 命令行参数,在运行时使用-Dspring.profiles.active参数来指定激活的profile
java -jar your-application.jar -Dspring.profiles.active=dev
  • 配置文件,在application.properties或者application.yml中直接配置
spring.profiles.active=dev
  • 在代码中激活,在启动类或者配置类中通过Java代码来激活profiles
@SpringBootApplication
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(YourApplication.class);
        application.setAdditionalProfiles("dev");
        application.run(args);
    }
}

😜小结

通过这次问题的排查和解决,深刻认识到了Spring Profiles的重要性。在项目开发中,合理使用Profiles能够更好地适应不同的环境,提高系统的灵活性和可维护性。同时,在配置Eureka时,确保eureka defaultZone正确配置也是至关重要的。

### 解决方案分析 当尝试建立与对等服务器 `server2` 的网络级连接时遇到错误,可能的原因在于端口或地址冲突以及NAT穿透问题。 #### 地址重用冲突 如果之前的 `outboundconnect()` 尝试使用了一组源和目标端点组合,而这些端点现在已被另一个套接字占用,则异步 `connect()` 请求通常会在某个时刻失败,并返回“地址已在使用”的错误消息[^1]。尽管如此,应用程序仍然拥有用于通信的工作P2P流套接字,因此可以忽略此失败并继续操作。 #### NAT兼容性和洞穿支持 对于TCP协议,在286个数据样本中,有184个(占总数的64%)展示了与TCP打孔技术的良好兼容性:NAT设备会一致地转换客户端私有的TCP端点,并不会因未请求的入站连接尝试发送RST包作为响应。然而,回环翻译的支持率要低得多——仅37份报告(占比约13%)显示了针对TCP的此类特性支持[^4]。 为了有效解决问题: - **确认本地资源释放**:确保之前创建的所有套接字已正确关闭,防止新连接由于端口被占用而导致失败。 - **调整防火墙/NAT设置**:检查是否有任何安全策略阻止来自特定IP范围的数据传输;考虑配置静态映射或者启用UPnP来简化外部访问过程。 - **实施TCP Hole Punching机制**:利用该方法绕过某些类型的NAT限制,提高成功建立直接P2P连接的可能性。 ```python import socket def establish_connection(server_address, port): sock = None try: # 创建一个新的socket对象 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置SO_REUSEADDR选项允许快速重启服务而不必等待TIME_WAIT状态结束 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 进行连接前先绑定到指定接口上的随机可用端口 sock.bind(('0.0.0.0', 0)) # 发起连接请求 sock.connect((server_address, port)) print(f"Connection established successfully.") return sock except Exception as e: print(f"Failed to connect: {e}") if sock is not None: sock.close() raise finally: pass # 可在此处添加清理逻辑 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Abner G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值