Sunday, September 13, 2009

Migração de Blog (http://blog.emresumo.com)

Estou me dedicando ao novo blog (http://blog.emresumo.com), e este aqui, que já tinha uma frequência baixa, vai ficar realmente parado. Por favor, quem acessa este blog, veja o novo layout, com novo servidor e com mais pessoas para trazer um bom conteúdo para todos nós.

Monday, April 13, 2009

NDB Cluster: não existe milagre


Há algum tempo atrás eu estava comentando sobre o NDB Cluster no Twitter e o meu amigo @leandrod (referência em PostreSQL no Brasil) comentou que a persistência em disco do MySQL NDB Cluter é ruim. Eu discordo deste ponto de vista, acredito que ela é exatamente o que precisa ser para suprir a solução proposta. Claro que sim, tudo em tecnologia pode ser melhorado, mas do que jeito que este cluster se encontra, já pode ser utilizado em produção tranqüilamente (desde que, a sua necessidade se encaixe com o perfil de banco de dados MySQL, e com o NDB Cluster -- acho que não era necessário citar isso).

Na versão 5.0 e ancessores, a persistência do banco de dados era totalmente feita em RAM, indicando que este tipo de cluster não era confiável para dados importantes, poderia ser utilizado algo como um cache, talvez. Porem, a partir da versão 6.x isso mudou, além de todo o seu banco de dados (sim todo ele) ficar sempre disponível na RAM, ele também ganha persistência em disco.

Vamos raciocinar um pouco. Se todo o meu DB ficar disponível em RAM, quer dizer, que os meu servidores de NDB Cluster precisam ter memória o suficente para alocar tudo isso, porem, atente que não é cada servidor precisa de 10G (se o meu DB tem este tamanho). A RAM de cada servidor pode ser determinada por esta formula simples:

( ( Tamanho do DB × Número de Réplicas × 1.3 ) / Nós do cluster )

Então, vamos aos calculos (exemplo):

Tamanho da minha base de dados: 10G
Número de réplicas: 1
Quantidade de nós (nodes): 6

Portanto:

( 10 x 1 x 1.3 ) / 6 == 2.16G RAM

Agora já sabemos que o nossos servidores não vão consumir um absurdo de RAM, apenas o necessário.

Persistência em disco:

O NDB Cluster divide as requisições através dos seus nodes, onde cada um deles replica informações para os outros utilizando o daemon "ndbd". Cada um destes nós faz persistência em disco local periodicamente e, principalmente, quando o servidor estiver "idle", ou seja, sempre haverá disponibilidade para processar as chamadas da sua aplicação. O fato de fazer a persistência enquanto "idle" não indica falta de segurança neste processo, pelo contrário, o "ndbd" é capaz de detectar que um dos nós do cluster não está mais diponsível (através do controlador deste cluster e do processo de replicação) e assim ele forçar uma persistência regular (constante) dos dados.
Cálculos apontam que o NDB Cluster pode ficar até sem 40% de suas máquinas, mantendo a confiabilidade perfeita dos dados (mas este cálculo fica para um próximo post).

Bibliografia:

http://dev.mysql.com/doc/refman/5.1/en/faqs-mysql-cluster.html#qandaitem-23-10-1-11
http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html


Saturday, April 11, 2009

MySQL NDB Cluster


Introdução:


É uma tecnologia que provê clustering de databases em principalmente memória RAM, e com persistência em disco, sobre ambiente "shared-nothing", esta arquitetura permite que um sistema trabalhe de uma maneira pouco onerosa para o hardware, apenas, com um mínimo de requisitos específicos.

MySQL Cluster é designado para eliminar os pontos únicos de falha. Por esta razão, de cada componente é esperado ter seus próprios elementos básicos (disco, memória, CPUs), ou seja, o uso de mecanismos para compartilhamento de informações como storages, NFSs, SANs, não são recomendados para este tipo de arquitetura.

O cluster consiste em uma série de computadores, cada um rodando um ou mais processos que podem ser um MySQL Server, "data node", um "management server" e possivelmente programas específicos para acesso aos dados do cluster. A relação entre estes componentes pode ser visto na figura abaixo:



Todos estes programas trabalham juntos para formar um MySQL Cluster. Quando os dados são guardados em um storage engine -- motor de armazenamento, se preferir -- NDBCLUSTER, as tabelas estão alocadas nos data nodes. Cada tabela é diretamente acessível de todos os outros servidores neste cluster, se uma aplicação alterar (INSERT, UPDATE, DELETE), todos os outros nós do cluster terão esta alteração imediatamente.

Os dados armazenados nos data nodes são "espelhados" pelos outros nodes; o cluster pode gerenciar falhas dos seus servidores sem impacto sobre a consistência dos dados, este é apenas sensível (depende também do seu setup) ao desempenho do cluster. Outro ponto que pode haver problemas são nas transações, pois, o node que falhou poderia estar gerenciando uma delas, porem, este não deve ser um ponto de extrama preocupação, porque a sua aplicação deverá tratar este tipo de situação adversa.

Casos de uso:

Esta solução não é simplesmente a melhor a ser aplicada para todos os casos. Temos que lembrar que a replicação no MySQL é algo muito simples e resolve quase muitos casos onde escalabilidade é a temática central. Veja onde o NDB Cluster é recomendado:
  • Aplicações que terão crescimento horizontal, tanto para leitura como para escrita;
  • Arquiteturas onde o tempo de downtime é crucial no servidor de escrita, ou seja, você não tem tempo para eleger um SLAVE como um novo MASTER, se uma "tragédia" acontecer;

Onde ele não é recomendado:

Sistemas onde o uso de chave estrageira não pode ser suprimido pela aplicação. Podemos imaginar que você usa um software de código-fonte fechado e não pode, simplesmente, implementar este recurso;

Devo lembrar também que subir uma estrutura com estas características não é algo trivial, existem muitos pequenos detalhes a considerar. Se para o seu caso isso é um problema, repense a idéia da replicação, apesar de simples, ela é muito flexível, existem "N" maneiras de replicar um banco de dados MySQL sem perder desempenho e com um tempo de resposta muito baixo.

Considerações a respeito de tecnologia:

MySQL é um banco de dados confiável e robusto, porem, quando nós queremos que ele seja solução para um ambiente de grande porte, nem sempre é simples cumprir esta tarefa, assim como não seria ao fazê-lo com um de seus concorrentes (Oracle, PostreSQL, etc).

Na sua concepção, ele foi criado para ser um banco de dados disponível e de manipulação fácil para todos os possíveis usuários, e por este motivo, ele não vem com um belo tuning para high-concurrency, todo este trabalho deve ser feito pelo seu DBA (Sim, senhor! Com o MySQL a figura do DBA é necessária também.).

Para ter uma solução eficiente, você deve considerar todos os fatores envolvidos e escolher a melhor ferramenta para o pior problema, lembrando que não existe bala-de-prata quando falamos de tecnologia.

Bibliografia:

http://forums.mysql.com/read.php?12,100670,100670
http://dev.mysql.com/doc/refman/5.1/en/mysql-cluster-glossary.html

Acho este assunto polêmico? Espero seu comentário.

Sunday, January 4, 2009

"Variáveis" em Erlang

Um outro ponto muito importante para entendermos Erlang é o conceito de variáveis, este é muito diferente do que nós estamos acostumados. Vejam:

As variáveis são estruturas para basicamente, guardarmos um valor e tornar possível que nós o recuperemos depois. Exemplo:
1> X = 272727.
272727
Primeiro nós guardamos um valor em "X" e depois ele nos mostra "272727". Atente que todas as variáveis devem começar com uma letra maiúscula.

Agora, vamos recuperar o valor inserido:
2> X.
272727
Portanto, "X" contem um valor e nós podemos fazer uso:
3> X*X*X.
19683
Os exemplos acima são simples, porem expressam perfeitamente que em Erlang as variáveis tem um conceito análogo ao da Matemática, quando você associa um valor com uma variável, está fazendo uma "afirmação de um fato": esta variável tem este valor (ponto).

No entanto, se você tentar inserir um novo valor para a nossa velha variável "X", terá um erro brutal, como este:
4> X = 1234.
=ERROR REPORT==== 11-Sep-2006::20:32:49 ===
Error in process <0.31.0> with exit value:
{{badmatch,1234},[{erl_eval,expr,3}]}
** exited: {{badmatch,1234},[{erl_eval,expr,3}]} **
Para explicar é necessário fazer duas colocações importantes a respeito de "X = 1234.":
  • Primeiro, "X" não é uma variável, ao menos não como nós a encontraríamos em outras linguagens de programação;
  • Segundo, "=" não é um operador de atribuição;
Esta é provavelmente uma das áreas mais difíceis de entender, para quem é novo em Erlang (eu também sou).

Variáveis não são variáveis:

Em Erlang variáveis tem uma única atribuição, e assim como este conceito sugere, um valor só pode ser alterado uma única vez! Se você tentar mudar este valor, você receberá um erro fatal (como mostrado pouco acima). A variável que teve seu valor alterado é chamada "bound-variable" (pode ser traduzido como "variável-vinculada"). Todas as variáveis começam como "unbound" (desvinculadas), até que uma chamada como "X = 1234." atribui um valor ao elemento "X". Note que antes de ter um vínculo estabelecido, "X" poderia ter qualquer valor, porem, depois disso, ela terá o mesmo valor para sempre (até o final da execução).

A este ponto você deve estar pensando o porque chamar este elemento de "variável", e dá-se por dois motivos:
  • Eles são variáveis, porem, só pode ter seu valor alterado uma única vez;
  • Eles se parecem com variáveis em outras linguagens convencionais de programação, então é normal que uma linha de código com o padrão "X = ..." seja familiar ao conceito;
Na verdade, "=" é um operador para "pattern-matching" (correspondência de padrão), o qual comporta-se como um operador de atribuição quando "X" está "unbound" (desvinculado), ou seja, apenas uma única vez durante a vida de uma variável.

Finalmente, o escopo de uma variável é a unidade léxica no qual ela foi definida. Se "X" é utilizado em um bloco de uma função, então, este não será válido fora deste bloco. Em Erlang não existem variáveis de contexto global ou privado, nem mesmo será reutilizada em diferentes blocos de uma função. Se "X" ocorrer em diferentes funções, então serão variáveis diferentes, porem com um mesmo nome, e, provavelmente, com valores diferentes atribuídos em cada escopo.

Bibliografia:

Programming Erlang (Joe Armstrong)