当前使用Drive API Client Library for Java将项目与Google云端硬盘集成,当使用服务帐户来模拟用户以检索其云端硬盘内容时,当报告的请求数量达到以下数量时,会触发 userRateLimitExceeded 远低于控制台中可以看到的最低已定义配额。
用于测试Google云端硬盘集成的域当前将每100秒每用户的请求配额设置为1000。 在程序运行期间,使用服务帐户模拟用户并检索其文件,由于 usageLimits (即),Java客户端投射了 GoogleJsonResponseException userRateLimitExceeded 。但是,控制台报告的最大峰值是每分钟198个请求,远低于上述限制。
已尝试为每个请求设置随机的 quotaUser 参数,如error resolution page中所述,但这产生了相同的结果。
documentation中描述的指数退避策略在1秒钟开始等待然后增加,实际上并没有多大帮助,随着配额不断被触发,请求在等待20、30秒后基本上会逐渐通过。 / p>
要对此进行诊断,请针对不同的运行场景创建一个小型单元测试,在该场景中,我们运行1000个可调用对象,它们使用Drive的实例简单地列出了该域中知名Google云端硬盘区域中的前100个文件对象。
public class GoogleDriveRequestTest {
private Drive googleDrive;
//other class attributes
@Before
public void setup() throws Exception {
//sensitive data
final Credential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JacksonFactory.getDefaultInstance())
.setServiceAccountId(serviceAccountId)
.setServiceAccountPrivateKey(gdrivePrivateKey)
.setServiceAccountScopes(ImmutableSet.of(DriveScopes.DRIVE,
DirectoryScopes.ADMIN_DIRECTORY_USER,
DirectoryScopes.ADMIN_DIRECTORY_GROUP))
.setServiceAccountUser(serviceAccountUser)
.build();
this.googleDrive = new Drive.Builder(httpTransport, JacksonFactory.getDefaultInstance(), credential)
.setApplicationName("Google Drive API Load Test")
.build();
//other initialization code
}
@Test
public void shouldRequestListOfFilesOverAndOverAgain() {
Stream<Integer> infiniteStream = Stream.iterate(0, i -> i + 1);
AtomicInteger requestCounter = new AtomicInteger(1);
infiniteStream
.limit(1000)
.map(i -> new GoogleDriveCallable(requestCounter))
.parallel()
.map(executorService::submit)
.map(execution -> {
try {
return execution.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.forEach(triple -> System.out.println("Completed request n " + triple.getMiddle() + " in " + triple.getRight() + " millis on thread " + triple.getLeft()));
}
private class GoogleDriveCallable implements Callable<Triple<String, Integer, Long>> {
private final AtomicInteger requestNumber;
public GoogleDriveCallable(AtomicInteger requestNumber) {
this.requestNumber = requestNumber;
}
@Override
public Triple<String, Integer, Long> call() throws Exception {
try {
try {
StopWatch timeIt = StopWatch.createStarted();
googleDrive
.files()
.list()
.setSpaces("drive")
.setQuotaUser(UUID.randomUUID().toString())
.setFields("nextPageToken, files(id, name, mimeType)")
.setPageSize(100)
.execute();
timeIt.stop();
return new ImmutableTriple<>(Thread.currentThread().getName(), requestNumber.getAndIncrement(), timeIt.getTime());
} catch (GoogleJsonResponseException gjre) {
GoogleJsonError.ErrorInfo firstReportedError = gjre.getDetails().getErrors().get(0);
if (USER_LIMIT_QUOTA_EXCEEDED_ERROR_REASON.equals(firstReportedError.getReason())) {
fail("Google user rate limit triggered during request n " + requestNumber);
} else {
throw gjre;
}
}
} catch (Exception e) {
throw new RuntimeException("BOOM during request n " + requestNumber, e);
}
return null;
}
}
}
使用不同数量的线程(两次运行之间至少相差5分钟,以确保无干扰)运行此单元测试会产生以下结果:
已经确认没有其他人正在使用该域,因此没有任何东西可以干扰这些测试。
如果我们没有达到100秒的时间点,为什么后两种情况会失败,并触发用户配额,即使将速率推算到100秒并且确实接近,它们仍然不足1000个请求每100秒配额中有多少用户?
答案 0 :(得分:0)
与Google支持的通信着重指出,除了已知的配额外,后端服务还具有突发保护功能。
同样地,如果请求率是恒定的,则配额将适用,但是,如果请求率遭受突发并且所述突发,如果推断为正常流量,则会导致配额被超支,则API将使用usageLimit错误进行回复