nacos-group / r-nacos

Nacos server re-implemented in Rust.
https://r-nacos.github.io/docs/
Apache License 2.0
992 stars 104 forks source link

nginx反代nacos之后,Spring项目无法使用http协议连接rnacos #130

Closed jayxuz closed 2 months ago

jayxuz commented 3 months ago

使用版本 v0.5.20 docker版本部署 使用ip:8848启动项目一切正常

根据文档 应用服务通过nginx链接nacos场景迁移方案

配置nginx后,老spring项目启动报错

ava.lang.reflect.UndeclaredThrowableException: null
    at org.springframework.util.ReflectionUtils.rethrowRuntimeException(ReflectionUtils.java:354) ~[spring-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at com.alibaba.cloud.nacos.registry.NacosServiceRegistry.register(NacosServiceRegistry.java:73) ~[spring-cloud-starter-alibaba-nacos-discovery-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration.register(AbstractAutoServiceRegistration.java:219) ~[spring-cloud-commons-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    at com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration.register(NacosAutoServiceRegistration.java:76) ~[spring-cloud-starter-alibaba-nacos-discovery-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration.start(AbstractAutoServiceRegistration.java:118) ~[spring-cloud-commons-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    at org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration.bind(AbstractAutoServiceRegistration.java:82) ~[spring-cloud-commons-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    at org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration.onApplicationEvent(AbstractAutoServiceRegistration.java:69) ~[spring-cloud-commons-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    at org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration.onApplicationEvent(AbstractAutoServiceRegistration.java:32) ~[spring-cloud-commons-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:398) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:355) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:166) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at xxx.xxx.xxx.XXXApplication.main(XXXXApplication.java:31) [classes/:na]
Caused by: com.alibaba.nacos.api.exception.NacosException: failed to req API:/api//nacos/v1/ns/instance after all servers([https://nacos.xxxxx.com]) tried: 
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:496) ~[nacos-client-1.2.1.jar:na]
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:401) ~[nacos-client-1.2.1.jar:na]
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:397) ~[nacos-client-1.2.1.jar:na]
    at com.alibaba.nacos.client.naming.net.NamingProxy.registerService(NamingProxy.java:212) ~[nacos-client-1.2.1.jar:na]
    at com.alibaba.nacos.client.naming.NacosNamingService.registerInstance(NacosNamingService.java:207) ~[nacos-client-1.2.1.jar:na]
    at com.alibaba.cloud.nacos.registry.NacosServiceRegistry.register(NacosServiceRegistry.java:64) ~[spring-cloud-starter-alibaba-nacos-discovery-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    ... 20 common frames omitted

本来以为是配置了https的原因,切换到http的nginx配置后同样报错

heqingpan commented 3 months ago

那应该是http代理配置有问题(也可能是文档上的配置有问题,我晚上回去再确认一遍)。

你可以把你的nginx配置发出来看看(ip或域名可以用xxx替代)。

另外可以按进一步确认问题

  1. 可以先看看r-nacos 服务日志是否收到请求,是否有报错 2.可以用curl直接请求nginx反向代理后的接口,看看响应是否正常。(比如curl http://nginx_host:port/nacos/v1/console/namespaces
jayxuz commented 2 months ago

那应该是http代理配置有问题(也可能是文档上的配置有问题,我晚上回去再确认一遍)。

你可以把你的nginx配置发出来看看(ip或域名可以用xxx替代)。

另外可以按进一步确认问题

  1. 可以先看看r-nacos 服务日志是否收到请求,是否有报错 2.可以用curl直接请求nginx反向代理后的接口,看看响应是否正常。(比如curl http://nginx_host:port/nacos/v1/console/namespaces

配置如下

server {
    listen       443 ssl http2;
    server_name  nacos.xxx.com;

    ssl_certificate  /etc/nginx/conf.d/xxxxx.com.pem;
    ssl_certificate_key /etc/nginx/conf.d/xxxxx.com.key;
    ssl_session_timeout 5m;

    location /nacos {
        proxy_set_header Host $proxy_host;
        proxy_pass   http://192.168.xxx.xxx:8848;
    }

}

server {
    listen 80;
    server_name  nacos.xxx.com;
    # rewrite ^(.*)$ https://${server_name}$1 permanent;

    location /nacos {
        proxy_set_header Host $proxy_host;
        proxy_pass   http://192.168.xxx.xxx:8848;
    }
}

原本是让所有的http请求重定向到https的,发现https连接不上之后,改了80的转发配置,还是连不上。之前用java版nacos是正常的。 当前配置下,curl http://nacos.xxxxxx.com/nacos/v1/console/namespaces 请求能正常返回 curl -d POST http://nacos.xxxxxx.com/nacos/v1/console/namespaces 也能正常注册服务 但是spring项目启动仍然报错。看java运行情况,配置中心能够成功取到,但是在注册中心注册服务时失败导致服务启动失败

rnacos在服务注册失败时报错

[2024-08-29 06:38:44.533082 +00:00 ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[2024-08-29 06:38:44.536179 +00:00 ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[2024-08-29 06:38:44.538729 +00:00 ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[2024-08-29 06:38:44.541443 +00:00 ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided

因为是老项目了,用的nacos-client很旧了,是1.2.1 nacos-client, 通过下面的pom引入的

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>
heqingpan commented 2 months ago

从r-nacos服务端报错来看,应该是解析部分http请求header不符合预期。

从现象看走nginx后部分接口能成功部分失败,可以初步判断和nginx有关,走它后引发部分接口兼容性问题。

出问题的应用关于nacos的配置方便的话可以提供一下。 我后面回去你你的这个版本试试看是否能复现,如果能复现就好解决。

另外,客户端的报错路径有点奇怪:

Caused by: com.alibaba.nacos.api.exception.NacosException: failed to req API:/api//nacos/v1/ns/instance after all servers([https://nacos.xxxxx.com]) tried:     at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:496) ~[nacos-client-1.2.1.jar:na]

日志中的路径是/api//nacos/v1/ns/instance ,确认一下是不是客户端配置的地址不对?

jayxuz commented 2 months ago

从r-nacos服务端报错来看,应该是解析部分http请求header不符合预期。

从现象看走nginx后部分接口能成功部分失败,可以初步判断和nginx有关,走它后引发部分接口兼容性问题。

出问题的应用关于nacos的配置方便的话可以提供一下。 我后面回去你你的这个版本试试看是否能复现,如果能复现就好解决。

另外,客户端的报错路径有点奇怪:

Caused by: com.alibaba.nacos.api.exception.NacosException: failed to req API:/api//nacos/v1/ns/instance after all servers([https://nacos.xxxxx.com]) tried:   at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:496) ~[nacos-client-1.2.1.jar:na]

日志中的路径是/api//nacos/v1/ns/instance ,确认一下是不是客户端配置的地址不对?

这个配置的路径肯定是没问题的,也没什么空格之外的额外的字符,因为填ip加端口时就一切正常,没有报错。 客户端配置也很普通,配置都用的nacos读出的,所以启动参数很少。 个人猜测rnacos接口对请求头校验太严格或者缺少关键的nginx配置

spring:
  application:
    name: xxxxx
  cloud:
    nacos:
      discovery:
        server-addr: http://nacos.xxx.com #报错
        # server-addr: 192.168.x.x:8848 #正常启动
        # server-addr: http://192.168.x.x:8848 #正常启动
        enabled: true
        username: nacos
        password: nacos
        namespace: test
      config:
        server-addr: http://nacos.xxx.com #报错
        # server-addr: 192.168.x.x:8848 #正常启动
        # server-addr: http://192.168.x.x:8848 #正常启动
        group: BASE_GROUP 
        file-extension: yaml
        username: nacos
        password: nacos
        namespace: test
  profiles:
    active: dev
server:
  port: 30054
jayxuz commented 2 months ago

另外切换了rnacos 0.1.10的旧版本进行测试,发现仍然是同样的状态 ip+端口能正常启动项目 而使用nginx做代理之后启动报错,同样是注册服务失败。 rnacos日志中报错

[2024-08-29T07:55:18Z ERROR actix_http::h1::dispatcher] stream error: Request parse error: Invalid Header provided

nginx转发日志中参数复制出来用curl调用正常。

感觉此兼容问题rnacos应该一直存在。 可能升级nacos依赖能解决问题,但是由于是历史项目,pom更改涉及到的依赖变更太多,还是希望能够能从rnacos和nginx端解决问题。 目前生产环境运行的nacos占用内存太大(接近20G),还是很希望能够替换rnacos释放多余的内存的。

heqingpan commented 2 months ago

收到,我这边晚点尝试看能不能在我本地复现,如果能复现会尽快解决。

heqingpan commented 2 months ago

这个问题和nginx有关,如果方便的话也提供一下nginx的版本号。尽量用和你们一样的版本号,提高在我本地复现的概率。

heqingpan commented 2 months ago

我这边本地可以复现,这个问题争取本周末解决。

heqingpan commented 2 months ago

已定位到原因并找到解决方案。

按上面的nginx配置,请求通过nginx代理后多了一个header Connection: close

可通过增加nginx配置解决问题,代理配置内容如下:

proxy_pass  http://xxx;
proxy_set_header  Host $host;

proxy_set_header  Connection "";
proxy_http_version  1.1;
jayxuz commented 2 months ago

已定位到原因并找到解决方案。

按上面的nginx配置,请求通过nginx代理后多了一个header Connection: close

可通过增加nginx配置解决问题,代理配置内容如下:

proxy_pass  http://xxx;
proxy_set_header  Host $host;

proxy_set_header  Connection "";
proxy_http_version  1.1;

采用此配置后解决问题,现在能完美实现启动项目。 非常感谢! 终于可以着手准备生产环境的rnacos替换了

另外贴一下当前的nginx配置供其他人参考,能够让用户网页访问时默认跳转到管理端 防止因为nacos管理地址从/nacos切换到/rnaocs导致找不到管理页面的问题。

server {
        listen 80;
        server_name  nacos.xxx.com;

    location /rnacos {
        proxy_pass   http://192.168.xxx.xxx:10848;
    }

    location /nacos {
        proxy_pass   http://192.168.xxx.xxx:8848;
        proxy_set_header Host $proxy_host;
        proxy_set_header  Connection "";
        proxy_http_version  1.1;
    }

    location = / {
        rewrite ^/$ /rnacos permanent;
    }
}

希望rnacos能在后续版本中通java版本一样将管理端web和/nacos接口合并在同一端口下

heqingpan commented 2 months ago

关于控制台用单独的端口主要是为了安全的支持把控制台暴露到外网,有需要合并的通过nginx代理也比较方便做到。所以暂时不打算调整这块。

我们想收集下真实用户切换r-nacos前后的资源使用对比,以便把真实情况告知给其它潜在用户参考。

你们后面如果线上切换后,方便的话可以抽空再到这说明下你们切换后的资源使用情况,谢谢😃