终止抢占式实例的GCP负载均衡器行为

时间:2018-12-03 13:25:56

标签: google-cloud-platform google-compute-engine load-balancing preemptive

背景

我们有一个调度程序实例组,每个活动的VM每秒接收大约700个请求。该调度程序位于自动缩放的负载均衡器后面。到目前为止,我们所有的虚拟机都是通用的虚拟机,但是我们一直在研究使它们具有抢占性的可能性。

抢占式实例的问题

根据文档,GCP可以在any time终止抢占实例。

让我们假设每个调度程序VM都不处于状态。它接收一个请求,对其进行处理,然后向其他计算机发出HTTP请求。

在任何给定时间,每个虚拟机将同时处理约700个请求,同时从负载均衡器接收数据。

问题

如果我的抢占式VM处理700个请求,收到终止信号,会发生什么情况?

嗯,从理论上讲,应该有一个shutdown script来确保处理完这些请求,然后终止该应用程序(清除出口)。这引出了一个大问题:

  • 但是负载平衡器是否知道我的VM正在关闭?它会继续向终止VM发送请求吗?

注意事项

如果是,则表示某些请求将失败,因为一旦应用程序关闭,计算机仍处于启动状态,并且负载平衡器继续向该计算机发送请求,而不知道该应用程序已经存在下。

理想情况下,这些请求将作为失败请求返回给负载均衡器,并将其发送到另一台计算机。但是,GCP负载平衡器不够聪明,无法做到这一点。

如果负载平衡器知道该虚拟机已选择提前终止,则无需执行任何特殊操作。

是哪个?

2 个答案:

答案 0 :(得分:1)

  

但是负载平衡器是否知道我的VM正在关闭?会吗   继续向终止VM发送请求?

是的,负载平衡器将继续向实例发送请求。

您将需要创建关闭脚本并将实例从负载平衡器中删除。

这并不是负载均衡器不够智能。负载平衡器不知道您的请求是否可以重试。该决定应由客户端/后端逻辑决定。

您的用例不是抢占式实例的好例子。抢占式实例将每24小时终止一次。如果您的目标是节省成本,请将长期实例定价与抢先定价进行比较。节省下来的钱不足以证明工程,测试和质量检查成本是合理的。

应该为失败而设计体系结构,但是我不会故意选择会不断失败的体系结构。您的情况是每24小时一次。还存在无法启动另一个实例来弥补增加的负载的风险。并且存在所有实例将被终止的风险。

答案 1 :(得分:0)

我们有类似的问题。我们几乎已经通过负载均衡器运行状况检查解决了它(在非常高的负载条件下存在一些问题)。 现在,Trick处于抢占信号的10-15秒之内,负载平衡器会因为停止向该实例发送新请求而将实例标记为不正常。

解决方案:

  1. 负载均衡器每3秒检查一次实例的运行状况,并在第三次运行状况检查失败后将实例标记为不正常,因此负载均衡器会在大约10秒内将实例标记为不运行并停止发送新请求。
  2. 使用ContextCloseEvent (Spring boot)Runtime.getRuntime().addShutdownHook()捕获Java中的抢占信号(在我的情况下,JVM接收到信号要花几秒钟的时间)
  3. 将运行状况检查设置为失败,即运行状况检查端点将开始返回404。
  4. 在关机块中睡眠15-25秒,以使正在进行的操作和新请求完成
  5. 释放资源并执行关机日志记录。

    
    @EventListener
    public void onShutdown(ContextClosedEvent event) {
    
    
    log.warn("shutdown event received {}", event.getSource().toString());
    log.warn("/ping will respond 404, Main thread will sleep for 20 seconds to allow pending tasks to complete");
    
    isShuttingDown = true;
    try {
        Thread.sleep(SLEEP_BEFORE_SHUTDOWN_MILLIS);
    } catch (InterruptedException e) {
        log.error("sleep before shutdown interrupted", e);
    }
    
    log.warn("Shutting down now, daemon threads will continue work");
    releaseResources(); 
    
    log.info("{} {} on {} stopped.", NAME, VERSION, HOSTNAME);
    
    } //health endpoint @RequestMapping(value = "ping", produces = MediaType.TEXT_PLAIN_VALUE) public ResponseEntity ping() { if(isShuttingDown()) { log.warn("health failed - shutting down soon"); return new ResponseEntity(HttpStatus.NOT_FOUND); } return ResponseEntity.ok("pong"); }