Производительность для базы данных Firestore пишет? - PullRequest
1 голос
/ 01 февраля 2020

ОС: Ma c ОС Catalina v 10.15.1

Python версия: Python 3.7.1

Я использую Firestore в качестве базы данных для личного проекта с Python SDK. В настоящее время я пытаюсь оптимизировать свой бэкэнд, и я заметил, что записи в Firestore довольно медленные. Возьмите пример кода ниже:

import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
import time


cred = credentials.Certificate("./path/to/adminsdk.json")
firebase_admin.initialize_app(cred)
db = firestore.client()

test_data = {f"test_field_{i}":f"test_value_{i}" for i in range(20)}

now = time.time()
db.collection(u'latency_test_collection').document(u'latency_test_document').set(test_data)
print(f"Total time: {time.time()-now}")

Для выполнения кода выше> 300 мс, что кажется довольно медленным, особенно когда у меня многократные записи гораздо большего размера, чем в приведенном выше примере. Я проверил свое inte rnet соединение, и независимо от соединения производительность колеблется вокруг этого значения. Ожидается ли такая производительность при записи в Firestore или есть способ оптимизировать мой код для этого?

Ответы [ 2 ]

0 голосов
/ 12 апреля 2020

Как сказал @ Nebulasti c, пакеты намного эффективнее, чем транзакции по одной. Я только что провел тест со своего ноутбука в Европе до Firestore, расположенного в us-west2 (Лос-Анджелес). Вот фактические результаты по одному удалению и пакетному удалению.

$ python firestore_test.py 
Creating 10 documents
Wrote 10 documents in 1.80 seconds.
Deleting documents one by one
Deleted 10 documents in 7.97 seconds.
###
Creating 10 documents
Wrote 10 documents in 0.92 seconds.
Deleting documents in batch
Deleted 10 documents in 1.71 seconds.
###
Creating 2000 documents
Wrote 2000 documents in 6.27 seconds.
Deleting documents in batch
Deleted 2000 documents in 9.80 seconds.

Вот тестовый код:

from time import time
from uuid import uuid4
from google.cloud import firestore

DB = firestore.Client()

def generate_user_data(entries = 10):
    print('Creating {} documents'.format(entries))
    now = time()
    batch = DB.batch()
    for counter in range(entries):
        # Each transaction or batch of writes can write to a maximum of 500 documents.
        # https://cloud.google.com/firestore/quotas#writes_and_transactions
        if counter % 500 == 0 and counter > 0:
            batch.commit()
            batch = DB.batch()

        user_id = str(uuid4())
        data = {
            "some_data": str(uuid4()),
            "expires_at": int(now)
            }
        user_ref = DB.collection(u'users').document(user_id)
        batch.set(user_ref, data)
    batch.commit()
    print('Wrote {} documents in {:.2f} seconds.'.format(entries, time() - now))

def delete_one_by_one():
    print('Deleting documents one by one')
    now = time()
    docs = DB.collection(u'users').where(u'expires_at', u'<=', int(now)).stream()
    counter = 0
    for doc in docs:
        doc.reference.delete()
        counter = counter + 1
    print('Deleted {} documents in {:.2f} seconds.'.format(counter, time() - now))

def delete_in_batch():
    print('Deleting documents in batch')
    now = time()
    docs = DB.collection(u'users').where(u'expires_at', u'<=', int(now)).stream()
    batch = DB.batch()
    counter = 0
    for doc in docs:
        counter = counter + 1
        if counter % 500 == 0:
            batch.commit()
        batch.delete(doc.reference)
    batch.commit()
    print('Deleted {} documents in {:.2f} seconds.'.format(counter, time() - now))


generate_user_data(10)
delete_one_by_one()
print('###')
generate_user_data(10)
delete_in_batch()
print('###')
generate_user_data(2000)
delete_in_batch()
0 голосов
/ 13 февраля 2020

Вообще говоря, это не очень хороший пример, поскольку вы пишете только один документ. Задержка написания этого единственного документа может составлять 3000 мс, а следующий теоретически может составлять 1 мс. Разработайте тест, который записывает несколько документов и принимает среднее время этих записей. Также имейте в виду, что написание последовательных документов приведет к снижению производительности, если идентификаторы документов являются приличными. Вот почему вы должны выбрать случайный идентификатор документа или ха sh некоторого вида.

import uuid
from google.cloud import firestore_v1

count = 20
data = [{f"test_field_{i}":f"test_value_{i}"} for i in range(count)]

now = time.time()
db = firestore_v1.Client()
coll = db.collection(u'latency_test_collection').

for record in data:
    coll.document(uuid.uuid4().hex).set(record)

print(f"Average time: {(time.time() - now)/count)}")

Но имейте в виду, что при записи большого количества отдельных записей / документов в хранилище вы все еще ограничены по скорости пожарного магазина api. Есть два способа преодолеть это. Первый пишет документы асинхронно. Таким образом, вы можете обрабатывать несколько записей одновременно, но это может быть очень дорого, так как вы платите за каждый вызов API в Firestore. Другой (предпочтительный) способ написания нескольких записей / документов - выполнение пакетных операций, это показано ниже. Имейте в виду, что максимальный размер пакета для записи составляет 500 во время записи.

import uuid
from google.cloud import firestore_v1

count = 20
data = [{f"test_field_{i}":f"test_value_{i}"} for i in range(count)]

now = time.time()
db = firestore_v1.Client()
coll = db.collection(u'latency_test_collection').
batch = db.batch()

for idx, record in enumerate(data):
    doc_ref = coll.document(uuid.uuid4().hex)
    batch.set(doc_ref, record)

    # Max batch size is 500
    if idx % 500 == 0:
        batch.commit()

if idx % 500 != 0
    batch.commit()

print(f"Total time: {(time.time() - now)/count)}")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...