springboot项目发布过程中访问网站有500错误码

问题起因:

当jenkins发布product项目时,访问后台会报出500错误码

排查过程:

项目都有负载均衡,正常不会有此类问题,初始判断可能是缓存问题,导致访问没有到其他节点上,跟开发沟通,排除了这个可能

然后判断可能是因为nacos上服务列表没有刷新,关闭的项目节点还在服务列表中,导致一直有访问到关闭的项目节点
多次尝试发布product项目,然后访问网站,检测出持续报出500错误码的时间大概30秒
修改nacos服务列表的刷新时间,将参数getUpdatedListOfServers降低到15秒,再次测试后发现没变化,而且每次报错的时长都在30秒左右
正常来说即便是服务列表没有及时刷新,也不可能每次都是30秒,这相当于每次发布刚好卡在列表刚刷新完的那个时间点,这在概率上来讲是不可能的
所以判断也不是这个问题,排查的方向错了

但是也因此可以发现,即便是刷新了服务列表,已经停止的项目依然在服务列表中,查看nacos管理界面的服务列表

果然,即便发布过程中,已经将一个节点停止了,但是在nacos的服务列表中还显示在线,而且还是绿的,大概过15秒才会变成红色,然后再过15秒被释放

问题原因:

根据排查的结果,可以判断出,当节点的项目停止时,没有给nacos发送’我要停止’的消息,导致nacos以为节点的项目还在线,网关服务也就一直给停止的节点发送数据

解决方法:

nacos作为注册中心,支持两种服务下线,一种是客户端主动调用api向服务端发送服务下线,然后实现服务下线,第二种就是服务故障,然后服务端很长时间没有收到某个实例的心跳信息,服务端就会将这个服务健康状态设置成false,也就是标志不健康状态(这个时间默认是15s,也就是15s服务端没有收到某个服务的心跳信息),如果更长时间没有收到心跳信息,直接就会将这个服务摘除(默认是30s)。

根据上述原理还需要查看到底是客户端没有调用api向服务端发送服务下线,还是服务故障

先看后者,后者较容易排查,而且前者很可能是开发的问题,所以此处使用排除法

后者所说的服务故障,一般来讲是强制关闭或者网络中断,此处排除网络中断,强制关闭需要看docker关闭容器的过程

