Skip to content

springcloud优雅下线服务

问题场景

线上问题需要紧急修复部署,但是服务一直在跑,网关还会一直往服务中路由请求进行处理,如果直接停掉服务,客户端会出现业务中断的问题。因此需要在替换更新前先手动下线服务,这样用户请求不会被分发到下线的节点上,就可以直接进行更新而不影响用户体验。

实现

查询注册中心中服务的状态

bash
curl -X GET -u eureka_username:eureka_password http://eureka_ip:eureka_port/eureka/apps/服务名称/实例ip:实例名称:实例port

例如

bash
curl -X GET -u admin:admin123 http://127.0.0.1:19991/eureka/apps/app-platform/127.0.0.1:app-platform-1.0.0-SNAPSHOT:8001

结果

xml

<instance>
    <instanceId>127.0.0.1:app-platform-2.0.0-SNAPSHOT:8001</instanceId>
    <hostName>127.0.0.1</hostName>
    <app>app-platform</app>
    <ipAddr>127.0.0.1</ipAddr>
    <status>UP</status>
    # 状态为在线
    <overriddenstatus>UNKNOWN</overriddenstatus>
    # 重写状态为空
    <port enabled="true">8001</port>
    <securePort enabled="false">443</securePort>
    <countryId>1</countryId>
    <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
    </dataCenterInfo>
    <leaseInfo>
        <renewalIntervalInSecs>10</renewalIntervalInSecs>
        <durationInSecs>30</durationInSecs>
        <registrationTimestamp>1636639654493</registrationTimestamp>
        <lastRenewalTimestamp>1636961178498</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1636639654493</serviceUpTimestamp>
    </leaseInfo>
    <metadata>
        <management.port>8001</management.port>
        <nodeId>127.0.0.1_kkg</nodeId>
    </metadata>
    <homePageUrl>http://127.0.0.1:8001/</homePageUrl>
    <statusPageUrl>http://127.0.0.1:8001/actuator/info</statusPageUrl>
    <healthCheckUrl>http://127.0.0.1:8001/actuator/health</healthCheckUrl>
    <vipAddress>app-platform</vipAddress>
    <secureVipAddress>app-platform</secureVipAddress>
    <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
    <lastUpdatedTimestamp>1636639654493</lastUpdatedTimestamp>
    <lastDirtyTimestamp>1636639654480</lastDirtyTimestamp>
    <actionType>ADDED</actionType>
</instance>

通知注册中心服务下线

bash
curl -i -X PUT -u eureka_username:eureka_password http://eureka_ip:eureka_port/eureka/apps/服务名称/实例ip:实例名称:实例port/status?value=OUT_OF_SERVICE

例如:

bash
curl -i -X PUT admin:admin123 http://127.0.0.1:19991/eureka/apps/app-platform/127.0.0.1:app-platform-1.0.0-SNAPSHOT:8001/status?value=OUT_OF_SERVICE

结果

bash
HTTP/1.1 200 # 请求成功
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/xml
Content-Length: 0
Date: Mon, 15 Nov 2021 07:30:32 GMT

再次查询服务状态

xml

<instance>
    <instanceId>127.0.0.1:app-platform-2.0.0-SNAPSHOT:8001</instanceId>
    <hostName>127.0.0.1</hostName>
    <app>app-platform</app>
    <ipAddr>127.0.0.1</ipAddr>
    <status>OUT_OF_SERVICE</status>
    # 服务状态-已下线
    <overriddenstatus>OUT_OF_SERVICE</overriddenstatus>
    # 重写状态为已下线
    <port enabled="true">8001</port>
    <securePort enabled="false">443</securePort>
    <countryId>1</countryId>
    <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
    </dataCenterInfo>
    <leaseInfo>
        <renewalIntervalInSecs>10</renewalIntervalInSecs>
        <durationInSecs>30</durationInSecs>
        <registrationTimestamp>1636639654493</registrationTimestamp>
        <lastRenewalTimestamp>1636961468691</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1636639654493</serviceUpTimestamp>
    </leaseInfo>
    <metadata>
        <management.port>8001</management.port>
        <nodeId>127.0.0.1_kkg</nodeId>
    </metadata>
    <homePageUrl>http://127.0.0.1:8001/</homePageUrl>
    <statusPageUrl>http://127.0.0.1:8001/actuator/info</statusPageUrl>
    <healthCheckUrl>http://127.0.0.1:8001/actuator/health</healthCheckUrl>
    <vipAddress>app-platform</vipAddress>
    <secureVipAddress>app-platform</secureVipAddress>
    <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
    <lastUpdatedTimestamp>1636961432181</lastUpdatedTimestamp>
    <lastDirtyTimestamp>1636639654480</lastDirtyTimestamp>
    <actionType>MODIFIED</actionType>
</instance>

可以看到此时,服务状态为已经下线,不过还是要等到网关服务不再路由请求到该服务时再停掉服务。

通知注册中心服务上线

bash
curl -i -X DELETE -u eureka_username:eureka_password http://eureka_ip:eureka_port/eureka/apps/服务名称/实例ip:实例名称:实例port/status

例如:

bash
curl -i -X DELETE -u admin:admin123 http://127.0.0.1:19991/eureka/apps/app-platform/127.0.0.1:app-platform-1.0.0-SNAPSHOT:8001/status

结果

bash
HTTP/1.1 200 # 请求成功
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/xml
Content-Length: 0
Date: Mon, 15 Nov 2021 07:37:11 GMT

再次查询服务状态

xml

<instance>
    <instanceId>127.0.0.1:app-platform-2.0.0-SNAPSHOT:8001</instanceId>
    <hostName>127.0.0.1</hostName>
    <app>app-platform</app>
    <ipAddr>127.0.0.1</ipAddr>
    <status>UP</status>
    # 此时服务已上线 如果通知后立刻查询,状态可能会是unknown,隔一段时间再查询即可
    <overriddenstatus>UNKNOWN</overriddenstatus>
    <port enabled="true">8001</port>
    <securePort enabled="false">443</securePort>
    <countryId>1</countryId>
    <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
    </dataCenterInfo>
    <leaseInfo>
        <renewalIntervalInSecs>10</renewalIntervalInSecs>
        <durationInSecs>30</durationInSecs>
        <registrationTimestamp>1636961828894</registrationTimestamp>
        <lastRenewalTimestamp>1636961861799</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1636639654493</serviceUpTimestamp>
    </leaseInfo>
    <metadata>
        <management.port>8001</management.port>
        <nodeId>127.0.0.1_kkg</nodeId>
    </metadata>
    <homePageUrl>http://127.0.0.1:8001/</homePageUrl>
    <statusPageUrl>http://127.0.0.1:8001/actuator/info</statusPageUrl>
    <healthCheckUrl>http://127.0.0.1:8001/actuator/health</healthCheckUrl>
    <vipAddress>app-platform</vipAddress>
    <secureVipAddress>app-platform</secureVipAddress>
    <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
    <lastUpdatedTimestamp>1636961828894</lastUpdatedTimestamp>
    <lastDirtyTimestamp>1636961828889</lastDirtyTimestamp>
    <actionType>ADDED</actionType>
</instance>