Google Analytics Core 报告 API v3 需要 4 分钟响应
Google Analytics Core reporting API v3 needs 4 minutes to respond
我们在 Laravel 应用程序中使用 Google Analytics 核心报告 API v3 已有 2 年多了。
多年来我们做了一些优化,但我们的设置一直是相同的,并且现在已经工作了很长一段时间。
本月早些时候开始发生一些奇怪的事情,很少有请求需要大约 4 分钟才能完成。我能找到的第一个事件发生在 12 月 6 日。
起初我没有多想,以为我们达到了某种极限,但问题仍然存在,并且越来越多地出现。
所以这两天我一直在寻找问题的根源,但我一点也不知道为什么会这样。开发人员控制台中没有达到限制的迹象。
我花了一些时间来找出当我连续快速调用 API 时有多少响应缓慢,14 个调用中有 4 个花费了 240.3 到 240.5 秒。我已经打印了调用的结果,并且只调用了 1 个特定视图以查看在 1 个请求中发送大量数据是否不是问题。
该视图当天没有数据,因此所有请求都返回 0 行,所有指标的总数为 0。没有附加错误消息。
开发者控制台另有说法,它说在过去的一个小时内没有请求超过 300 毫秒:
这发生在我们的服务器和本地环境中,因此我认为这与 nginx/internet 问题无关。
我很确定我的代码没有问题,这确实与限制有关,但我还是添加了它。此方法提取我们存储在数据库中的所有视图,并对 API 进行 3 次调用以提取多个指标,这不能在 1 个请求中完成,因为您不能一次请求超过 10 个指标.
public function getExternal()
{
$this->logInfo("Retrieving reports");
$views = $this->getLinkedViews();
$i = 1;
foreach ($views as $view) {
try {
$params= array('dimensions' => 'ga:campaign, ga:source, ga:medium, ga:date' );
$start = microtime(true);
$response = $this->analytics->data_ga->get(
'ga:' . $view->datasource_id,
$this->startDate,
$this->endDate,
'ga:users, ga:sessions, ga:bounceRate, ga:avgSessionDuration, ga:goal1Completions , ga:goal2Completions , ga:goal3Completions , ga:goal4Completions',
$params
);
var_dump('call time: ' . (microtime(true) - $start));
$data = $response->getRows();
if ($data != null) {
$this->rawData[$view->datasource_id. '.1'] = $data;
}
$response = $this->analytics->data_ga->get(
'ga:' . $view->datasource_id,
$this->startDate,
$this->endDate,
'ga:goal5Completions , ga:goal6Completions , ga:goal7Completions , ga:goal8Completions , ga:goal9Completions , ga:goal10Completions , ga:goal11Completions , ga:goal12Completions',
$params
);
$data = $response->getRows();
if ($data != null) {
$this->rawData[$view->datasource_id. '.2'] = $data;
}
$response = $this->analytics->data_ga->get(
'ga:' . $view->datasource_id,
$this->startDate,
$this->endDate,
'ga:goal13Completions , ga:goal14Completions , ga:goal15Completions , ga:goal16Completions , ga:goal17Completions , ga:goal18Completions , ga:goal19Completions , ga:goal20Completions',
$params
);
$data = $response->getRows();
if ($data != null) {
$this->rawData[$view->datasource_id. '.3'] = $data;
}
$this->logInfo($view->name . ' metrics retrieved'. "(" .$i . " - " . count($views). ")", $view->datasource_id);
$i++;
} catch (\Google_Service_Exception $gse) {
dd($gse);
$this->logError($gse->getMessage(), isset($view->datasource_id) ? $view->datasource_id : null, $this->formatErrorCode($gse->getCode()));
} catch (\Throwable $t){
dd($t);
$this->logError($t, isset($view->datasource_id) ? $view->datasource_id: null, $this->formatErrorCode('000001'));
}
我联系了Google,回复如下:
团队已意识到此问题,目前仍在努力解决此问题。目前,我会推荐以下建议以缓解此问题:
• 通过缩小范围(例如维度、列、日期范围、过滤器等)来简化查询的复杂性;请参阅 this page 以大致了解驱动复杂性的因素
• 实施指数 back-off
编辑:
Google 已修复此问题,我们必须实施上述建议,因为看起来我们比错误发生之前更容易受到限制。
我实现了一个重试逻辑,在超时的情况下休眠 5 秒以冷却。我测试了 API 调用,无论请求有多复杂,成功或失败都是随机的。
要强制超时,请将自定义 Guzzle 客户端设置为 Google 客户端,并在构造函数中指定最大连接时间(超过 2 秒看起来会失败),以便客户端在请求失败。
与我们最近一直在苦苦挣扎的情况完全相同。无论查询的复杂程度如何,请求挂起都是完全随机发生的,即使是最简单的查询也会发生同样的情况。
目前最好的解决方法是设置一个较短的超时并重试,因为如果超过 2 秒,它很可能会失败。但在这种情况下,唯一的缺点是,如果你继续重试太多(即使使用指数退避),你将开始收到 403:“最近失败报告的数量 API 请求太高”。奇怪的是我们的请求实际上并没有“失败”,因为它们没有出现在面板上,但它们仍然被认为是失败的请求。并导致这些 403 响应的开始。
Error response graph
所以我建议也增加请求。每次尝试的超时值,并对这些 403 错误给予更大的休息时间。也许每次尝试随机设置 quotaUser 和 userIp 参数也会有所帮助。
我们遇到了完全相同的问题,付费客户(显然)对此非常不满。降低复杂性不再是解决方案,因为它在最近几天变得更糟,即使是最简单的请求也需要很长时间或最终超时。
仅供参考我们的解决方案:我们摆脱了 Google 分析并将所有内容都放在我们自己的数据库中 => 平均请求时间从 1 分钟多到 2 秒以下。无论如何,大多数数据以及 API 等免费 https://geolocation-db.com/ 数据都是公开可用的。
我们在 Laravel 应用程序中使用 Google Analytics 核心报告 API v3 已有 2 年多了。 多年来我们做了一些优化,但我们的设置一直是相同的,并且现在已经工作了很长一段时间。
本月早些时候开始发生一些奇怪的事情,很少有请求需要大约 4 分钟才能完成。我能找到的第一个事件发生在 12 月 6 日。
起初我没有多想,以为我们达到了某种极限,但问题仍然存在,并且越来越多地出现。
所以这两天我一直在寻找问题的根源,但我一点也不知道为什么会这样。开发人员控制台中没有达到限制的迹象。
我花了一些时间来找出当我连续快速调用 API 时有多少响应缓慢,14 个调用中有 4 个花费了 240.3 到 240.5 秒。我已经打印了调用的结果,并且只调用了 1 个特定视图以查看在 1 个请求中发送大量数据是否不是问题。 该视图当天没有数据,因此所有请求都返回 0 行,所有指标的总数为 0。没有附加错误消息。
开发者控制台另有说法,它说在过去的一个小时内没有请求超过 300 毫秒:
这发生在我们的服务器和本地环境中,因此我认为这与 nginx/internet 问题无关。
我很确定我的代码没有问题,这确实与限制有关,但我还是添加了它。此方法提取我们存储在数据库中的所有视图,并对 API 进行 3 次调用以提取多个指标,这不能在 1 个请求中完成,因为您不能一次请求超过 10 个指标.
public function getExternal()
{
$this->logInfo("Retrieving reports");
$views = $this->getLinkedViews();
$i = 1;
foreach ($views as $view) {
try {
$params= array('dimensions' => 'ga:campaign, ga:source, ga:medium, ga:date' );
$start = microtime(true);
$response = $this->analytics->data_ga->get(
'ga:' . $view->datasource_id,
$this->startDate,
$this->endDate,
'ga:users, ga:sessions, ga:bounceRate, ga:avgSessionDuration, ga:goal1Completions , ga:goal2Completions , ga:goal3Completions , ga:goal4Completions',
$params
);
var_dump('call time: ' . (microtime(true) - $start));
$data = $response->getRows();
if ($data != null) {
$this->rawData[$view->datasource_id. '.1'] = $data;
}
$response = $this->analytics->data_ga->get(
'ga:' . $view->datasource_id,
$this->startDate,
$this->endDate,
'ga:goal5Completions , ga:goal6Completions , ga:goal7Completions , ga:goal8Completions , ga:goal9Completions , ga:goal10Completions , ga:goal11Completions , ga:goal12Completions',
$params
);
$data = $response->getRows();
if ($data != null) {
$this->rawData[$view->datasource_id. '.2'] = $data;
}
$response = $this->analytics->data_ga->get(
'ga:' . $view->datasource_id,
$this->startDate,
$this->endDate,
'ga:goal13Completions , ga:goal14Completions , ga:goal15Completions , ga:goal16Completions , ga:goal17Completions , ga:goal18Completions , ga:goal19Completions , ga:goal20Completions',
$params
);
$data = $response->getRows();
if ($data != null) {
$this->rawData[$view->datasource_id. '.3'] = $data;
}
$this->logInfo($view->name . ' metrics retrieved'. "(" .$i . " - " . count($views). ")", $view->datasource_id);
$i++;
} catch (\Google_Service_Exception $gse) {
dd($gse);
$this->logError($gse->getMessage(), isset($view->datasource_id) ? $view->datasource_id : null, $this->formatErrorCode($gse->getCode()));
} catch (\Throwable $t){
dd($t);
$this->logError($t, isset($view->datasource_id) ? $view->datasource_id: null, $this->formatErrorCode('000001'));
}
我联系了Google,回复如下:
团队已意识到此问题,目前仍在努力解决此问题。目前,我会推荐以下建议以缓解此问题:
• 通过缩小范围(例如维度、列、日期范围、过滤器等)来简化查询的复杂性;请参阅 this page 以大致了解驱动复杂性的因素
• 实施指数 back-off
编辑:
Google 已修复此问题,我们必须实施上述建议,因为看起来我们比错误发生之前更容易受到限制。
我实现了一个重试逻辑,在超时的情况下休眠 5 秒以冷却。我测试了 API 调用,无论请求有多复杂,成功或失败都是随机的。
要强制超时,请将自定义 Guzzle 客户端设置为 Google 客户端,并在构造函数中指定最大连接时间(超过 2 秒看起来会失败),以便客户端在请求失败。
与我们最近一直在苦苦挣扎的情况完全相同。无论查询的复杂程度如何,请求挂起都是完全随机发生的,即使是最简单的查询也会发生同样的情况。 目前最好的解决方法是设置一个较短的超时并重试,因为如果超过 2 秒,它很可能会失败。但在这种情况下,唯一的缺点是,如果你继续重试太多(即使使用指数退避),你将开始收到 403:“最近失败报告的数量 API 请求太高”。奇怪的是我们的请求实际上并没有“失败”,因为它们没有出现在面板上,但它们仍然被认为是失败的请求。并导致这些 403 响应的开始。 Error response graph
所以我建议也增加请求。每次尝试的超时值,并对这些 403 错误给予更大的休息时间。也许每次尝试随机设置 quotaUser 和 userIp 参数也会有所帮助。
我们遇到了完全相同的问题,付费客户(显然)对此非常不满。降低复杂性不再是解决方案,因为它在最近几天变得更糟,即使是最简单的请求也需要很长时间或最终超时。
仅供参考我们的解决方案:我们摆脱了 Google 分析并将所有内容都放在我们自己的数据库中 => 平均请求时间从 1 分钟多到 2 秒以下。无论如何,大多数数据以及 API 等免费 https://geolocation-db.com/ 数据都是公开可用的。