GCP存储桶对象读写时触发com.google.cloud.storage.StorageException 404异常排查
解决GCP存储桶读取对象时的偶发异常问题
嘿,我来帮你捋清楚这个问题。你当前的代码逻辑是先检查Blob是否存在,再读取内容,但偶尔还是会在blob.getContent()这里抛出异常,最可能的原因和对应的解决方案如下:
最常见的原因:竞态条件
你检查blob != null之后,到调用getContent()的这段时间里,这个存储桶对象可能被其他服务、进程甚至手动操作删除了。GCS的Blob对象其实是一个快照,当原对象被删除后,再调用这个实例的getContent()就会触发异常。
解决方案1:给读取逻辑加上异常捕获
即使提前检查了对象存在,也要对getContent()的调用做异常处理,尤其是捕获StorageException并判断错误码:
Storage storage = googleStorage.get(); BlobId blobId = BlobId.of(STORAGE_BUCKET, "path/to.obj"); Blob blob = storage.get(blobId); if (blob == null) return null; try { byte[] blobContent = blob.getContent(); // 你的后续更新逻辑 } catch (StorageException e) { // 针对对象不存在的404错误做处理 if (e.getCode() == 404) { // 这里可以返回null或者重新尝试读取 return null; } // 其他异常按需处理或重新抛出 throw e; }
解决方案2:利用生成号做版本校验
GCS的每个对象都有唯一的生成号(generation number),你可以在检查对象存在后,获取它的生成号,再用这个生成号去读取指定版本的对象,确保读取的是你最初检查到的那个版本:
Storage storage = googleStorage.get(); BlobId blobId = BlobId.of(STORAGE_BUCKET, "path/to.obj"); Blob blob = storage.get(blobId); if (blob == null) return null; // 获取当前对象的生成号 long generation = blob.getGeneration(); // 构造带版本号的BlobId BlobId versionedBlobId = BlobId.of(STORAGE_BUCKET, "path/to.obj", generation); Blob versionedBlob = storage.get(versionedBlobId); if (versionedBlob == null) { // 对象已被删除或版本变更,直接返回null return null; } byte[] blobContent = versionedBlob.getContent();
其他可能的原因:网络波动
如果是偶尔的网络问题导致读取失败,可以给GCS客户端配置重试机制,自动处理可重试的异常:
Storage storage = StorageOptions.newBuilder() .setRetrySettings(RetrySettings.newBuilder() .setTotalTimeout(Duration.ofMinutes(2)) .setInitialRetryDelay(Duration.ofMillis(100)) .setMaxRetryDelay(Duration.ofSeconds(5)) .setRetryDelayMultiplier(2.0) .setInitialRpcTimeout(Duration.ofSeconds(5)) .setMaxRpcTimeout(Duration.ofSeconds(30)) .setRpcTimeoutMultiplier(2.0) .build()) .build() .getService();
按照上面的方法调整代码,应该就能解决你遇到的偶发异常问题啦~
内容的提问来源于stack exchange,提问作者Nira
相关产品推荐
相关产品推荐

