我正在使用DataflowPipelineRunner创建数据流作业。我尝试了以下方案。
在上述所有场景中,Input是来自GCS的文件,文件非常小(KB大小),输出为Big Query表。
我在所有场景中都出现了内存错误
我编译的代码的大小是94mb。我只尝试单词计数示例,它没有读取任何输入(它在作业开始之前失败)。请帮助我理解为什么我会收到此错误。
注意:我正在使用appengine开始工作。
注意:相同的代码适用于beta versoin 0.4.150414
编辑1
根据答案中的建议尝试了以下内容,
完成这些配置后,Java堆内存问题就解决了。但它试图将一个罐子上传到超过10Mb的交错位置,因此失败了。
记录以下异常
com.google.api.client.http.HttpRequest execute: exception thrown while executing request
com.google.appengine.api.urlfetch.RequestPayloadTooLargeException: The request to https://www.googleapis.com/upload/storage/v1/b/pwccloudedw-stagging-bucket/o?name=appengine-api-L4wtoWwoElWmstI1Ia93cg.jar&uploadType=resumable&upload_id=AEnB2Uo6HCfw6Usa3aXlcOzg0g3RawrvuAxWuOUtQxwQdxoyA0cf22LKqno0Gu-hjKGLqXIo8MF2FHR63zTxrSmQ9Yk9HdCdZQ exceeded the 10 MiB limit.
at com.google.appengine.api.urlfetch.URLFetchServiceImpl.convertApplicationException(URLFetchServiceImpl.java:157)
at com.google.appengine.api.urlfetch.URLFetchServiceImpl.fetch(URLFetchServiceImpl.java:45)
at com.google.apphosting.utils.security.urlfetch.URLFetchServiceStreamHandler$Connection.fetchResponse(URLFetchServiceStreamHandler.java:543)
at com.google.apphosting.utils.security.urlfetch.URLFetchServiceStreamHandler$Connection.getInputStream(URLFetchServiceStreamHandler.java:422)
at com.google.apphosting.utils.security.urlfetch.URLFetchServiceStreamHandler$Connection.getResponseCode(URLFetchServiceStreamHandler.java:275)
at com.google.api.client.http.javanet.NetHttpResponse.<init>(NetHttpResponse.java:36)
at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:94)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:965)
at com.google.api.client.googleapis.media.MediaHttpUploader.executeCurrentRequestWithoutGZip(MediaHttpUploader.java:545)
at com.google.api.client.googleapis.media.MediaHttpUploader.executeCurrentRequest(MediaHttpUploader.java:562)
at com.google.api.client.googleapis.media.MediaHttpUploader.resumableUpload(MediaHttpUploader.java:419)
at com.google.api.client.googleapis.media.MediaHttpUploader.upload(MediaHttpUploader.java:336)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:427)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at com.google.cloud.hadoop.util.AbstractGoogleAsyncWriteChannel$UploadOperation.call(AbstractGoogleAsyncWriteChannel.java:357)
at java.util.concurrent.FutureTask.run(FutureTask.java:260)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1168)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:605)
at com.google.apphosting.runtime.ApiProxyImpl$CurrentRequestThreadFactory$1$1.run(ApiProxyImpl.java:1152)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.ApiProxyImpl$CurrentRequestThreadFactory$1.run(ApiProxyImpl.java:1146)
at java.lang.Thread.run(Thread.java:745)
at com.google.apphosting.runtime.ApiProxyImpl$CurrentRequestThreadFactory$2$1.run(ApiProxyImpl.java:1195)
我尝试直接上传jar文件 - appengine-api-1.0-sdk-1.9.20.jar ,仍尝试上传此jar appengine-api-L4wtoWwoElWmstI1Ia93cg.jar < / strong>即可。 我不知道它是什么罐子。知道这个罐子是什么的任何想法。
请帮我解决这个问题。
答案 0 :(得分:4)
简短的回答是,如果您在Managed VM上使用AppEngine,则不会遇到AppEngine沙箱限制(使用F1 or B1 instance class时的OOM,执行时间限制问题,列入白名单的JRE类)。如果您确实希望在App Engine沙箱中运行,那么您对Dataflow SDK的使用大多符合AppEngine沙箱的限制。下面我将解释常见问题以及人们为遵守AppEngine沙箱限制所做的工作。
Dataflow SDK需要一个AppEngine实例类,该实例类具有足够的内存来执行用户应用程序以构建管道,暂存所有资源,并将作业描述发送到Dataflow服务。通常我们看到用户需要使用内存超过128mb的instance class才能看到OOM错误。
如果已经暂存了应用程序所需的资源,通常构建管道并将其提交到Dataflow服务通常需要不到几秒钟的时间。将JAR和任何其他资源上载到GCS可能需要超过60秒。这可以通过预先将JAR预先暂存到GCS来手动解决(如果Dataflow SDK检测到它们已经存在,则会再次跳过它们)或使用task queue获得10分钟限制(请注意,对于大型应用程序,10分钟可能不足以暂存您的所有资源)。
最后,在AppEngine沙箱环境中,您和所有依赖项仅限于在JRE中使用whitelisted个类,否则您将获得如下异常:
java.lang.SecurityException:
java.lang.IllegalAccessException: YYY is not allowed on ZZZ
...
编辑1
我们在类路径上执行jar内容的哈希,并使用修改后的文件名将它们上传到GCS。 AppEngine运行带有自己的JAR的沙盒环境, appengine-api-L4wtoWwoElWmstI1Ia93cg.jar 指的是 appengine-api.jar ,它是沙盒环境添加的jar。您可以在我们的PackageUtil#getUniqueContentName(...)中看到我们只是在 .jar 之前附加 - $ HASH 。
我们正在努力解决您看到 RequestPayloadToLarge 的原因,目前建议您设置 filesToStage 选项并过滤掉执行您不需要的jar数据流来解决您面临的问题。您可以看到我们如何构建要使用DataflowPipelineRunner#detectClassPathResourcesToStage(...)暂存的文件。
答案 1 :(得分:1)
我在10MB限制时遇到了同样的问题。我所做的是过滤掉大于该限制的JAR文件(而不是特定文件),然后使用setFilesToStage
在pingHandler = scheduler.scheduleAtFixedRate([command], 5, 5, TimeUnit.MINUTES);
中设置重命名文件。
所以我刚刚从Dataflow SDK复制了方法DataflowPipelineOptions
,并且明显地改变了它:
detectClassPathResourcesToStage
然后当我创建private static final long FILE_BYTES_THRESHOLD = 10 * 1024 * 1024; // 10 MB
protected static List<String> detectClassPathResourcesToStage(ClassLoader classLoader) {
if (!(classLoader instanceof URLClassLoader)) {
String message = String.format("Unable to use ClassLoader to detect classpath elements. "
+ "Current ClassLoader is %s, only URLClassLoaders are supported.", classLoader);
throw new IllegalArgumentException(message);
}
List<String> files = new ArrayList<>();
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
try {
File file = new File(url.toURI());
if (file.length() < FILE_BYTES_THRESHOLD) {
files.add(file.getAbsolutePath());
}
} catch (IllegalArgumentException | URISyntaxException e) {
String message = String.format("Unable to convert url (%s) to file.", url);
throw new IllegalArgumentException(message, e);
}
}
return files;
}
:
DataflowPipelineOptions
答案 2 :(得分:1)