DEV Community

Cover image for Como eu deixei meu banco de dados open-source 4 VEZES mais rápido
Jaedson Silva
Jaedson Silva

Posted on

Como eu deixei meu banco de dados open-source 4 VEZES mais rápido

Sim, eu desenvolvi um banco de dados noSQL em Python chamado CookieDB que armazena seus dados em arquivos criptografados de forma rápida e simples, sem complicações. Mas no início, não era tão rápido assim...

Conhecendo o CookieDB

Eu decidi criar o este banco de dados como forma de aprendizado, além de estar empolgado com a ideia de usar meu próprio banco de dados em outros projetos.

A ideia era armazenar todos os dados em um arquivo JSON, utilizando uma classe em Python com métodos para criar, obter, atualizar e deletar dados. Algo realmente simples. Porém, como forma de segurança, eu adicionei a possibilidade de criptografar o banco de dados usando a biblioteca cryptography. Mas o problema de performance começa ao usar o JSON e a biblioteca cryptography.

Escrita e leitura de um grande volume de dados 😰

Imagine que uma aplicação receba 1 milhão de usuários em um dia, obviamente esses usuários não se registraram de uma vez só, mas cada escrita de um novo usuário no banco de dados demora alguns milissegundos que, somados no final do dia, resultarão em alguns segundos ou minutos, dependendo do desempenho do banco de dados. Se o número de usuários por dia aumentar, o tempo total também aumenta, podendo causar transtornos na aplicação.

Então, escrevi um código que adiciona, obtém e deleta 1 milhão de usuários para testar a performance entre as versões 7.0 e 5.0 do CookieDB. A versão 7.0 possui as otimização feitas para alcançar uma velocidade 4 vezes maior que a versão 5.0, que não possui tais otimizações. Esse é o código:

import random
import secrets
import time

import cookiedb

cookiedb_version = cookiedb.__version__

db = cookiedb.CookieDB(key='ultra-secret-key!')
db.create_database(f'test-{cookiedb_version}', if_not_exists=True)
db.open(f'test-{cookiedb_version}')


def generate_data(users_number: int) -> list:
    names = ['Jaedson', 'Pedro', 'Maria', 'Lucas',
             'Larissa', 'Mateus', 'Edvaldo', 'Luíza']
    password = secrets.token_hex(32)

    users = []

    for __ in range(users_number):
        name = random.choice(names)
        email = name.lower() + '@mail.com'

        users.append({
            'name': name,
            'email': email,
            'password': password
        })

    return users


def test_add_users(users: list) -> None:
    db.add('users/', users)


def test_get_users() -> None:
    db.get('users/')


def test_delete_users() -> None:
    db.delete('users/')


def main() -> None:
    users_test_number = 1000000
    total_time = 0

    print(f'Test CookieDB version {cookiedb_version}')
    print(f'Test with {users_test_number} users data')

    users = generate_data(users_test_number)
    print('Data ready. Testing...\n')

    start = time.time()
    test_add_users(users)
    test_time = time.time() - start
    total_time += test_time

    print(f'Add users in {test_time:.4f}')

    start = time.time()
    test_get_users()
    test_time = time.time() - start
    total_time += test_time

    print(f'Get users in {test_time:.4f}')

    start = time.time()
    test_delete_users()
    test_time = time.time() - start
    total_time += test_time

    print(f'Delete users in {test_time:.4f}')

    print(f'\nTest finished in {total_time:.4f}')


main()
Enter fullscreen mode Exit fullscreen mode

Agora, veja a comparação de performance entre as duas versões do banco de dados CookieDB:

Versão 5.0

Test CookieDB version 5.0.0
Test with 1000000 users data
Data ready. Testing...

Add users in 13.4102
Get users in 9.3546
Delete users in 18.8088

Test finished in 41.5736
Enter fullscreen mode Exit fullscreen mode

Versão 7.0

Test CookieDB version 7.0.0
Test with 1000000 users data
Data ready. Testing...

Add users in 3.0604
Get users in 2.5955
Delete users in 5.1419

Test finished in 10.7977
Enter fullscreen mode Exit fullscreen mode

Observem a diferença: de 40 para apenas 10 segundos para executar três ações com 1 milhão de usuários. Pode parecer pouco, mas se executarmos esse teste com 10 milhões de usuários, a diferença seria de 7 minutos para 1 minuto!

Os problemas que encontrei...

Os problemas que encontrei estão relacionados a biblioteca cryptography e o módulo json, que já vem embutido no Python 3.

Biblioteca cryptography

O resultado da criptografia utilizando a biblioteca cryptography é codificado em base64 para facilitar o transporte do conteúdo criptografado. O que é desnecessário em meu projeto, já que o banco de dados é local.

Obviamente, a codificação em base64 leva tempo, inclusive se o conteúdo a ser codificado for grande.

Para resolver este problema, utilizei a biblioteca pycryptodome, que permite manipular a criptografia de uma forma "pura", onde o resultado da criptografia é retornado em bytes, sem serem codificados em base64. Com isso, criei uma classe em Python para facilitar a criptografia dos dados. Você pode ver o código no arquivo _encrypt.py do projeto CookieDB.

Módulo json

O problema aqui não é o módulo em si, e sim sua velocidade em codificar e decodificar dados JSON. Isso pode ser resolvido utilizando o módulo pickle do Python, onde você pode serializar dicionários, listas, strings, classes e diversos tipos da linguagem Python. Além de dar uma grande melhoria na velocidade, o tamanho do arquivo também diminui muito, já que não é preciso ser lido por humanos, igual o JSON.

Conclusão

Procure otimizar seu projeto ao máximo, há sempre uma forma de deixá-lo mais rápido, seja criando suas próprias soluções ou utilizando soluções já desenvolvidas e testadas.

O projeto CookieDB passa por diversas mudanças constantemente, seja para uma nova funcionalidade, correção de bugs ou melhoria de performance. Meu objetivo é fazer com que ele seja usável em grandes aplicações, e pra isso, é necessário um bom trabalho no desenvolvimento.

Links úteis

Top comments (0)