데이터베이스 성능 최적화

앱에서 Firebase 실시간 데이터베이스의 성능을 개선하는 방법에는 여러 가지가 있습니다. 실시간 데이터베이스 성능을 최적화할 방법을 파악하려면 다양한 실시간 데이터베이스 모니터링 도구를 통해 데이터를 수집한 다음 그에 따라 앱 또는 실시간 데이터베이스 사용을 변경하면 됩니다.

실시간 데이터베이스 성능 모니터링

원하는 상세 수준에 따라 몇몇 도구를 통해 실시간 데이터베이스 성능에 대한 데이터를 수집할 수 있습니다.

  • 개략적인 개요: 프로파일러 도구를 사용하면 색인이 생성되지 않은 쿼리 목록과 읽기/쓰기 작업의 실시간 개요를 확인할 수 있습니다.
  • 청구 사용량 추정: Firebase Console에서 제공되는 사용량 측정항목을 사용하여 청구 사용량과 높은 수준의 성능 측정항목을 확인할 수 있습니다.
  • 상세 분석: Cloud Monitoring을 사용하면 시간 경과에 따른 데이터베이스 성능 변화를 더 상세하게 파악할 수 있습니다.

측정항목별 성능 개선

데이터를 수집한 후 개선할 성능 영역에 따라 다음과 같은 권장사항 및 전략에 대해 알아보세요.

성능 개선 전략 요약
측정항목 설명 권장사항
부하/사용률 특정 시점에 요청을 처리하는 데 사용되는 데이터베이스 용량을 최적화합니다(**Load** 또는 **io/database_load** 측정항목에 반영). 데이터 구조 최적화
데이터베이스 간 데이터 샤딩
리스너 효율 개선
쿼리 기반 규칙을 사용한 다운로드 제한
연결 최적화
활성 연결 데이터베이스에 대한 동시 활성 연결 수가 200,000개의 연결 한도를 초과하지 않도록 조정합니다. 데이터베이스 간 데이터 샤딩
새 연결 감소
발신 대역폭 데이터베이스에서 원하는 것보다 더 많은 양이 다운로드되는 것 같다면 읽기 작업의 효율을 높이고 암호화 오버헤드를 줄일 수 있습니다. 연결 최적화
데이터 구조 최적화
쿼리 기반 규칙을 사용한 다운로드 제한
SSL 세션 재사용
리스너 효율 개선
데이터 액세스 제한
스토리지 사용하지 않는 데이터를 저장하고 있는지 확인하고 할당량을 초과하지 않도록 저장된 데이터를 다른 데이터베이스 또는 Firebase 제품에 분산시킵니다. 사용하지 않는 데이터 정리
데이터 구조 최적화
데이터베이스 간 데이터 샤딩
Firebase용 Cloud Storage 사용

연결 최적화

GETPUT과 같은 RESTful 요청은 단시간이더라도 연결이 필요합니다. 이처럼 빈번한 짧은 연결은 데이터베이스에 대한 실시간 활성 연결보다 훨씬 많은 연결 비용, 데이터베이스 부하, 발신 대역폭을 초래할 수 있습니다.

가능하다면 REST API 대신 앱 플랫폼에 기본 SDK를 사용하세요. SDK는 개방형 연결을 유지하므로 REST API로 인해 늘어날 수 있는 SSL 암호화 비용과 데이터베이스 부하가 줄어듭니다.

REST API를 사용하는 경우 HTTP 연결 유지를 사용하여 개방형 연결을 유지하거나 서버 전송 이벤트를 사용하여 SSL 핸드셰이크에 따르는 비용을 줄여보세요.

여러 데이터베이스 간 데이터 샤딩

여러 실시간 데이터베이스 인스턴스 간에 데이터를 분할(데이터베이스 샤딩)하면 다음과 같은 3가지 이점이 있습니다.

  1. 데이터베이스 인스턴스 간에 데이터를 분할하면 앱에 허용되는 총 동시 활성 연결 수가 늘어납니다.
  2. 데이터베이스 인스턴스 간에 부하의 균형을 맞춥니다.
  3. 개별 데이터 세트에만 액세스해야 하는 독립적인 사용자 그룹이 있을 경우 여러 데이터베이스 인스턴스를 사용하면 처리량을 높이고 지연 시간을 줄일 수 있습니다.

Blaze 요금제를 사용 중인 경우 동일한 Firebase 프로젝트 내에서 여러 데이터베이스 인스턴스를 만들어 여러 데이터베이스 인스턴스에서 공통된 사용자 인증 방법을 활용할 수 있습니다.

데이터 샤딩 방법 및 시기에 대해 자세히 알아보세요.

효율적인 데이터 구조 구축

