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

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을 실행하고 있습니다.

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



답변

업데이트 : 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에서 멈춘 부분을 분리하는 데 도움이 될 수 있습니까?


답변

업데이트 날짜 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에서이 문제를 해결할 때까지 계속 움직이기 위해.


답변

오늘 아침까지이 문제가있었습니다. 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
    }
}


답변

거의 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 ()를 호출하지 않아도 아무것도 변경되지 않습니다.


답변

글쎄요, 제가 현재하고있는 일에서 에뮬레이터와 실제 안드로이드 폰 화웨이 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


답변