Dataflow 2.3.0中使用Spanner写入Pub/Sub消息遇异常求助
解决Dataflow写入Spanner时的
internal_static_google_rpc_LocalizedMessage_fieldAccessorTable异常 这个异常我之前帮同事排查过,本质是Protobuf版本冲突搞的鬼——你之前用Bigtable的客户端库,现在加了SpannerIO,不同Google Cloud依赖带了不同版本的Protobuf,导致类加载时反射找不到对应的字段访问器表。下面是具体的解决步骤:
1. 强制统一Protobuf版本
Dataflow SDK v2.3.0依赖的是Protobuf 3.5.1,你需要在项目依赖管理里锁定这个版本,避免依赖传递带来的冲突:
- 如果你用Maven,在
pom.xml里添加:<dependencyManagement> <dependencies> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.5.1</version> </dependency> </dependencies> </dependencyManagement> - 如果你用Gradle,在
build.gradle里添加:configurations.all { resolutionStrategy.force 'com.google.protobuf:protobuf-java:3.5.1' }
2. 排查并排除冲突依赖
用依赖树命令找出偷偷引入其他Protobuf版本的依赖:
- Maven:
mvn dependency:tree | grep protobuf - Gradle:
./gradlew dependencies | grep protobuf
找到冲突的依赖后,在对应的dependency里排除Protobuf,比如Bigtable的依赖:
<dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-bigtable</artifactId> <version>你的Bigtable版本</version> <exclusions> <exclusion> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> </exclusion> </exclusions> </dependency>
3. 确保Spanner依赖和SDK兼容
虽然google-cloud-dataflow-java-sdk-all包含SpannerIO,但有时候传递依赖可能缺失,你可以手动添加兼容版本的Spanner客户端依赖(注意排除Protobuf避免冲突):
<dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-spanner</artifactId> <version>1.11.0</version> <!-- 和Dataflow v2.3.0完全兼容 --> <exclusions> <exclusion> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> </exclusion> </exclusions> </dependency>
4. 验证打包和运行环境
- 本地运行时确保用JDK 8(Dataflow v2.3.0不支持更高版本JDK);
- 打包时用
mvn clean package -DskipTests生成fat jar,确保所有依赖都被正确打包且版本统一,不要依赖本地环境的零散依赖; - 提交到Dataflow集群时,确保指定的SDK版本和本地依赖一致,避免集群端加载不同版本的类。
这个问题核心就是类加载冲突,统一Protobuf版本后基本就能解决。
内容的提问来源于stack exchange,提问作者Flavius