节点的服务是通过docker进行部署,发布过程中停止容器肯定用的是docker stop的方法,当你通过命令 docker stop mycontainer 来停止容器时,docker CLI 会将 TERM 信号发送给 mycontainer 的 PID 为 1 的进程,这就需要看 PID 为 1 的进程到底是什么(此处引入了docker 优雅关闭容器的问题,可以查看我的另一个文章https://www.wmmzz.com/docker-youyaguanbirongqi/),根据排查和调整,用strace命令跟踪信号值

从图中可以看出, pid 为 1 的进程在docker stop 的时候是收到了 SIGTERM 的信号了

也就是说docker stop 并没有让服务强制关闭,而是服务本身没有调用api向服务端发送服务下线通知

最终解决的方法应该是让开发把这个下线通知的功能加上,但是在解决这个问题的过程中也找到了一个其他方法,这个方法也可以让服务下线,可以看我这个文章https://www.wmmzz.com/springbootxiangmulianjienacosshiyouyaguanbi/

更新:

开发将下线通知nacos的代码加上了,关闭后的日志输出如下:

根据实际测试,关闭docker容器服务后,在nacos里服务列表中的记录就直接没了,这种方法比上面用curl命令的方法更好

但是改用这种方式后,再测试发布还是会有code 500的问题

期间又将ribbon下的很多参数进行了调整,但是都不理想,只有将ServerListRefreshInterval参数调低,才能有所改善,可是还会有code 500,只是时间变短了

ribbon:
  eureka:
    enabled: true
  http:
    client:
      enabled: true
  okhttp:
    enabled: false
  ## 从注册中心刷新servelist的时间 默认30秒,单位ms
  ServerListRefreshInterval: 2000
  ## 请求连接的超时时间 默认1秒,单位ms
  ConnectTimeout: 1000
  ## 请求处理的超时时间 默认1秒,单位ms
  ReadTimeout: 30000
  ## 对所有操作请求都进行重试,不配置这个MaxAutoRetries不起作用 默认false
  OkToRetryOnAllOperations: true
  ## 对所有错误进行重试
  OkToRetryOnAllErrors: false
  ## 跟服务端建立连接时出现错误
  OkRetryOnConnectionErrors: true
  ## 切换实例的重试次数 默认1
  MaxAutoRetriesNextServer: 2
  ## 对当前实例的重试次数 默认0
  MaxAutoRetries: 0
  retryableStatusCodes: 500,404,502
  restclient:
    enabled: true

最终解决办法:

其实还是配置的问题,网关服务本身也有重试机制,在nacos的网关服务配置文件中加入以下代码,最终发布不再有code 500

default-filters:
        - DedupeResponseHeader=Vary Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_FIRST
        - name: Retry
          args:
            retries: 3
            statuses: 
              - BAD_GATEWAY
              - SERVICE_UNAVAILABLE
              - GATEWAY_TIMEOUT
            ## GET,POST,PUT
            methods: 
              - GET
              - PATCH
              - DELETE
              - OPTIONS
              - HEAD
            exceptions: 
              - org.springframework.cloud.gateway.support.NotFoundException
              - java.io.IOException
              - org.springframework.cloud.gateway.support.TimeoutException

配置结构在spring.cloud.gateway.下面,以下是结构比较全面的配置

spring:
  cloud:
    sentinel:
      eager: true
      transport:
        dashboard: ${meta.sentinel.base-url}
        heartbeat-interval-ms: 2000
      filter:
        enabled: true
      datasource:
        flow:
          nacos:
            namespace: ${meta.gateway.nacos.namespace}
            server-addr: ${meta.gateway.nacos.address}
            dataId: ${spring.application.name}-sentinel-flow-rules
            groupId: SENTINEL_GROUP
            ruleType: flow
        degrade:
          nacos:
            namespace: ${meta.gateway.nacos.namespace}
            server-addr: ${meta.gateway.nacos.address}
            dataId: ${spring.application.name}-sentinel-degrade-rules
            groupId: SENTINEL_GROUP
            ruleType: degrade
        system:
          nacos:
            namespace: ${meta.gateway.nacos.namespace}
            server-addr: ${meta.gateway.nacos.address}
            dataId: ${spring.application.name}-system-rules
            groupId: SENTINEL_GROUP
            rule-type: system
        authority:
          nacos:
            namespace: ${meta.gateway.nacos.namespace}
            server-addr: ${meta.gateway.nacos.address}
            dataId: ${spring.application.name}-authority-rules
            groupId: SENTINEL_GROUP
            rule-type: authority
        param-flow:
          nacos:
            namespace: ${meta.gateway.nacos.namespace}
            server-addr: ${meta.gateway.nacos.address}
            dataId: ${spring.application.name}-param-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: param-flow
    loadbalancer:
      retry:
        enabled: true
    gateway:
      discovery:
        locator:
          enabled: false
          lowerCaseServiceId: true
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedHeaders: "*"
            allowedMethods: "*"
      default-filters:
        - DedupeResponseHeader=Vary Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_FIRST
        - name: Retry
          args:
            retries: 3
            statuses: 
              - BAD_GATEWAY
              - SERVICE_UNAVAILABLE
              - GATEWAY_TIMEOUT
            ## GET,POST,PUT
            methods: 
              - GET
              - PATCH
              - DELETE
              - OPTIONS
              - HEAD
            exceptions: 
              - org.springframework.cloud.gateway.support.NotFoundException
              - java.io.IOException
              - org.springframework.cloud.gateway.support.TimeoutException

参考文献:

https://www.jianshu.com/p/5c4903cd328b

https://www.jianshu.com/p/62bee46faa02

https://blog.csdn.net/yuanshangshenghuo/article/details/111290929

https://blog.csdn.net/yuanshangshenghuo/article/details/111299177

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值