데이터 가져 오기시 Firestore 성능 저하 문제


78

1/10 비율의 실시간 데이터베이스에 비해 문서에 저장된 기본 데이터를 검색하는 동안 Firestore에서 성능 저하 문제가 있습니다.

Firestore를 사용하면 첫 번째 호출에서 평균 3000ms가 걸립니다.

 this.db.collection(‘testCol’)
   .doc(‘testDoc’)
   .valueChanges().forEach((data) => {
     console.log(data);//3000 ms later
 });

실시간 데이터베이스를 사용하면 첫 번째 호출에서 평균 300ms가 걸립니다.

 this.db.database.ref(‘/test’).once(‘value’).then(data => {
     console.log(data); //300ms later
 });

다음은 네트워크 콘솔의 스크린 샷입니다.

Firestore 성능 저하 문제 데이터 가져 오기

AngularFire2 v5.0 rc.2와 함께 Javascript SDK v4.50을 실행하고 있습니다.

누구든지이 문제를 경험 했습니까?


두 번째 호출 (다른 문서 / 컬렉션)을하면 어떤 성능이 보입니까? 앵귤러 파이어를 사용하지 않으면 같은 문제가 발생합니까?
Sam Stern

비슷한 경험이 있습니다. 첫 번째 호출은 약간 느립니다. 때로는 5-10 초입니다. 채팅 앱을 만들고 있습니다. 첫 번째 메시지는 전달하는 데 시간이 걸리지 만 다음 메시지는 거의 즉각적입니다. Firestore 아직 베타 버전 이며 여전히 문제를 해결하고 있습니다.
xenetics

1
비슷한 경험이 있습니다. 먼저 onSnapShot 시간의 부당한 금액을 소요 - 최대 unuseable 우리의 응용 프로그램을 렌더링하고 일부 사용자에게 2 분에
wizloc

똑같은 문제, 꽤 실망 스럽습니다. 일부는 쓰기를하면 "정지 된"쿼리가 해제된다고보고합니다.
DarkNeuron

같은 호, 간단한 collection.get (문서)로 최대 1.5 분
aMarCruz

답변:


44

업데이트 : 2018 년 2 월 12 일-iOS Firestore SDK v0.10.0

다른 댓글 작성자와 마찬가지로 첫 번째 get 요청에서 응답 속도가 느리다는 것을 발견했습니다 (이후 요청은 ~ 100ms 소요). 저에게는 30 대만큼 나쁘지는 않지만 연결 상태가 좋으면 2-3 초 정도가 될 수 있습니다. 앱이 시작될 때 나쁜 사용자 경험을 제공하기에 충분합니다.

Firebase는이 '콜드 스타트'문제를 알고 있으며 이에 대한 장기적인 수정 작업을 진행 중이라고 조언했습니다. 안타깝게도 ETA는 없습니다. 연결 상태가 좋지 않은 경우 요청이 캐시에서 읽기로 결정되기까지 시간이 오래 걸릴 수 있다는 것은 별도의 문제라고 생각합니다.

Firebase가 이러한 모든 문제를 해결하는 동안 저는 새로운 disableNetwork()enableNetwork()메서드 (Firestore v0.10.0에서 사용 가능)를 사용하여 Firebase의 온라인 / 오프라인 상태를 수동으로 제어 하기 시작했습니다 . 나는 것으로 했어하지만 매우 특정 시나리오에서 충돌이 발생할 수있는 경우 FireStore 버그 거기에 나는, 내 코드에서 사용할 경우주의하십시오.


업데이트 : 2017 년 11 월 15 일-iOS Firestore SDK v0.9.2

성능 저하 문제가 해결 된 것 같습니다. 아래에 설명 된 테스트를 다시 실행했으며 Firestore가 100 개의 문서를 반환하는 데 걸리는 시간은 이제 일관되게 약 100ms 인 것 같습니다.

이것이 최신 SDK v0.9.2의 수정인지 아니면 백엔드 수정 (또는 둘 다)인지 확실하지 않지만 모두가 Firebase 포드를 업데이트하는 것이 좋습니다. 내 앱은 실시간 DB에서와 비슷하게 눈에 띄게 더 반응이 좋습니다.


