从App Engine Standard使用BigQuery的最佳做法是什么?

时间:2018-02-01 21:45:42

标签: google-app-engine google-bigquery

我正在使用App Engine标准环境(自动标量),这意味着在取消请求之前我有10分钟的限制。

目标是定期查询BigQuery中的数据,并为每条记录在任务队列中创建一个任务,以便可以在后台处理记录。

https://cloud.google.com/bigquery/create-simple-app-api州的指示等待这样的工作:

// Create a job ID so that we can safely retry.
JobId jobId = JobId.of(UUID.randomUUID().toString());
Job queryJob = bigquery.create(JobInfo.newBuilder(queryConfig).setJobId(jobId).build());

// Wait for the query to complete.
queryJob = queryJob.waitFor();

问题是10分钟的限制,因为BigQuery查询是在后台处理的,并且可能需要一些时间才能得到结果,所以我可能无法在同一个端点调用中处理响应。

  • 当查询准备就绪时,有没有办法从URL接收BigQuery的回调?
  • 在App Engine Standard中有更智能的方法来处理来自BigQuery的数据吗?

我知道我可以配置App Engine来延长每个请求的最长时间,但这几乎不是解决方案。

2 个答案:

答案 0 :(得分:0)

一种可靠的方法是处理应用程序代码中的作业生命周期管理,而不是依赖于自动为您执行此操作的包装器(在作业完成之前阻塞的包装器)。

来自Running jobs

  

以编程方式运行作业:

     
      
  1. 使用唯一的job ID generated by your client code调用jobs.insert方法来开始工作。服务器生成一个作业   如果省略它,则为您提供ID,但最佳做法是生成   客户端的作业ID允许可靠地重试jobs.insert   调用

         

    调用jobs.insert方法时,请包含作业资源   包含指定作业类型的子属性的表示    - loadqueryextractcopy

  2.   
  3. 通过使用作业ID调用jobs.get检查作业状态,并检查status.state值以了解作业状态。什么时候   status.stateDONE,作业已停止运行;但是,a   DONE状态并不意味着作业仅成功完成   它不再运行了。

         

    注意:有一些管理作业状态的包装函数   请求你。例如,运行jobs.query会创建一个作业   定期轮询DONE状态指定的时间段。

  4.   
  5. 检查工作是否成功。如果作业具有status.errorResult属性,则作业失败。 status.errorResult属性成立   描述失败工作中出错的信息。如果   status.errorResult缺席,工作成功完成,   虽然可能存在一些非致命错误,例如问题   在加载作业中导入几行。返回非致命错误   工作的status.errors列表。

  6.   

基本上不是使用单个阻塞调用来等待作业完成(在您的情况下为queryJob.waitFor();,相当于引用中提到的jobs.query),您可以启动后台作业,然后进行重复调用查询作业的状态(例如在延迟推送队列任务中),当它完成时,您实际上开始处理结果。

可能感兴趣的还有Introduction to BigQuery JobsManaging BigQuery Jobs

注意:答案完全基于文档,我还不是BigQuery用户。

答案 1 :(得分:0)

最好的选择是处理长时间运行的任务,如BQ所做的那样:提供一个job-id并允许客户端查询它,在查询尚未完成时返回202,并在结果为200时返回结果结果已准备好供客户使用。

此外,202可以返回正文,因此您可以为客户端设置不同的状态(例如“排队”,“正在运行”,“处理结果”,......)。

在服务器端,您启动一​​个查询,并在BQ返回作业ID后立即将其存储在某个持久存储中(我会选择Datastore,但它可能是memcachecloudSQL实例,甚至是GCS中的文件。)

然后,您只需创建一个cron job来检查BQ以查找未完成查询的状态,并相应地更新其在持久存储中的状态。 BQ作业完成后,您可以检索结果并存储它们,以便在客户端检查您的服务时准备好它们。

例如,这是您应该在应用中执行的BQ API查询(在此处使用curl提供示例,您可以稍后使用idiomatic libraries翻译为任何语言):

  1. 创建作业,从响应中检索作业ID,然后存储它:

    PROJECT=$(gcloud config get-value project)
    QUERY='SELECT * FROM `bigquery-samples.wikipedia_benchmark.Wiki1k` limit 0'
    curl -H"Authorization: Bearer $(gcloud auth print-access-token)" -H'content-type:application/json' https://www.googleapis.com/bigquery/v2/projects/$PROJECT/jobs -d"
    {
     \"configuration\": {
      \"query\": {
       \"query\": \"$QUERY\",
       \"useLegacySql\": false
      }
     },
     \"jobReference\": {
      \"projectId\": \"$PROJECT\"
     }
    }"|jq -r .jobReference.jobId >> running_jobs
    
  2. 继续查询BQ API以了解作业状态。 (这可能是你的cron工作):

    for job in $(cat running_jobs); do
      if [ $(curl -H"Authorization: Bearer $(gcloud auth print-access-token)" https://www.googleapis.com/bigquery/v2/projects/$PROJECT/jobs/$job|jq -r .status.state) = "DONE" ]; then
        # here your processing part including your callback
        # then remove the job from the list of running jobs
        sed -i "/$job/d" ./running_jobs
      fi
    done
    
  3. 您可以在cloud shell中尝试此操作。