H2 é um banco de dados de thread único com boa reputação em relação ao desempenho. Outros bancos de dados são multi-thread.
Minha pergunta é: quando um banco de dados multi-thread se torna mais interessante do que um banco de dados de thread único? Quantos usuários? Quantos processos? Qual é o gatilho? Alguém tem experiência para compartilhar?
Resumo
- O gargalo usual é o acesso ao disco
- Os SSDs são rápidos, mas frágeis (o procedimento de falha é obrigatório)
- Uma longa consulta em um único sistema de thread bloqueará todas as outras
- Configurar o sistema multi-threading pode ser complicado
- Bancos de dados multithread são benéficos mesmo em sistemas de núcleo único
Se há uma coisa que posso dizer sobre o MySQL é que o InnoDB, seu mecanismo de armazenamento transacional (compatível com ACID), é de fato multithread. No entanto, é tão multithread quanto VOCÊ CONFIGURA !!! Mesmo "fora da caixa", o InnoDB tem um ótimo desempenho em um único ambiente de CPU, dadas suas configurações padrão. Para aproveitar os recursos de multithreading do InnoDB, você deve se lembrar de ativar muitas opções.
innodb_thread_concurrency define o limite superior do número de threads simultâneos que o InnoDB pode manter abertos. O melhor número de rodada a ser definido para isso é (2 X Número de CPUs) + Número de Discos. ATUALIZAÇÃO : Como aprendi em primeira mão na Percona NYC Conference, você deve definir isso como 0 para alertar o InnoDB Storage Engine para encontrar o melhor número de threads para o ambiente em que está sendo executado.
innodb_concurrency_tickets define o número de threads que podem ignorar a verificação de simultaneidade com impunidade. Depois que esse limite é atingido, a verificação de simultaneidade de thread se torna a norma novamente.
innodb_commit_concurrency configura o número de transações simultâneas que podem ser confirmadas. Como o padrão é 0, não definir isso permite que qualquer número de transações seja confirmado simultaneamente.
innodb_thread_sleep_delay define o número de milissegundos que um thread do InnoDB pode ficar inativo antes de entrar novamente na fila do InnoDB. O padrão é 10.000 (10 seg).
innodb_read_io_threads e innodb_write_io_threads (ambos desde o MySQL 5.1.38) alocam o número especificado de threads para leituras e gravações. O padrão é 4 e o máximo é 64.
innodb_replication_delay impõe atraso de encadeamento em um escravo quando innodb_thread_concurrency é atingido.
innodb_read_ahead_threshold permite leituras lineares do número definido de extensões (64 páginas [página = 16K]) antes de alternar para leitura assíncrona.
O tempo me escaparia se eu nomeasse mais opções. Você pode ler sobre eles na documentação do MySQL .
A maioria das pessoas desconhece esses recursos e está bastante satisfeita com o InnoDB apenas fazendo transações compatíveis com ACID. Se você ajustar qualquer uma dessas opções, você o fará por sua conta e risco.
Eu joguei com MySQL 5.5 Multiple Buffer Pool Instances (162 GB em 9 instâncias de buffer pools) e tentei ter dados auto-particionados na memória dessa maneira. Alguns especialistas dizem que isso deve proporcionar uma melhoria de desempenho de 50%. O que eu consegui foi uma tonelada de bloqueio de thread que realmente fez o InnoDB rastrear. Mudei para 1 buffer (162GB) e tudo ficou bem novamente no mundo. Acho que você precisa de especialistas da Percona à sua disposição para definir isso. Estarei na Percona MySQL Conference em Nova York amanhã e perguntarei sobre isso se houver oportunidade.
Em conclusão, o InnoDB se comporta bem agora em um servidor com várias CPUs, dadas suas configurações padrão para operações multithread. Ajustá-los exige muito cuidado, muita paciência, ótima documentação e ótimo café (ou Red Bull, Jolt, etc.).
Bom dia, boa tarde e boa noite!!!
ATUALIZAÇÃO 2011-05-27 20:11
Voltei da Percona MySQL Conference em Nova York na quinta-feira. Que conferência. Aprendi muito, mas obtive uma resposta que analisarei sobre o InnoDB. Fui informado por Ronald Bradford que definir innodb_thread_concurrency como 0 permitirá que o InnoDB decida o melhor curso de ação internamente com a simultaneidade de thread. Vou experimentar isso ainda mais no MySQL 5.5.
ATUALIZAÇÃO 2011-06-01 11:20
No que diz respeito a uma longa consulta, o InnoDB é compatível com ACID e opera muito bem usando o MultiVersion Concurrency Control . As transações devem ser capazes de transportar níveis de isolamento (leituras repetíveis por padrão) que impeçam o bloqueio de outros acessos aos dados.
Quanto aos sistemas multi-core, o InnoDB percorreu um longo caminho. No passado, o InnoDB não tinha um bom desempenho em um ambiente multicore. Lembro-me de ter que executar várias instâncias do mysql em um único servidor para obter os vários núcleos para distribuir os vários processos do mysqld pelas CPUs. Isso não é mais necessário, graças ao Percona, e mais tarde ao MySQL (eh, Oracle, dizendo que ainda me dá ânsia), pois eles desenvolveram o InnoDB em um mecanismo de armazenamento mais maduro que pode acessar os núcleos com simplicidade sem muito ajuste. A instância atual do InnoDB hoje pode operar bem em um único servidor de núcleo.
Aqui está minha opinião:
Normalmente, o gargalo (ou parte mais lenta) de um sistema de banco de dados é o disco. A CPU só tem picos durante operações aritméticas, processamento ou qualquer outra tarefa que a CPU faz. Com a arquitetura adequada, o multithreading pode ajudar a compensar a carga de uma consulta na CPU em vez de fazer as leituras/gravações lentas do disco. Há casos em que é mais rápido calcular um valor usando os ciclos da CPU em vez de criar uma coluna computada (que foi salva anteriormente no disco) e ler essa coluna do disco.
Em alguns RDBMS existe um banco de dados temporário (tempdb) que é usado por todos os bancos de dados nessa instância para classificação, hash, variáveis temporárias, etc... Multithreading e divisão desses arquivos tempdb podem ser usados para melhorar a taxa de transferência do tempdb , melhorando assim o desempenho geral do servidor.
Usando multithreading (paralelismo), o conjunto de resultados de uma consulta pode ser dividido para ser processado nos diferentes núcleos do servidor, em vez de usar apenas um núcleo. Esse recurso nem sempre melhora o desempenho, mas há casos em que isso ocorre e, portanto, o recurso está disponível.
Os encadeamentos disponíveis para o banco de dados são usados para muitos propósitos: leitura/gravação em disco, conexões de usuário, trabalhos em segundo plano, travamento/latching, E/S de rede, etc. gerenciados usando esperas e filas. Se a CPU puder processar esses threads rapidamente, os tempos de espera serão baixos. Um banco de dados multithread será mais rápido do que um banco de dados de thread único, pois em um banco de dados de thread único haverá a sobrecarga de reciclar apenas um thread em vez de ter outros passos prontamente disponíveis.
A escalabilidade também se torna um problema, pois mais threads serão necessários para gerenciar e executar o sistema de banco de dados dimensionado.
Assim que você tiver vários usuários ou processos simultâneos, ou mesmo um único processo com acesso ao banco de dados multithread, ter um banco de dados que suporte threading se tornará potencialmente interessante.
H2 é thread-safe, mas serializa todas as solicitações para o banco de dados, o que pode se tornar um possível problema de desempenho em um cenário de carga pesada. Se este é realmente o caso de um projeto específico depende de uma combinação de seus requisitos de desempenho, o número de threads/usuários/processos acessando o banco de dados, a frequência de consultas executadas por esses threads e o desempenho médio e de pior caso de seu consultas.
Por exemplo, se seus requisitos de desempenho devem ter uma resposta em um segundo, você não tem mais de 10 usuários simultâneos executando uma única consulta que leva 0,05 segundos para ser executada, um banco de dados de thread único ainda permite atingir esses objetivos (embora multithreaded provavelmente já daria um aumento de desempenho notável). Dado o mesmo cenário com uma única consulta em potencial com um desempenho de meio segundo no pior caso, serializar seu acesso ao banco de dados não permitirá mais que você atinja suas metas de desempenho.
Se você estiver usando H2 em seu projeto, eu o aconselharia a executar um criador de perfil em sua base de código em um cenário de carregamento (basta iniciar um número x de threads atingindo seu código simultaneamente usando alguns casos de uso típicos). Isso fornecerá métricas reais sobre o desempenho e os gargalos em sua base de código, em vez de apenas teorizar. Se isso mostrar que suas solicitações gastam uma grande porcentagem do tempo apenas esperando para acessar o banco de dados, é hora de migrar para um banco de dados encadeado.
Pelo que posso dizer, "single-threaded" é um nome um pouco impróprio para H2. O ponto é que ele serializa todas as transações (ou seja, faz uma de cada vez).
A questão crucial sobre se isso é "ok" ou não para o seu aplicativo não é "Quantos usuários?" ou até mesmo "Quantos processos?", mas "Quanto tempo minhas transações levarão?"
Se todas as suas transações forem de menos de um segundo, isso pode ser bom, se algumas demorarem várias horas para serem concluídas, isso pode não ser bom, pois todas as outras transações pendentes estarão esperando que elas terminem. A decisão sobre se isso é "bom" ou não dependerá de seus próprios requisitos de desempenho - ou seja, quanto tempo é uma espera aceitável para meus usuários acessarem o banco de dados com transações.
--EDITAR
Parece que o H2 realmente não serializa transações - apenas DML. Em outras palavras, muitas atualizações curtas em uma única transação longa não bloquearão outras atualizações . No entanto, a menos que você esteja usando o recurso MVCC experimental , o bloqueio de tabela significa que isso tem um efeito semelhante na prática. Há também um recurso experimental "multi_threaded", mas não pode ser usado ao mesmo tempo que o MVCC
Citando trechos do site PostgreSQL... Por favor, note que eu não tenho absolutamente nenhuma idéia dos méritos desses argumentos -- eles simplesmente não cabem em um comentário.
Da FAQ do desenvolvedor ("Por que os tópicos não são usados ..."):
http://wiki.postgresql.org/wiki/Developer_FAQ#Why_don.27t_you_use_threads.2C_raw_devices.2C_async-I.2FO.2C_.3Cinsert_your_favorite_wizz-bang_feature_here.3E.3F
Da lista de tarefas ("Recursos que não queremos"):
http://wiki.postgresql.org/wiki/Todo#Features_We_Do_Not_Want
Então, novamente... eu não tenho absolutamente nenhuma idéia dos méritos do acima. Era apenas muito longo para caber em um comentário.
Um banco de dados multithread só irá beneficiá-lo quando você tiver mais de 1 consulta paralela indo para o banco de dados. Depende do número de usuários que você tem. Se você tiver mais de dez usuários trabalhando no aplicativo ao mesmo tempo, provavelmente eles produzirão mais de uma consulta no banco de dados ao mesmo tempo.
Além disso, um banco de dados multithread só pode se beneficiar quando há vários núcleos na CPU. Se houver um único núcleo, o banco de dados multiencadeado precisa enfileirar o trabalho e executá-lo sequencialmente no único núcleo. Quando há vários núcleos, cada núcleo pode executar um thread em paralelo. Assim, melhor desempenho.
Isso responde sua pergunta?