Histórico :
criei um aplicativo Web que gostaria de poder escalar razoavelmente bem. Sei que não sou Google ou Twitter, mas meu aplicativo usa uma quantidade bastante grande de dados para cada usuário e, portanto, possui requisitos de dados bastante altos. Quero estar pronto para escalar razoavelmente bem sem ter que re-arquitetar tudo mais tarde.
Eu me considero um desenvolvedor de software, não um especialista em banco de dados. É por isso que estou postando aqui. Espero que alguém com muito mais experiência em banco de dados possa me dar conselhos.
Com um número relativamente grande de usuários, mas nada como os números do Facebook, espero ter um banco de dados parecido com este:
Uma "mesa grande":
- 250 milhões de registros
- 20 colunas
- Aproximadamente 100 GB de dados
- Possui uma chave estrangeira bigint (20) indexada
- Possui uma coluna varchar indexada (500) string_id
- Possui uma coluna "valor" int (11)
4 outras tabelas:
- 10 milhões de registros cada
- Aproximadamente 2 a 4 GB de dados cada
- cada uma dessas tabelas possui de 4 a 8 colunas
- uma coluna é datetime date_created
- uma coluna é a coluna varchar (500) string_id
- uma ou duas colunas de cada uma dessas tabelas serão selecionadas em uma junção
Uma dessas tabelas é usada para armazenar médias - seu esquema é bigint (20) id, varchar (20) string_id, datetime date_created, float average_value
O que eu quero fazer - duas consultas relativamente caras:
Calcular novos valores médios:
- Usando uma chave estrangeira, selecione até vários milhões de registros separados na tabela grande.
- Calcule uma nova média, agrupando pelo string_id.
- Inserir resultados na tabela de médias.
- Conforme construída atualmente, essa consulta usa duas junções.
Crie registros não normalizados, somente leitura, para atender aos usuários:
- Use uma chave estrangeira para selecionar de 1.000 a 40.000 registros da tabela grande.
- Associe-se a cada uma das outras quatro tabelas no registro mais recente com a coluna de identificação da sequência.
- Insira os resultados em uma tabela não normalizada.
- Esses registros devem ser usados pelo front-end para exibir informações aos usuários.
- Conforme construída atualmente, essa consulta usa quatro junções.
Planejo executar cada uma dessas consultas caras em um banco de dados de back-end em lote que enviará seus resultados para um servidor de banco de dados front-end em tempo real que lida com solicitações de usuários. Essas consultas serão executadas em intervalos regulares. Não decidi com que frequência. A consulta média pode ser feita talvez uma vez por dia. A consulta de desnormalização precisará ser mais frequente - talvez a cada poucos minutos.
Atualmente, cada uma dessas consultas é executada em poucos segundos no MySQL em uma máquina muito simples, com um conjunto de dados com 100 mil registros na "grande tabela". Estou preocupado com minha capacidade de escalar e com os custos de escalar.
Perguntas :
- Essa abordagem parece sólida? Existe algo obviamente errado com isso do ponto de vista geral?
- Um RDBMS é a ferramenta certa ou devo procurar outras soluções de "big data" como algo da família Hadoop? Minha inclinação é usar um RDBMS porque os dados são estruturados e se encaixam perfeitamente no modelo relacional. Em um determinado momento, porém, entendo que eu não consiga mais usar um RDBMS. Isso é verdade? Quando essa troca seria necessária?
- será que vai dar certo? Essas consultas podem ser executadas em um período de tempo razoável? Posso esperar talvez horas pela consulta nº 1, mas a consulta nº 2 deve terminar em minutos.
- O que devo considerar da perspectiva do hardware? Quais são meus gargalos de RAM e CPU? Presumo que manter índices na RAM seja importante. Há mais alguma coisa que eu deva considerar?
- Em algum momento, provavelmente terei que particionar meus dados e usar vários servidores. Meu caso de uso parece que já está nessa categoria ou poderei dimensionar uma única máquina verticalmente por um tempo? Isso funcionará com 10x os dados? 100x?
Respostas:
Você já tentou reunir mais dados e compará-los? 100 mil linhas são irrelevantes. Experimente 250M ou 500M como você espera que seja necessário e veja onde estão os gargalos.
Um RDBMS pode fazer muitas coisas se você prestar muita atenção às limitações e tentar trabalhar com os pontos fortes do sistema. Eles são excepcionalmente bons em algumas coisas e terríveis em outras, então você precisará experimentar para ter certeza de que é o ajuste certo.
Para alguns trabalhos de processamento em lote, você realmente não pode superar arquivos simples, carregando os dados na RAM, destruindo-os usando uma série de loops e variáveis temporárias e eliminando os resultados. O MySQL nunca será capaz de corresponder a esse tipo de velocidade, mas, se ajustado corretamente e usado corretamente, poderá chegar a uma ordem de magnitude.
O que você deseja fazer é investigar como seus dados podem ser particionados. Você tem um grande conjunto de dados com muitos links cruzados para poder dividi-los ou há lugares naturais para particioná-los? Se você puder particioná-lo, não terá uma tabela com uma pilha inteira de linhas, mas potencialmente muitas significativamente menores. Tabelas menores, com índices muito menores, tendem a ter um desempenho melhor.
Da perspectiva do hardware, você precisará testar para ver o desempenho da sua plataforma. Às vezes, a memória é essencial. Outras vezes, é a E / S do disco. Realmente depende do que você está fazendo com os dados. Você precisará prestar muita atenção ao uso da CPU e procurar altos níveis de espera de E / S para saber onde está o problema.
Sempre que possível, divida seus dados em vários sistemas. Você pode usar o MySQL Cluster se estiver corajoso ou simplesmente criar várias instâncias independentes do MySQL, onde cada uma armazena uma parte arbitrária do conjunto completo de dados usando algum esquema de particionamento que faça sentido.
fonte
Tabelas de resumo.
Todos os dias, calcule informações agregadas para os dados do dia. Coloque isso nas tabelas "resumidas". Faça suas consultas contra eles. Facilmente 10 vezes mais rápido.
Para uma discussão mais aprofundada, forneça
Algumas coisas óbvias ...
"Menor -> mais armazenável em cache -> mais rápido
fonte
Para exibir seus dados de front-end, a menos que haja muitas e várias inserções o tempo todo, você realmente não pode superar o uso de gatilhos para inserir em visualizações materializadas que são mantidas em sincronia com o back-end, mas otimizadas para veicular os dados. Obviamente, você precisa manter as junções, etc, etc, no mínimo nesses gatilhos. Uma estratégia que usei é enfileirar essas inserções / atualizações em uma tabela intermediária e enviá-las posteriormente mais ou menos a cada minuto. É muito mais fácil enviar um registro que 4 GB. 4 GB de dados levam muito tempo para serem transmitidos, mesmo que você encontre rapidamente os registros que está procurando.
Eu concordo com o Tadman. O melhor é analisá-lo com o tipo de dados que você espera do tipo de sistema que deseja.
fonte