【问题标题】:Very Slow upload/download speed of Firebase StorageFirebase 存储的上传/下载速度非常慢
【发布时间】:2016-12-28 04:23:24
【问题描述】:

故事

我在我的应用中使用 Firebase 存储将大文件上传到 Firebase 存储。文件大多是视频,有时甚至会超过 2 GB。

我做了什么

这就是我所做的。

UploadTask originalUpload = originalDestination.putFile(Uri.fromFile(originalSource));
            mCurrentUploadTask = originalUpload;
            originalUpload.addOnProgressListener(mOnProgressUpdateListener);
originalUpload.addOnSuccessListener(mOriginalSuccessListener);

只是通知一下,我还将这些同步任务转换为异步,因为我需要在后台处理所有内容,

Tasks.await(originalUpload);

问题

这个问题很奇怪而且出乎意料。上传/下载完美,但速度很慢。

我在 1 MBps 的良好互联网连接上,但这些文件从未以这种速度传输。它大约是 100-150 KBps,几乎是我网络可用速度的 15%。

在提出此声明之前,我已经在多个不同的网络上进行了多次测试。无处可去,我发现 Firebase 充分利用了可用带宽,而其他非 Firebase 下载/上传则全速运行。

我的应用需要下载和上传大文件,因此无法承受如此慢的传输速度。 Firebase 完全没有预料到这一点。

如果我在实施中做错了什么,或者这是 Firebase 的固有问题,请告诉我?

更新

我也遇到了仅上传的问题。当我下载某些东西并且我只是关闭了 Wifi 时,下载会因为这个错误而被取消。

com.google.firebase.storage.StorageException: An unknown error occurred, please check the HTTP result code and inner exception for server response.

Read error: ssl=0xb7e7a510: I/O error during system call, Connection timed out
                                                                           javax.net.ssl.SSLException: Read error: ssl=0xb7e7a510: I/O error during system call, Connection timed out
                                                                               at com.android.org.conscrypt.NativeCrypto.SSL_read(Native Method)
                                                                               at com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:699)
                                                                               at com.android.okio.Okio$2.read(Okio.java:113)
                                                                               at com.android.okio.RealBufferedSource.read(RealBufferedSource.java:48)
                                                                               at com.android.okhttp.internal.http.HttpConnection$FixedLengthSource.read(HttpConnection.java:446)
                                                                               at com.android.okio.RealBufferedSource$1.read(RealBufferedSource.java:168)
                                                                               at java.io.InputStream.read(InputStream.java:162)
                                                                               at com.google.firebase.storage.FileDownloadTask.run(Unknown Source)
                                                                               at com.google.firebase.storage.StorageTask$5.run(Unknown Source)
                                                                               at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                                                                               at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                                                                               at java.lang.Thread.run(Thread.java:818)

但是当我对上传执行完全相同的操作时,它只是等待连接,如果我再次打开 Wifi,它会重新连接并恢复。为什么问题只发生在下载文件时? 又是 getFile() API 的问题吗?

仅供参考,我没有更改上传和下载的超时设置。它们处于默认状态。

【问题讨论】:

  • 对于下载,您是否尝试过直接使用 DownloadUrl 而不是使用 Stream/FileDownloadTask?这样更好吗?
  • videos which can be even larger than 2 GB some times - 天啊。为什么选择 Firebase?尝试使用一些 FTP 服务器。
  • @BenjaminWulfe 问题不仅在于下载,还在于上传和下载。怎么解决?
  • @ReazMurshed 我几乎使用了 Firebase 提供的所有服务,这就是我选择使用 Firebase 存储的原因。它还得到 Google Cloud Storage 的支持,因此我可以享受它提供的所有好处。为什么我不应该将 Firebase 存储用于大文件?缺点是什么?
  • Firebase 通过客户端编码提供服务器端实现以及其他一些非凡的功能。现在,如果您必须编写自己的服务器端服务,您可能会考虑使用某些 FTP 服务器上传大文件,对吧? Firebase 拥有一个带有客户端应用程序的 websocket,这也有点昂贵。但无论如何,它的效果很好。

标签: android firebase firebase-storage


【解决方案1】:

我提供这个并不是为了反驳你的观察,而是作为一个比较点。作为测试,我使用下面的代码上传了一个约 50MB 的文件并计算进度。该测试是在带有家庭 WiFi 连接(加利福尼亚州)的三星 Galaxy S3 (4.4.2) 上运行的。平均吞吐量约为 760KB/秒。

我在使用相同网络的其他电话设备上进行了相同的测试,吞吐量范围从 300KB/秒到 850KB/秒(Moto X Pure;Marshmallow)。

private void uploadTest() {
    // This file is ~50MB
    final File file = new File("/storage/emulated/0/DCIM/Camera/20160821_101145.mp4");
    // Upload the file
    Log.i(TAG, String.format("uploadTest: Starting upload of %5.2fMB file",
            file.length()/1024.0/1024.0));

    FirebaseStorage.getInstance().getReference("test").putFile(Uri.fromFile(file))
            .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                    Log.i(TAG, "onSuccess: Done");
                }
            }).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
            Log.i(TAG, String.format("onProgress: %5.2f MB transferred",
                    taskSnapshot.getBytesTransferred()/1024.0/1024.0));
        }
    });
}

这是生成的 logcat,删除了一些进度线以使列表更紧凑:

