为了解决在微服务重启的过程中,可能出现一部分 http 请求处理失败的问题,提供一下方案
拟用方案:
第一步:重启前先从主动将服务剔除,并等待一段时间
第二步:停止服务并重启
一、主动将服务剔除
该方案主要考虑因为服务下线的瞬间,如果服务信息更新不及时,导致复杂均衡算法依然转发到已经停掉的实例上发生一些服务不可用的情况
在每个项目增加一个接口(例如 /discovery/deregister
),在项目重启的脚本中主动调用接口剔除这个服务,shell 大致改动如下:
function stop()
{
echo "deregister [${PROJECT}]."
curl -X POST "127.0.0.1:${SERVER_PORT}/discovery/deregister"
echo ""
echo "deregister [${PROJECT}] then sleep 10 seconds."
sleep 10
kill xxxxxxxxxxxxxxxxxxxx
}
接口代码示例
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("discovery")
@Slf4j
public class DeregisterInstanceController {
@Autowired
@Lazy
private ServiceRegistry serviceRegistry;
@Autowired
@Lazy
private Registration registration;
@PostMapping("deregister")
public void deregister() {
log.info("deregister serviceName:{}, ip:{}, port:{}",
registration.getServiceId(),
registration.getHost(),
registration.getPort());
try {
serviceRegistry.deregister(registration);
} catch (Exception e) {
log.error("deregister error", e);
}
}
}
二、Spring Boot 自带的优雅停机方案
要求 Spring Boot 的版本大于等于 2.3
在配置文件中增加如下配置:
application.yaml
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 10s
当使用 server.shutdown=graceful
启用时,在 Web 容器关闭时,Web 服务器将不再接收新请求,并将等待活动请求完成的缓冲期。缓冲器默认是 30s, 具体项目时间根据具体情况而定
不同 web 容器优雅停机行为区别
容器停机行为取决于具体的 web 容器行为
web 容器名称 | 行为说明 |
---|---|
tomcat 9.0.33+ | 停止接收请求,客户端新请求等待超时。 |
Reactor Netty | 停止接收请求,客户端新请求等待超时。 |
Undertow | 停止接收请求,客户端新请求直接返回 503。 |
两者一同使用效果更加
网友评论