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)

Sunday, December 21, 2008

Erlang II

Näo gosto muito de dar exemplos extremamente técnicos, como o artigo abaixo, mas acredito que é necessário mostrar um pouco da tipagem e do "feeling" de Erlang, depois do post anterior.

Erlang Shell:

Parece-nos um pouco de modismo atual, mas todas as linguagens de programação interpretadas tem um shell para testar os comandos, mas o fato é que esta pratica remonta de muitos anos, a exemplo do Erlang Shell:
$ erl
Erlang (BEAM) emulator version 5.6.3 [source] [smp:2] \
[async-threads:0] [kernel-poll:false]

Eshell V5.6.3 (abort with ^G)
1> 27*2.
54
2>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
a
Acima segue um exemplo bem simples de como este shell se parece, também um exemplo de uma operação matemática, veja que os padrões para este tipo de ação é equiparado a todas as outras linguagens, o único exemplo, de destaque de Erlang, é que todas as intruções terminam com um ponto (".").

Módulos e Funçoes:

Vamos começar com um exemplo para nos acostumarmos um pouco com a tipagem de Erlang, devo dizer que a primeira vista ela não é das mais fáceis, porem, ela privilegia a fluidez deste tipo de software, lembre-se de que será necessário um período de adaptação.

Abra um arquivo com nome de "teste.erl" (sim, a extensão é importante), e acrescente o seguinte conteúdo:
-module(teste).
-export([double/1]).
double(X) ->
2 * X.
Feito isso, vamos chama-lo dentro do Erlang Shell, atente que o shell deve ser chamado no mesmo diretório que você criou o arquivo acima:
$ erl
1> c(teste).
{ok,teste}
2> teste:double(27).
54
Após o comando "c(teste)." o interpretador faz a leitura dos fontes e o compila, gerando um executavel em RAM, logo em seguida ele já está pronto para ser utlizado, sabemos disso através do retorno "{ok,teste}".

Toda a declaracao de módulos em Erlang é feita com a instruçao "-module().", atenção ao detalhe de ser iniciado com "-" e sempre finalizado com ".". Neste exmplo o mais importante é a instrução "-export([double/1]).", esta deixa disponível o método "double" o qual espera um parametro, por isso a presença do "/1" na instrução. Sem o "export" o método "double" só estaria disponível dentro do módulo "teste".

Outro retorno dos comandos acima é a criação do "teste.beam", este é o resultado do código Erlang compilado há pouco:

$ file teste.beam
teste.beam: Erlang BEAM file

Bibliografia (Links):