08-21 11:39:17.539 18427-18427/com.qbix.test I/MainActivity: uploadTest: Starting upload of 51.79MB file
08-21 11:39:17.559 18427-18427/com.qbix.test I/MainActivity: onProgress:  0.00 MB transferred
08-21 11:39:25.117 18427-18427/com.qbix.test I/MainActivity: onProgress:  5.00 MB transferred
08-21 11:39:31.654 18427-18427/com.qbix.test I/MainActivity: onProgress: 10.00 MB transferred
08-21 11:39:38.711 18427-18427/com.qbix.test I/MainActivity: onProgress: 15.00 MB transferred
08-21 11:39:45.088 18427-18427/com.qbix.test I/MainActivity: onProgress: 20.00 MB transferred
08-21 11:39:51.375 18427-18427/com.qbix.test I/MainActivity: onProgress: 25.00 MB transferred
08-21 11:39:57.411 18427-18427/com.qbix.test I/MainActivity: onProgress: 30.00 MB transferred
08-21 11:40:03.408 18427-18427/com.qbix.test I/MainActivity: onProgress: 35.00 MB transferred
08-21 11:40:10.886 18427-18427/com.qbix.test I/MainActivity: onProgress: 40.00 MB transferred
08-21 11:40:17.233 18427-18427/com.qbix.test I/MainActivity: onProgress: 45.00 MB transferred
08-21 11:40:23.069 18427-18427/com.qbix.test I/MainActivity: onProgress: 50.00 MB transferred
08-21 11:40:25.792 18427-18427/com.qbix.test I/MainActivity: onProgress: 51.79 MB transferred
08-21 11:40:25.792 18427-18427/com.qbix.test I/MainActivity: onSuccess: Done 

【讨论】:

  • 感谢您的测试。顺便说一句,您用于测试的网络的总带宽是多少?我从来没有得到超过总带宽的 15%。
  • @AritraRoy:Ookla 速度测试测得的上传速度为 12 Mbits/sec。
  • 我明白了。很难找出我到底做错了什么。可能是因为我在后台线程中使用它吗?
  • 我怀疑这是原因,但不知道。我在不同设备上得到的结果表明设备性能(内存、处理器等)是一个因素。您是否在中高性能设备上进行测试?此外,我发现 Android Studio 中的 Monitors 窗格(CPU、内存、网络)可以很好地概述测试期间的活动。观看它可能会给您一些见解。
  • Aritra -- 能否请您在使用 getDownloadUrl() 返回的 url 下载时测试下载速度?这很重要的原因是它会给我们(谷歌)一个指示,表明问题是在我们的客户端 sdk 中的某个地方,还是在网络路由中。此外,请检查您的设备上是否有其他进程正在运行,这些进程可能会占用 CPU 周期。
【解决方案2】:

我一直在做一些测试,并试图弄清为什么你会看到性能不佳的原因。 当使用 getStream 一次读取单个字节时,我已经能够复制糟糕的性能,但这可以通过读取合理大小的字节缓冲区(256kb 缓冲区)来解决。 修复这个之后,我看到的性能相当于直接用httpsUrlConnection下载了。

三种可能性出现在我的脑海中:

1) 您在 dns 解析期间看到超时(到我们的多个 ip),并且连接池在上传期间不起作用。但这只能解释为什么上传(分块)会很慢。下载不会分块。

2) 您位于我们尚未优化的区域。我们即将在亚洲和欧洲推出本地支持以优化性能。

3) 也许您正在将它与 httpsurlconnection 以外的其他东西进行比较?你能提供更多的测试细节吗?

这是我的测试:

        final long startTime = System.currentTimeMillis();
        // Test via Firebase
        mStorage.child(downloadPath).getStream(new StreamDownloadTask.StreamProcessor() {
               @Override
               public void doInBackground(StreamDownloadTask.TaskSnapshot taskSnapshot,
                      final InputStream inputStream) throws IOException {
                 readStream("FB", inputStream, startTime);
               }
        });

        //Test with AsyncTask
        AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                URL url = null;
                try {
                    url = new URL(uri.toString());
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                try {
                    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
                    connection.connect();
                    if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                        return null;
                    }
                    InputStream inputStream = connection.getInputStream();
                    readStream("ASYNC_TASK", inputStream, startTime);
                    inputStream.close();

                }
                catch(IOException e) {

                }

                return null;
            }
        };

        task.execute();

    private void readStream(String desc, InputStream inputStream, long startTime) {
      long bytesRead = 0;
      byte[] buffer = new byte[256*1024];
      int b = 1;
      try {
        while (b > 0) {
            b = inputStream.read(buffer);
            bytesRead += b;
                Log.i("giug", "PROGRESS_" + desc + ": bytesperMS:" +
                        (bytesRead / (System.currentTimeMillis() - startTime)));
        }
        inputStream.close();
      } catch (IOException e) {
          e.printStackTrace();
      }
   } 

【讨论】:

  • 但我一直在使用 getFile() 而不是 getStream()。你能分享你的代码,以便我可以实现它并用结果回复你吗?我遇到了一个非常奇怪的问题并更新了我的问题。你能帮忙吗?
  • 您关于下载重试的问题是另一个问题。所以要确认一下——性能问题只存在于上传上?
  • 不,传输速度慢的问题是两者都有。我已经问了一个关于退休的单独问题,stackoverflow.com/questions/38993429/…。如果可能,请帮助解决这个问题。 Firebase Storage 似乎有几个问题,如果它有这个问题,那么我将不得不停止在我的应用中使用它。
  • 我已经添加了我的测试代码,它对我来说显示了异步任务和通过 firebase 之间的相同结果。我不会同时运行它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2016-05-21
  • 2019-09-10
  • 1970-01-01
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
相关资源
最近更新 更多