java - Spring Boot GCP Data Spanner 延迟问题

标签 java spring-boot google-cloud-platform google-cloud-spanner grpc-java

在谷歌云环境中使用 Spring Boot 和 Spanner。我们现在正在努力解决性能问题。 为了证明这一点,我设置了一个小型演示案例,说明我们如何使用不同的方法从 spanner 检索数据。

第一种方法

使用 Google 的“本地”驱动程序来实例化 dbClient 并像这样检索数据。

@Repository
public class SpannerNativeDAO implements CustomerDAO {

  private final DatabaseClient dbClient;
  private final String SQL = "select * from customer where customer_id = ";

  public SpannerNativeDAO(
      @Value("${spring.cloud.gcp.spanner.instanceId}") String instanceId,
      @Value("${spring.cloud.gcp.spanner.database}") String dbId,
      @Value("${spring.cloud.gcp.spanner.project-id}") String projectId,
      @Value("${google.application.credentials}") String pathToCredentials)
      throws IOException {
    try (FileInputStream google_application_credentials = new FileInputStream(pathToCredentials)) {
      final SpannerOptions spannerOptions =
          SpannerOptions.newBuilder().setProjectId(projectId)
              .setCredentials(ServiceAccountCredentials.fromStream(google_application_credentials)).build();
      final Spanner spanner = spannerOptions.getService();
      final DatabaseId databaseId1 = DatabaseId.of(projectId, instanceId, dbId);
      dbClient = spanner.getDatabaseClient(databaseId1);
      // give it a first shot to speed up consecutive calls
      dbClient.singleUse().executeQuery(Statement.of("select 1 from customer"));
    }
  }

  private Customer readCustomerFromSpanner(Long customerId) {
    try {
      Statement statement = Statement.of(SQL + customerId);
      ResultSet resultSet = dbClient.singleUse().executeQuery(statement);
      while (resultSet.next()) {
        return Customer.builder()
            .customerId(resultSet.getLong("customer_id"))
            .customerStatus(CustomerStatus.valueOf(resultSet.getString("status")))
            .updateTimestamp(Timestamp.from(Instant.now())).build();
      }
    } catch (Exception ex) {
      //log
    }
    return null;
  }


....

}

第二种方法

使用 Spring Boot Data Starter ( https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-starters/spring-cloud-gcp-starter-data-spanner )

然后就是这样

@Repository
public interface SpannerCustomerRepository extends SpannerRepository<Customer, Long> {

  @Query("SELECT customer.customer_id, customer.status, customer.status_info, customer.update_timestamp "
      + "FROM customer customer WHERE customer.customer_id = @arg1")
  List<Customer> findByCustomerId(@Param("arg1") Long customerId);
}

现在,如果我采用第一种方法,建立到 Spanner 的初始 gRPC 连接需要 > 5 秒,所有连续调用都在 1 秒 左右。第二种方法只需要大约。 400 毫秒 用于初始调用后的每个调用。 为了测试差异,我在一个 Spring Boot 项目中连接了这两种解决方案,并将其与内存解决方案 (~100ms) 进行了比较。 所有给定的时间都是指开发机器上的本地测试,但回过头来调查云环境中的性能问题。

我测试了几个不同的 SpannerOptions (SessionOptions) 但没有结果,并在项目上运行了一个分析器。 我似乎 96% 的响应时间来自于建立到 spanner 的 gRPC channel ,而数据库本身在 5 毫秒内处理和响应。

我们真的不理解这种行为。我们只使用非常少的测试数据和几个小表。

  • DatabaseClient 应该管理 ConnectionPool 并且它本身连接到一个 Singleton-Scoped Repository-Bean。所以 Session 应该被重用,对吗?
  • 为什么第一种方法比第二种方法花费的时间长得多。 Spring FW 本身只是使用 DatabaseClient 作为 SpannerOperations/SpannerTemplate 中的成员。
  • 我们通常如何才能减少延迟。每个数据库调用的普通响应超过 200 毫秒似乎是我们预期的四倍。 (我知道需要谨慎对待本地时序基准)

最佳答案

跟踪使我们能够很好地了解客户端,希望它可以帮助您诊断延迟。

正在运行 TracingSample , 我得到 stackdriver trace来自堆栈驱动程序。您可以使用不同的后端,或 print it out as logs .

上面的示例还导出了 http://localhost:8080/rpczhttp://localhost:8080/tracez您可以四处查看以检查延迟和痕迹。

设置教程:Cloud Spanner, instrumented by OpenCensus and exported to Stackdriver

关于java - Spring Boot GCP Data Spanner 延迟问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50861577/

相关文章:

google-cloud-platform - 谷歌计算引擎: Required 'compute.zones.get' permission error

python - 使用谷歌云sdk python使缓存内容无效

java - android - OutofMemoryError - 位图大小超出 VM 预算 - 方向改变

java - java中哈希函数的误解以及HashSet上contains的工作

java - 如何仅使用非前导零复制 int 数组

java - Spring boot RestTemplate 发布 400 错误

google-cloud-platform - GCP Cloud SQL 未能删除实例,因为 `deletion_protection` 设置为 true

java - 使用扫描仪从控制台读取数字的最佳方法是什么?

java - Mapstruct - 字符串操作,但仅限于一个属性

java - Spring boot - 更新一个实体后,一对一关系未反射(reflect)在两个表上