Wikipedia (http://en.wikipedia.org/wiki/Erlang_(programming_language));
Erlang Getting Started (http://www.erlang.org/starting.html);

Tuesday, November 18, 2008

Introdução a Erlang

Introdução:

Erlang é uma linguagem de programação de propósito geral, focada em concorrência e sistemas de tempo real. Esta linguagem foi criada pela Ericsson para suportar sistemas tolerantes a falhas, de tempo-real e ininterruptas. Estes requisitos, na época de sua criação até os nossos dias, é algo muito ousado. Mesmo hoje, temos dificuldades em fazer aplicações com estas características e por este motivo, voltamos um pouco no tempo e queremos reaproveitar conceitos que foram forjados pela prática e obter o melhor resultado possível com as ferramentas atuais.

Concorrência e "Actor Model":

Para concorrência Erlang segue o modelo matemático de atores... Para explicar, vamos criar uma metáfora atribuindo a cada processo determinadas capacidades ou características, neste consenso seria possível para um ator: tomar decisões locais, criar mais atores, enviar mensagens, determinar seu modelo de respostas, entre muitos outros. O "Actor Model" foi concebido em 1973 por Carl Hewitt, Peter Bishp e Richard Steiger. Este modelo foi inspirado por leis da física e influenciou fortemente linguagens de programação, por isso, para realmente entender Erlang, tenha estes conceitos em mente.

Processos e Troca de Mensagens:

A criação e manipulação de processos é algo trivial para Erlang, onde, threads são consideradas de difícil manipulação e inseguras, em muitos sentidos. Para driblar todos estes problemas, intrínsecos de threads, Erlang propõe uma arquitetura formada basicamente por processos (característica também dos SOs unix-like), intercomunicando-se por troca de mensagens ("Message Passing"). Esta é realizada sem usar nenhum tipo de memória ou variáveis compartilhadas, tornando cada processo uma instância independente também seu modelo de comunicação é assíncrono. Cada processo tem algo comparavel a uma fila de mensagens, recebidas de outros processos que ainda não foram devidamente tratados.

Com o uso do "Actor Model" podemos perceber um pouco do que nos é possível usando Erlang: ter uma série de pequenas partes do nosso programa assumindo ações e "tomando" decisões. Podemos abstrair parte deste conceito pensando em uma fábrica, ou linha de produção, na qual, cada colaborador faz uma parte das rotinas e repassa tratamento a diante, podemos também atribuir as figuras dos inspetores e gerentes, com o papel de atentar ao processo como um todo, orientando as melhoras e corrigindo pequenos problemas em tempo de execução.

Escalabilidade:

Outra face incrível de Erlang é a facilidade para fazer uma aplicação horizontalmente escalável, ou seja, podemos dividir os processos de Erlang por vários servidores distintos, e caso seja necessário, adicionar mais um servidor e, simplesmente, dividir a carga entre eles, o único requisito, é ter a Virtual Machine de Erlang instalada. Este modelo vai deixar as partes da nossa aplicação espalhadas, porem, os processos continuam a se comunicar da mesma forma, e com a mesma facilidade, mesmo estando em máquinas separadas. Esta feature reduz drasticamente a complexidade de manutenção.

Links:

http://www.erlang.org
http://www.erlang.org/doc/getting_started/part_frame.html
http://en.wikipedia.org/wiki/Erlang_(programming_language)
http://en.wikipedia.org/wiki/Message_passing
http://en.wikipedia.org/wiki/Real-time_computing

Saturday, October 4, 2008

Why Perl

Há alguns anos atrás eu precisava de uma boa ferramenta para concentrar anti-spam, anti-vírus, e muitas outras funções, dentre as possíveis escolhas eu elegi o Amavisd-new, por ser um projeto maduro e com referencias fortes. E, em um determinado momento eu estava cercado por situações nas quais eu não encontrava saída, mesmo nas listas de discussão e documentação, então, senti-me "obrigado" a ler os fontes. Inicialmente foi uma das piores experiências da minha vida, o software é todo escrito em Perl (claro!) e na época tinha mais de 18 mil linhas de código... Porem, foi também, uma das melhores oportunidades da minha vida profissional! Vou explicar o porque.

Para quem não tem muita experiência com a linguagem, Perl é um tanto quanto complicado, pois tem uma estrutura bastante diferenciadas e utiliza elementos que não são auto-explicativos. Ou seja, sem conhecer a linguagem eu não poderia entender como aquele software trabalha.

Comecei então a procurar um bom artigo ou tutorial sobre introdução e na maioria deles eu era redirecionado às manpages. Na época me parecia estranho aprender uma linguagem de programação através de suas manpages, pois eu nunca havia pensado nisso. No entanto, segui o conselho e comecei: "$ perldoc perl". Devo admitir, tudo o que você precisa, quer ou terá necessidade estão em suas manpages, e todo o conteúdo está mais do que bem explicado, cheio de exemplos e textos adicionais. Sem dúvida, as manpages do Perl são mais do que suficientes.

Perl é uma linguagem extremamente poderosa e madura, criada por Larry Wall em 1987 com o enfoque de ter recursos para processamento de texto, foi principalmente influenciada por C, Shell Script, AWK, Sed e Lisp, hoje, Perl encontra-se na versão 5.10, e está presente em quase todas as plataformas.

Afinal, Porque Perl?
  • Com mais de 20 anos de idade esta linguagem está mais do que consolidada no mercado, hoje é praticamente impossível ver um sistema operacional unix-like sem o seu interpretador, e mais, sem ter dezenas de scripts para as mais variadas funções, escritos em Perl;
  • É o canivete-suíço das linguagens de programação pois, comprovadamente, é flexível e adaptável;
  • Sua sintaxe é inspirada em linguagem C (ANSI), então, é simples, direta e prazerosa de escrever;
  • Reúne as listas de Lisp, os Arrays Associativos do AWK e as Expressões Regulares do Sed, ou seja, o melhor destes mundos com inúmeras outras inovações;
  • Também suporta estrutura de dados complexas, First Class Functions (construção de novas funções em tempo de execução), Closures, Orientação a Objetos, bem como a mistura de vários paradigmas, fica a critério do programador, e muito muito mais;
  • Toda a liberdade ao desenvolvedor, possibilitando escrever instruções complexas em poucas linhas de código (quanto menos linhas de código menos bugs);
  • É rápido e produtivo, pois provê ao programador todas as ferramentas necessárias para colocar os seus anseios em prática;
  • "There is more than one way to do it";
  • CPAN, um repositório com milhares de módulos Perl, largamente utilizados, e conseqüentemente, testados pela comunidade;
  • Liberdade. Não te prende à burocracia, e subentende de que o desenvolvedor tem consciência do que faz e quer liberdade para isso;
Porem é necessário deixar claro que Perl é uma linguagem voltada às soluções e meios para atingir os objetivos, e, não necessariamente voltada a quem vai desenvolver estas soluções, ou seja, ela vai exigir dos programadores conceitos e disciplina, na minha opinião, isso é muito bom nos dias de hoje.

Links: