Google Cloud Spanner 空提交中的 AbortedException

问题描述 投票:0回答:1

我目前正在使用 Google Cloud Spanner 开发一个 Java 程序,通过多线程方法在手动事务中进行批量插入。应用程序中的每个线程负责生成和累积自己的突变数组。作为该过程的一部分,我们向本地数组添加插入突变并执行空提交。但是,我遇到了一个问题,即在这些空提交期间出现 AbortedException,而不是专门在满足数据库提交的批处理大小时出现。事务是使用 TransactionManager 和 TransactionContext 处理的。我正在寻找有关为什么此异常特别发生在空提交时的见解。非常感谢!

这是应用程序简化版本的repo的链接。

基本上,应用程序利用 SpannerClient 类中的批处理方法来处理数据库插入操作。在此过程中,每个线程都会为插入操作创建突变,这些突变存储在 bufferedMutations ArrayList 中。收集这些突变直到它们达到设定的批量大小。达到此限制后,批次将通过单个事务发送到 Google Cloud Spanner 数据库。

发生的一些基本错误有两种类型(当应用程序在本地运行时打印出更多详细信息):

---------------------------------------------------------------------------------------------------------------
Thread-138 in SpannerClient.commit() method- AbortedException occurred.
Current size of mutation buffers array: 94.
Stack Trace:com.google.cloud.spanner.AbortedException: ABORTED: io.grpc.StatusRuntimeException: ABORTED: Database schema has changed



---------------------------------------------------------------------------------------------------------------
Thread-0 in SpannerClient.commit() method- AbortedException occurred.
Current size of mutation buffers array: 77.
Stack Trace:com.google.cloud.spanner.AbortedException: ABORTED: io.grpc.StatusRuntimeException: ABORTED: Transaction was aborted.
retry_delay {
  nanos: 38655229
}
google-cloud-platform google-cloud-spanner
1个回答
0
投票

Cloud Spanner 可以出于多种原因中止读/写事务。在上面给出的示例中,其中一次中止是由读/写事务期间生效的架构更改引起的。但读/写事务也可能因其他原因而中止,并且无法预先保证给定的读/写事务不会被中止。

重要的是要认识到,Cloud Spanner 中读/写事务的 API 合约的一部分是它们始终可以中止。因此,您“总是”需要将读/写事务置于重试循环中。示例中也显示了如何使用 TransactionManager:

long singerId = my_singer_id;
try (TransactionManager manager = dbClient.transactionManager()) {
  TransactionContext transaction = manager.begin();
  while (true) {
    String column = "FirstName";
    Struct row = transaction.readRow("Singers", Key.of(singerId), Collections.singleton(column));
    String name = row.getString(column);
    transaction.buffer(Mutation.newUpdateBuilder("Singers").set(column).to(name.toUpperCase()).build());
    try {
      manager.commit();
      break;
    } catch (AbortedException e) {
      Thread.sleep(e.getRetryDelayInMillis());
      transaction = manager.resetForRetry();
    }
  }
}

(来源:
https://github.com/googleapis/java-spanner/blob/f689f742d8754134523ed0394b9c1b8256adcae2/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java#L429

© www.soinside.com 2019 - 2024. All rights reserved.