Spring 调度程序无法在 google 云 运行 中工作,cpu 节流

Spring Scheduler not working in google cloud run with cpu throttling off

你好,我有一个 spring 调度程序作业 运行ning,它必须在 google 云 运行 上 运行 并具有预定的时间间隔。

它与 docker-compose 本地部署完美配合。它被触发没有任何问题。

虽然它在 google 云 运行 服务中本地运行良好,但 CPU 节流关闭,这使得 CPU 始终保持 100% 开启,但在第一个 运行.

我将粘贴 docker 文件供任何一次参考,但我很确定它工作正常

FROM maven:3-jdk-11-slim AS build-env

# Set the working directory to /app
WORKDIR /app
COPY pom.xml ./
COPY src ./src
COPY css-common ./css-common

RUN echo $(ls -1 css-common/src/main/resources)

# Build and create the common jar
RUN cd css-common && mvn clean install

# Build and the job
RUN mvn package -DskipTests

# It's important to use OpenJDK 8u191 or above that has container support enabled.
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM openjdk:11-jre-slim

# Copy the jar to the production image from the builder stage.
COPY --from=build-env /app/target/css-notification-job-*.jar /app.jar

# Run the web service on container startup
CMD ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

下面是用于部署的 terraform 脚本

resource "google_cloud_run_service" "job-staging" {
  name     = var.cloud_run_job_name
  project  = var.project
  location = var.region

  template {
    spec {
      containers {
        image = "${var.docker_registry}/${var.project}/${var.cloud_run_job_name}:${var.docker_tag_notification_job}"
        env {
          name  = "DB_HOST"
          value = var.host
        }
        env {
          name  = "DB_PORT"
          value = 3306
        }
      }
    }

    metadata {
      annotations = {
        "autoscaling.knative.dev/maxScale"        = "4"
        "run.googleapis.com/vpc-access-egress"    = "all-traffic"
        "run.googleapis.com/cpu-throttling"       =  false
      }
    }
  }

  timeouts {
    update = "3m"
  }
}

我在日志中注意到的一些事情

2022-01-04T00:19:39.178057Z2022-01-04 00:19:39.177 INFO 1 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
Standard
2022-01-04T00:19:39.182017Z2022-01-04 00:19:39.181 INFO 1 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
Standard
2022-01-04T00:19:39.194117Z2022-01-04 00:19:39.193 INFO 1 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.

正在关闭实体管理器。我提供了 -Xmx1024m 堆内存以确保它有足够的内存。

虽然在 google 文档中提到它应该可以工作,但由于某种原因我不确定调度程序是否被触发。任何帮助都会非常好。

TL;DR:在云 运行 上使用 Spring 调度器不是一个好主意。改用 Cloud Scheduler

其实你要明白什么是云运行实例的生命周期。首先,CPU仅在处理请求时分配给进程。

这样做的直接影响是后台进程(如调度程序)无法工作,因为没有 CPU 分配给请求处理。

除非您将 CPU 节流设置为关闭。你做到了?是的,很好,但还有其他注意事项!

一个实例在收到请求时创建,并在没有任何请求处理的情况下存活长达 15 分钟。然后实例被卸载,你扩展到 0.

同样,如果实例关闭,调度程序将无法工作。解决方案是将最小实例设置为 1 并将 CPU 节流设置为 false 以保持 1 个实例 100% 运行并让调度程序完成其工作。

Cloud 运行 的最后一个问题是可扩展性。您在 terraform 中设置了 4,这意味着您最多可以并行运行 4 个实例,因此并行运行 4 个调度程序 运行ning,每个实例一个。这真的是你想要的吗?如果没有,你可以设置max instance为1来限制parallel instance的个数为1。


最后,您有 1 个实例,全时运行,并且无法向上和向下扩展。因为它不能扩展,我不建议你在当前实例上执行处理,而是调用另一个 API which 运行 on another Cloud 运行 instance and that will be able to根据调度程序要求扩大和缩小规模。

因此,您将只有 1 个调度程序将执行 API 调用另一个云 运行 服务来执行任务。这就是 Cloud Scheduler 的目的。