또한 특히 많은 문서를 읽을 때 Firestore가 Realtime DB보다 훨씬 느리다는 것을 발견했습니다.

업데이트 된 테스트 (최신 iOS Firestore SDK v0.9.0 포함) :

RTDB와 Firestore를 모두 사용하여 iOS Swift에서 테스트 프로젝트를 설정하고 각각에 대해 100 개의 순차적 읽기 작업을 실행했습니다. RTDB의 경우 observeSingleEvent를 테스트하고 100 개의 최상위 노드 각각에서 메소드를 관찰했습니다. Firestore의 경우 TestCol 컬렉션의 100 개 문서 각각에서 getDocument 및 addSnapshotListener 메서드를 사용했습니다. 디스크 지속성을 켜고 끄면서 테스트를 실행했습니다. 각 데이터베이스의 데이터 구조를 보여주는 첨부 이미지를 참조하십시오.

동일한 장치와 안정적인 Wi-Fi 네트워크에서 각 데이터베이스에 대해 10 번 테스트를 실행했습니다. 기존 관찰자와 청취자는 각각의 새로운 실행 전에 파괴되었습니다.

실시간 DB observeSingleEvent 메소드 :

func rtdbObserveSingle() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from RTDB at: \(start)")

    for i in 1...100 {
        Database.database().reference().child(String(i)).observeSingleEvent(of: .value) { snapshot in
            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            let data = snapshot.value as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

실시간 DB 관찰 방법 :

func rtdbObserve() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from RTDB at: \(start)")

    for i in 1...100 {
        Database.database().reference().child(String(i)).observe(.value) { snapshot in
            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            let data = snapshot.value as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

Firestore getDocument 메소드 :

func fsGetDocument() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from FS at: \(start)")

    for i in 1...100 {
        Firestore.firestore().collection("TestCol").document(String(i)).getDocument() { document, error in

            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            guard let document = document, document.exists && error == nil else {
                print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
                return
            }
            let data = document.data() as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

Firestore addSnapshotListener 메소드 :

func fsAddSnapshotListener() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from FS at: \(start)")

    for i in 1...100 {
        Firestore.firestore().collection("TestCol").document(String(i)).addSnapshotListener() { document, error in

            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            guard let document = document, document.exists && error == nil else {
                print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
                return
            }
            let data = document.data() as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

각 메서드는 기본적으로 메서드가 실행을 시작할 때 밀리 초 단위로 유닉스 타임 스탬프를 인쇄하고 각 읽기 작업이 반환 될 때 다른 유닉스 타임 스탬프를 인쇄합니다. 초기 타임 스탬프와 반환 할 마지막 타임 스탬프의 차이를 확인했습니다.

결과-디스크 지속성이 비활성화 됨 :

디스크 지속성 비활성화

결과-디스크 지속성 사용 :

디스크 지속성 사용

데이터 구조 :

데이터 구조

Firestore getDocument / addSnapshotListener 메서드가 중단되면 대략 30 초의 배수 인 기간 동안 중단 된 것 같습니다. 아마도 이것이 Firebase 팀이 SDK에서 멈춘 부분을 분리하는 데 도움이 될 수 있습니까?


2
그래서 firestore는 더 비싸고 훨씬 느립니다 .. Hope
firebase

6
[Firebaser here] 이러한 자세한 데이터를 제공해 주셔서 감사합니다. 항상 감사합니다. 문제는 시스템이 "느려진다"는 것이 아니라 매우 적은 수의 쿼리가 중단되거나 반환하는 데 엄청난 시간이 걸린다는 것입니다. 곧 상황을 개선 할 수있는 몇 가지 수정 사항이 있습니다.
Sam Stern

1
계속 업데이트 해 주셔서 감사합니다. 최신 Firestore SDK v0.9.0에 대한 몇 가지 새로운 결과를 추가하여 팀이 문제의 원인을 분리하는 데 도움이 될 수 있습니다. 또한 스냅 샷 리스너에 또 다른 문제가 발생했습니다. stackoverflow.com/questions/46710371/… 근본 원인은이 주제와 관련이있을 수도 있고 아닐 수도 있지만 Firebase 팀에서 살펴볼 수 있다면 좋을 것입니다. . 감사합니다!
Saul

3
또한 웹 SDK에서 "고착 된"쿼리가 발생합니다. 10-20 초 동안 중단 된 다음 데이터가 도착합니다 (v4.8.0).
DarkNeuron

1
나는 이것을 최근에 발견하고 Firebase 에보 고했습니다. 그들은 "콜드 스타트"문제를 알고 있으며 해결을 위해 노력하고 있습니다. 그 동안 위의 업데이트에 자세히 설명 된 해결 방법을 시도하고 있으며 다양한 수준의 성공을 거두었습니다.
Saul

21

업데이트 날짜 2018 년 3 월 2 일

이는 알려진 문제로 보이며 Firestore의 엔지니어가 문제를 해결하기 위해 노력하고 있습니다. 이 문제에 대해 Firestore 엔지니어와 몇 차례 이메일을 교환하고 코드를 공유 한 후 이것이 오늘의 답변이었습니다.

"실제로 맞습니다. 추가로 확인한 결과 getDocuments () API의 이러한 속도 저하는 Cloud Firestore 베타에서 알려진 동작입니다. Google 엔지니어는"콜드 스타트 ​​"태그가 지정된이 성능 문제를 알고 있지만 걱정하지 마십시오. Firestore 쿼리 성능을 개선하기 위해 최선을 다하고 있습니다.

이미 장기적인 수정 작업을 진행 중이지만 현재로서는 일정이나 세부 사항을 공유 할 수 없습니다. Firestore는 아직 베타 버전이지만 앞으로 더 많은 개선 사항이있을 것으로 기대합니다. "

그래서 바라건대 이것은 곧 녹아웃 될 것입니다.


Swift / iOS 사용

약 3 일 동안 이것을 처리 한 후 문제는 확실히 get () 즉 .getDocuments 및 .getDocument 인 것 같습니다. 내가 생각 하기에 극단적이지만 간헐적 인 지연이 발생했지만 그렇지 않은 것 같습니다.

  1. 네트워크 연결성이 좋지 않음
  2. .getDocument () 루프를 통한 반복 호출
  3. get () 호출 연결
  4. Firestore 콜드 스타트
  5. 여러 문서를 가져 오는 중 (작은 문서 1 개를 가져 오면 20 초 지연됨)
  6. 캐싱 (오프라인 지속성을 비활성화했지만 아무것도하지 않았습니다.)

내가 만드는 모든 Firestore 데이터베이스 호출에서이 문제가 발생하지 않는다는 것을 알았 기 때문에이 모든 것을 배제 할 수있었습니다. get ()을 사용하여 검색 만합니다. 킥을 위해 .getDocument를 .addSnapshotListener로 대체하여 데이터와 짜잔을 검색했습니다. 첫 번째 호출을 포함하여 매번 즉시 검색. 콜드 스타트가 없습니다. 지금까지 .addSnapshotListener에는 문제가 없으며 getDocument (s) 만 있습니다.

지금은 시간이 중요한 .getDocument ()를 삭제하고 .addSnapshotListener로 바꾼 다음

for document in querySnapshot!.documents{
// do some magical unicorn stuff here with my document.data()
}

... Firestore에서이 문제를 해결할 때까지 계속 움직이기 위해.


같은 동작이 Android에서만 나타납니다. 지금은 스냅 샷으로 돌아갑니다. 그러나 get 쿼리의 성능이 일관되면 좋을 것입니다.
sowdri apr

또한 addSnapshotListener를 사용하는 FirebaseUI 리사이클 러 어댑터에서도 성능이 느려집니다.
Jeff Padgett

이 "콜드 스타트"문제가 여전히 존재합니까? 3 월에 업데이트 한 귀하의 업데이트가 Firebase 엔지니어가 "콜드 스타트"문제로 태그를 지정하는 것을 알고 있다고 언급하면서 약간 혼란 스럽습니다. 원래 답변에서 "4. Firestore 콜드 스타트"를 배제했다고 썼기 때문입니다. 문제?
trollkotze

나는 여전히 안드로이드의 느린 성능과 많은 메모리 문제를보고 있습니다. 너희들이 수정 어떤 업데이트를 제공 할 계획
pannu 히텐

이 문제는 최신 버전의 firestore i에서 계속 발생합니다. iOS와 스냅 샷 리스너 사용은 마치 매력처럼 작동했습니다. 훌륭한 발견.
johndoe

8

오늘 아침까지이 문제가있었습니다. iOS / Swift를 통한 Firestore 쿼리는 1 개 항목에 대한 비 비례 쿼리 시간이 반환 된 상태에서 단순하고 완전히 인덱싱 된 쿼리를 완료하는 데 약 20 초가 걸립니다.

내 해결책은 오프라인 데이터 지속성을 비활성화하는 것이 었습니다. 제 경우에는 매일 업데이트되는 데이터의 상당 부분이있는 Firestore 데이터베이스의 요구 사항에 맞지 않았습니다.

iOS 및 Android 사용자는이 옵션을 기본적으로 활성화하고 웹 사용자는이 옵션을 기본적으로 비활성화합니다. 방대한 문서 컬렉션을 쿼리하는 경우 Firestore가 엄청나게 느려 보입니다. 기본적으로 쿼리하는 데이터의 사본을 캐시합니다 (그리고 쿼리하는 컬렉션-나는 모든 문서를 캐시한다고 생각합니다). 이는 높은 메모리 사용량으로 이어질 수 있습니다.

제 경우에는 장치가 필요한 데이터를 캐시 할 때까지 모든 쿼리에 대해 엄청난 대기가 발생했습니다. 따라서 동일한 컬렉션에서 반환되는 항목 수가 증가하는 데 비례하지 않는 쿼리 시간이 발생했습니다. 이는 각 쿼리에서 컬렉션을 캐시하는 데 동일한 시간이 걸렸기 때문입니다.

오프라인 데이터-Cloud Firestore 문서에서

동일한 쿼리 컬렉션에서이 효과 (오프라인 지속성을 활성화 한 상태)를 표시하기 위해 몇 가지 벤치마킹을 수행했지만 .limit 매개 변수를 사용하여 반환 된 항목의 양이 다릅니다.

벤치 마크 이제 100 개 항목이 반환되면 (오프라인 지속성이 비활성화 됨) 쿼리를 완료하는 데 1 초도 걸리지 않습니다.

내 Firestore 쿼리 코드는 다음과 같습니다.

let db = Firestore.firestore()
self.date = Date()
let ref = db.collection("collection").whereField("Int", isEqualTo: SomeInt).order(by: "AnotherInt", descending: true).limit(to: 100)
ref.getDocuments() { (querySnapshot, err) in
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
        for document in querySnapshot!.documents {
            let data = document.data()
            //Do things
        }
        print("QUERY DONE")
        let currentTime = Date()
        let components = Calendar.current.dateComponents([.second], from: self.date, to: currentTime)
        let seconds = components.second!
        print("Elapsed time for Firestore query -> \(seconds)s")
        // Benchmark result
    }
}

웹, iOS 또는 Android의 테스트 번호입니까?
Sam Stern

벤치 마크는 iOS에서 가져온 것입니다. 모든 플랫폼에서 성능 향상을 기대합니다. 쿼리 한 컬렉션의 크기에 따라 달라집니다
Hendies

당신이 Firebase 팀이라는 사실을 몰랐습니다! 이 쿼리에 대한 공짜는 우리 컬렉션이 캐시에 저장되었다고 가정했을 때 메모리 사용량이 높은 숫자 (600-700mb 램)까지 증가한다는 것입니다. 쿼리는 항상 중단되고 메모리가 점진적으로 증가한 다음 동일한 지점 (700mb-ish)에 도달하면 완료됩니다. 지속성이 비활성화 된 후이 효과는 중단되고 메모리는 예상대로 (100-150MB) 유지되었으며 결과는 매우 빠릅니다. 더 많은 정보가 필요하면 문의하십시오.
Hendies

매우 흥미 롭군요. 이것을 복제 한 샘플 Xcode 프로젝트를 만들어 이메일로 보내 주시겠습니까? 그렇다면 Google 닷컴의 samstern입니다. 자세히 살펴보고 싶습니다.
Sam Stern

@SamStern : 이것은 오래되었지만 Android에서 똑같은 문제에 직면하고 있습니다. 원인에 대한 단서가 있습니까? 최소한의 프로젝트를 만들려고했지만 그 프로젝트에는 문제가 없습니다!
rednuht

6

거의 3 년 후, Firestore는 베타에서 완전히 벗어 났고이 끔찍한 문제가 여전히 지속된다는 것을 확인할 수 있습니다 ;-(

모바일 앱에서는 javascript / node.js firebase 클라이언트를 사용합니다. 앱의 시작 시간이 약 10 초인 이유를 알아 내기 위해 많은 테스트를 마친 후 그 시간의 70 %를 차지하는 원인을 파악했습니다.

  • firebase.auth (). onAuthStateChanged ()는 약을 발생시킵니다. 1.5-2 초 후, 이미 상당히 나쁩니다.
  • 사용자를 반환하면 해당 ID를 사용하여 firestore에서 사용자 문서를 가져옵니다. 이것은 firestore에 대한 첫 번째 호출이며 해당 get ()은 4 ~ 5 초가 걸립니다. 동일한 문서 또는 다른 문서의 후속 get ()에는 약이 걸립니다. 500ms.

따라서 전체 사용자 초기화에는 6 ~ 7 초가 소요되며 완전히 허용되지 않습니다. 그리고 우리는 그것에 대해 아무것도 할 수 없습니다. javascript 클라이언트에는 이러한 옵션이 없기 때문에 지속성 비활성화를 테스트 할 수 없습니다. 지속성은 기본적으로 항상 활성화되어 있으므로 enablePersistence ()를 호출하지 않아도 아무것도 변경되지 않습니다.


이 문제에 대한 해결 방법이 있습니까? 답변을 찾을 수있는 위치에 대한 몇 가지 조언을 주시면 감사하겠습니다.
bjornl

자바 스크립트 클라이언트에서는 기본적으로 꺼져 For the web, offline persistence is disabled by default. To enable persistence, call the enablePersistence method있습니다 . 하지만 꺼두면 초기 요청 시간이 비슷한 ~ 8 초에서 약 ~ 500ms로 줄어 듭니다. firebase.google.com/docs/firestore/manage-data/ enable-offline
pat

맞습니다. 자바 스크립트에서는 기본적으로 꺼져 있으며 위에서 언급 한 시간은 기본 설정입니다. 그리고 우리의 경우에는 새롭고 업데이트 된 사용자 프로필 데이터가 필요하므로 지속성을 사용하는 것은 선택 사항이 아닙니다.
JPJ

1

글쎄요, 제가 현재하고있는 일에서 에뮬레이터와 실제 안드로이드 폰 화웨이 P8에서 nexus 5X를 사용하여 연구하고 있습니다.

Firestore와 Cloud Storage는 모두 처음 document.get () 및 first storage.getDownloadUrl ()을 수행 할 때 응답 속도가 느려서 골칫거리입니다.

각 요청에 대해 60 초 이상의 응답을 제공합니다. 느린 응답은 실제 안드로이드 폰에서만 발생합니다. 에뮬레이터가 아닙니다. 또 다른 이상한 것. 첫 만남 후 나머지 요청은 원활합니다.

느린 응답을 만나는 간단한 코드는 다음과 같습니다.

var dbuserref = dbFireStore.collection('user').where('email','==',email);
const querySnapshot = await dbuserref.get();

var url = await defaultStorage.ref(document.data().image_path).getDownloadURL();

나는 또한 같은 것을 연구하는 링크를 찾았습니다. https://reformatcode.com/code/android/firestore-document-get-performance

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.