실시간 데이터베이스는 경로뿐만 아니라 경로의 하위 노드에서도 데이터를 가져오기 때문에 데이터 구조를 최대한 평면화하는 것이 좋습니다. 그러면 필요한 데이터를 선택적으로 가져올 수 있으며 클라이언트에 불필요한 데이터를 다운로드할 필요도 없습니다.

특히 데이터를 구조화할 때는 쓰기 및 삭제를 고려해야 합니다. 예를 들어 리프가 수천 개인 경로는 삭제하는 데 비용이 많이 들 가능성이 높습니다. 경로를 여러 개의 하위 트리와 적은 수의 노드당 리프로 분할하면 삭제 속도가 빨라집니다.

또한 각각의 쓰기가 전체 데이터베이스 사용률의 0.1%를 차지할 수 있습니다. SDK의 update() 메서드 또는 RESTful PATCH 요청을 통해 다중 경로 업데이트로 쓰기를 단일 작업으로 일괄 처리할 수 있도록 데이터를 구조화합니다.

데이터 구조를 최적화하고 성능을 개선하려면 데이터 구조 권장사항을 따르세요.

무단 액세스 방지

실시간 데이터베이스 보안 규칙을 사용하여 데이터베이스에 대한 무단 작업을 방지하세요. 예를 들어 규칙을 사용하면 악의적인 사용자가 전체 데이터베이스를 반복적으로 다운로드하는 상황을 피할 수 있습니다.

Firebase 실시간 데이터베이스 규칙 사용에 대해 자세히 알아보세요.

쿼리 기반 규칙을 사용한 다운로드 제한

실시간 데이터베이스 보안 규칙으로 데이터베이스의 데이터 액세스를 제한할 뿐만 아니라 읽기 작업을 통해 반환되는 데이터를 제한할 수도 있습니다. query.limitToFirst 등의 query. 표현식으로 정의된 쿼리 기반 규칙을 사용하면 쿼리가 규칙에 의해 제한된 데이터만 가져옵니다.

예를 들어 다음 규칙은 읽기 액세스를 쿼리 결과 중 우선순위에 따라 정렬한 처음 1,000개로 제한합니다.

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example query:
db.ref("messages").limitToFirst(1000)
                  .orderByKey("value")

실시간 데이터베이스 보안 규칙에 대해 자세히 알아보세요.

쿼리 색인 생성

데이터를 색인화하면 앱이 쿼리를 실행할 때마다 사용되는 총 대역폭이 감소합니다.

SSL 세션 재사용

TLS 세션 티켓을 발급하여 재개된 연결의 SSL 암호화 오버헤드 비용을 줄이세요. 이 방법은 데이터베이스에 대한 보안 연결이 자주 필요한 경우에 특히 유용합니다.

리스너 효율 개선

리스너를 경로에서 최대한 아래에 배치하여 동기화하는 데이터 양을 제한하세요. 가져올 데이터와 리스너가 가까워야 합니다. 데이터베이스 루트를 수신 대기하면 전체 데이터베이스가 다운로드되므로 권장하지 않습니다.

수신 대기 작업으로 반환되는 데이터를 제한하는 쿼리를 추가하고 데이터 업데이트만 다운로드하는 리스너(예: once() 대신 on())를 사용하세요. 데이터 업데이트가 전혀 필요하지 않은 작업에는 .once()를 예약합니다. 또한 가능하다면 최상의 성능을 위해 orderByKey()를 사용하여 쿼리를 정렬합니다. orderByChild()를 사용하여 정렬하면 6~8배 더 느려질 수 있으며 orderByValue()를 사용한 정렬은 영구적 계층에서 전체 위치를 읽어야 하므로 대규모 데이터 세트를 처리할 때 속도가 매우 느릴 수 있습니다.

또한 리스너를 상황에 맞게 자유롭게 추가하고 더 이상 필요 없으면 삭제합니다.

사용하지 않는 데이터 정리

데이터베이스에서 사용되지 않거나 중복된 데이터를 주기적으로 삭제하세요. 백업을 실행하여 수동으로 데이터를 검사하거나 주기적으로 Google Cloud Storage 버킷에 백업할 수 있습니다. 또한 저장된 데이터를 Firebase용 Cloud Storage를 통해 호스팅하는 것도 고려해 보세요.

업데이트 가능한 확장형 코드 포함

IoT 기기에 내장된 앱에는 쉽게 업데이트할 수 있는 확장형 코드를 포함해야 합니다. 사용 사례를 철저히 테스트하고 사용자층이 급증할 수 있는 상황을 고려하고 코드에 업데이트를 배포하는 기능을 구축하세요. 예를 들어 데이터 샤딩과 같이 향후 대대적인 변경이 필요할 수 있는 경우를 신중하게 고려하세요.