sábado, 18 de junho de 2011

18 de junho agora é #dornelesday

Hoje é um dia muito especial, pois hoje é dia de homenagear uma grande pessoa: Dorneles Treméa. Pois ele, com seus gestos simples, paciência, perseverança e generosidade, se tornou um exemplo para muitas pessoas, no mundo todo, dentro da comunidade de Software Livre e mais especificamente na comunidade Python e Plone.

Apesar de ter nos deixado tão jovem, o tempo é relativo, por isso, tenho certeza que ele deixou uma marca profunda na vida de todos que conviveram com ele. Seja pela paz e alegria que ele transmitia, sempre de bom humor nas mais difíceis situações, seja pela disposição eu ajudar quem lhe pedia auxílio, seja pela dedicação que tinha pela sua família.

Por isso, para mim e para muitas pessoas, o dia 18 de junho é a partir de hoje #dornelesday, que representa um dia para refletir sobre tudo de bom que nosso colega e amigo trouxe para nós com seu exemplo de vida. Que todo dia possamos nos inspirar com esse exemplo e possamos aprender, um pouco que seja, com este legado.

Na verdade não é fácil seguir seu exemplo, não é fácil ajudar as pessoas como ele ajudava, não é fácil estar sempre de bom humor como ele sempre estava. Mas é por isso que é tão importante essa homenagem, não somente para valorizar o que ele nos trouxe, mas principalmente para conseguir passar esse exemplo adiante, para outras pessoas e assim tornar o mundo em que vivemos um lugar melhor para todos nós.

Viva o Deo (@dorneles)! Viva o #dorndeleday! Que sua luz continue brilhando forte de onde quer que você esteja, como sempre brilhou por aqui! Agradeço imensamente a oportunidade que tive de conviver contigo.

quinta-feira, 27 de agosto de 2009

RelStorage: ZODB usando backend relacional (SGDBs)

Introdução

O ZODB (banco de dados orientado à objetos para aplicalções Python), originalmente criado como um componente do servidor de Aplicação Zope2 (Z Object Publishing Environment), foi desenvolvido com o conceito de "Storage Layer", o qual abstrai o tipo de backend responsável pela persistência dos objetos.

Historicamente, o primeiro Storage Layer desenvolvido para o ZODB foi FileStorage, que tem como objetivo ser simples e robusto, e por isso armazena todos os objetos e transações um único arquivo de forma sequencial. Para acessar os objetos através do seu caminho na hieraquia de objetos do ZODB (ex: obj2 = root['obj1']['obj2'] ), o FileStorage cria um arquivo auxiliar de índice e que deve estar completamente na memória para que o desempenho seja adequado.

Compartilhando o ZODB

Mais tarde, devido a necessidade de compartilhar um mesmo banco de dados por diversas instâncias de uma aplicação (ou diversas aplicações), foi desenvolvido o ZEO (Zope Enterprise Objetcts), que é composto por um servidor RPC que fornece acesso via rede a um ou mais bancos de dados ZODB em FileStorage.

Segue abaixo um de acesso ao ZODB com ZEO e ClientStorage retirado do ZODB Guide:
from ZEO import ClientStorage
from ZODB import DB
import transaction

# modificar essa linha de acordo com a configuração do servidor ZEO
addr = 'zeoserver.example.com', 1975
storage = ClientStorage.ClientStorage(addr)
db = DB(storage)
conn = db.open()
root = conn.root()

# vamos armazenar uma lista e um dicionário no objeto raiz
root['lista'] = ['a', 'b', 1.0, 3]
root['dicionario'] = {'a':1, 'b':4}

# o ZODB é um banco ACID e transacional, é preciso fazer o commit
# no caso do ZOPE, esse commit é automático caso exista uma exceção não tratada
transaction.commit()

Dessa forma, cada instância da aplicação cliente acessa o ZEO usando o Storage Layer ClientStorage para se concectar ao banco de dados compartilhado pelo servidor ZEO. Para o tratamento de concorrência, o ZEO / ZODB utiliza um mecanismo "otimista" de controle de conflitos entre transações que acessam os mesmo objetos, se um conflito ocorrer, uma exceção do tipo "ConflictError" é levantada para avisar o problema a aplicação cliente.

O conjunto de ZEO + FileStorage e aplicação cliente (Zope por exemplo) + ClientStorage permite que os mesmos arquivos de dados ZODB no formato FileStorage sejam acessados simultanemente para criação de Clusters, muito usados para aumentar o desempenho de sites de alto tráfego que usam Zope/Plone, por exemplo.

Essa combinação, apesar de ser a única alternativa para "compartilhar" o ZODB por várias instâncias de uma aplicação, possui algumas limitações de escalabilidade e redundância:
  • O ZEO é uma aplicação Python e devido ao GIL (Global Lock Interpreter) ele somente consegue ser escalonado em uma CPU por vez e, por isso, não aproveita melhor os sistemas com vários processadores/núcleos. Essa limitação prejudica a escalabilidade do backend e pode ser percebida quando muitas instâncias da aplicação precisam acessar ou gravar dados ao mesmo tempo.

  • A Zope Corp possui um componente proprietário, o Zope Replication Services, que é vendido separadamente para replicação de bases de dados ZODB + FileStorage, possibilitando replicar em tempo real o servidor ZEO, conseguindo então uma solução de alta disponibilidade, porém o custo é alto e proibitivo para a maioria das organizações e situações de uso do ZODB.

  • Quanto mais objetos no ZODB, maior o arquivo de índice do FileStorage e, em alguns casos de grandes bases de dados, a inicialização pode ser bem demorada, principalmente se for necessário recriar esse índice.
Surge o RelStorage

Foi com objetivo de atacar essas deficiências e seguindo a idéia do BerkeleyStorage, que foi desenvolvido RelStorage (inicialmente chamado de PGStorage) o qual suporta o aramazenamento dos objetos opacos do ZODB (no formato de byte-code python), em bases de dados relacionais.

Isso significa que esses objetos não podem ser consultados diretamente através do banco de dados relacional (ex: realizando consultas para reltórios), mas apenas pelo ZODB (aplicações Python), o qual ao ser configurado com RelStorage, sabe como recuperar e gravar os objetos, de forma transparente, que estão persistidos em um backend relacional e que substitui o ZEO + FileStorage na tarefa de compartilhar o ZODB por diversas instâncias da mesma aplicação ou diversas aplicações.

Atualmente existem "adapters" no RelStorage para armazenar bases de dados ZODB em três diferentes backends relacionais: MySQL, PostgreSQL e Oracle. Novas servidores de banco de dados podem ser integrados atrvés da implementação de um novo adapter.

Segue um exemplo simples para configuração de um banco de dados ZODB com RelStorage e usando o PostgreSQLAdapter, lembrando que é preciso primeiro criar o banco de dados no PostgreSQL e o RelStorage inicializa as tabelas no primeiro acesso:


import transaction
from ZODB.DB import DB

from relstorage.relstorage import RelStorage
from relstorage.adapters.postgresql import PostgreSQLAdapter

# alterar a configuração de acordo com o banco de dados no PostgreSQL
dsn = "dbname='ruda' user='ruda' host='localhost' password='12345'"

adapter = PostgreSQLAdapter(dsn)
storage = RelStorage(adapter)
db = DB(storage)
conn = db.open()
root = conn.root()
# vamos armazenar uma lista e um dicionário no objeto raiz
root['lista'] = ['a', 'b', 1.0, 3]
root['dicionario'] = {'a':1, 'b':4}
transaction.commit()

Desempenho e Alta Disponibilidade

Os testes realizados por Shane Hataway (criados do RelStorage) indicam que o RelStorage possui um desempenho superiror ao ZEO tanto na leitura quanto na gravação, e que esse ganho aumenta quanto maior concorrência de acesso ao ZODB. É importante notar que é possível fazer um tunning no ZEO que melhora seu desempenho, porém o problema de escalabilidade decorrente do GIL, tente a tornar o ZEO mais lento em ambientes de alta concorrêcia, como por exemplo sites Zope/Plone que possuem muitas instâncias Zope.

Além disso, devido ao uso de bases de dados relacionais, as bases de dados ZODB armazenadas com RelStorage podem ser replicadas usando as ferramentas disponíveis em cada SGDB. Por esse motivo, o RelStorage passa a ser uma alternativa interessante para criação de ambientes de alta disponibilidade que usam o ZODB, novamente, grandes portais Zope/Plone são um público em potecial.

Estabilidade, Migração e Integração

O RelStorage pode ser considerado estável e já está sendo usado em produção por diversos sites, incluindo um grande portal Zope/Plone que usa RelStorage com Oracle e foi um dos patrocinadores da implementação desse novo Storage para ZODB.

Além disso, RelStorage possui uma excelente cobertura de testes e inclui em sua distribuição uma ferramenta (zodbconvert.py) para migração de bases de dado do formato FileStorage para RelStorage (MySQLAtapter, PostgresSQLAdapter e OracleAdapter) e vice-versa.

As opções do arquivo de configuração para migração usando zodbconvert.py são semlhantes as opções usadas na configuração de cada adapter do RelStorage (cada um possui opções distintas). No caso do PostgreSQL a configuração (migration.conf) seria:

<filestorage>
path /tmp/Data.fs
</filestorage>

<relstorage>
<postgresql>
dsn dbname='ruda' user='ruda' host='localhost' password='12345'
</postgresql>
</relstorage>


Para realizar a migração, em um ambiente Zope/Plone configurado via Buildout, basta executar os seguintes comandos no shell, assumindo a versão 1.2.0b2 do RelStorage:

$ cd meu_diretorio_buildout
$ ./bin/zopepy ./eggs/RelStorage-1.2.0b2-py2.4.egg/relstorage/zodbconvert.py /tmp/migration.conf
Finalmente, já existe suporte no pacote plone.recipe.zope2instance para que o RelStorage seja configurado com Buildout para automatização do deploy de aplicações Zope/Plone. Porém, para uso com Plone 2.5 (Zope 2.9) e Plone 3.x (Zope 2.10), é necessário incluir o repositório com versões modificadas do ZODB 3.7 e 3.8 para suportar o RelStorage. Já no Plone 4.x (Zope 2.12) que virá com o ZODB 3.9, não será preciso usar a versão com patch pois o mesmo já foi aplicado no repositório oficial da nova versão do ZODB.

Conclusão

Com RelStorage podemos criar ambientes que necessitam de maior desempenho e disponibildiade do ZODB, substituindo o ZEO e consequentemente algumas de suas limitações. Grandes portais desenvolvidos em Plone podem aproveitar esses recursos, principalmente em ambientes nos quais são usados clusters Zope e que tem o requisito de maior alto desempenho e redundância.

Embora ainda não exista informações divulgadas sobre sites que usam o RelStorage, incluindo detalhes sobre ganhos de desempenho e escalabilddade que demostrem claramente as vantagens da sua adoção, dependendo do ambiente a possibilidade de replicação on-line já seria um motivo suficiente para justificar a migração para o RelStorage.

domingo, 16 de agosto de 2009

Python Brasil [5]! Sigam /pythonbrasil no Twitter

Essa é rapidinha, mas tem mais de 140 caracteres! :-)

Para melhor divulgar as informações a respeito da Conferência Python Brasil [5], tanto sobre os preparativos, bem como as dicas, avisos e acontecimentos durante o evento, foi criada a conta @pythonbrasil no Twitter específica para isso!

Então.. sigam @pythonbrasil e nos vemos em Caxias do Sul!

domingo, 12 de abril de 2009

Como explodir seu buildout com Plone 2.5 e Five 1.4?

Já faz algum tempo que a melhor forma de realizar deploy de projetos Plone passou a ser a utilização da ferramenta zc.buildout, também chamada apenas de buildout. É realmente incrível como ela facilita a tarefa de criar ambientes tanto para produção como desenvolvimento de forma simples, rápida e fácil, mesmo nos mais complexos cenários.

Tudo isso graças a sua arquitetura, a qual permite a utilização de diferentes receitas (recipes), desde que elas sejam publicadas como um pacote Python no PyPi, e assim podem ser reutilizadas por qualquer um que necessite da mesma funcionalidade. Na verdade, o buildout pode (e deve) ser usado por quaisquer projetos, não se limitando apenas ao Zope e seus compatriotas como o Plone e Grok, e já vem sendo usado em projetos Django também.

Porém, existem vantagens e desvantagens de se utilizar o buildout para o deploy de projetos de software. Na minha opinião, as vantagens são muito maiores que as desvantagens. A principal vantagem é a capacidade de se criar ambientes de forma controlada, facéis de serem reproduzidos e estáveis (a depender da configuração usada). E a principal desvantagem é a dependência da ferramenta (buildout) sem ter conhecimento de como o deploy do ambiente funciona a ponto de poder identificar e reparar as falhas e problemas que ocorrem quando algum conflito, atualização de pacote ou incompatibilidade interferem no seu funcionamento.

De fato, existem armadilhas que podem ocorrer e acredito que muitos usuários do buildout já devem ter odiado ele quando as coisas começam a dar errado e não se sabe por que. Ontem mesmo que recebi um email de um amigo, relatando um problema com o buildout, e por incrível coincidência, ele já havia ocorrido comigo, por isso, eu já tinha a solução.

Foi então que percebi que era hora de compartilhar o problema e a solução a fim de ajudar qualquer um que venha a se deparar com essa situação no futuro. O cenário é o seguinte: instalação do Plone 2.5 (e Zope 2.9) com buildout, porém utilizando o Five 1.4 ao invés do Five 1.3 que vem originalmente com o Zope 2.9.

A armadilha é a seguinte: quando modificamos a versão do Five, não estamos fazendo nada de errado, pois a versão 1.4 foi feita para ser compatível com o Zope 2.9. Esse é também um pré requisito para diversos pacotes adicionais do Plone que necessitam de funcionlidades da ZCA e do Framework Zope 3 que não são suportados pela versão 1.3 do Five.

Porém, a receita de instalação do Zope para o Plone 2.5 (plone.recipe.zope2instance), não está preparada para essa situação e o sintoma do problema apenas aparece na tentativa de iniciar ou reiniciar a instância, gerando uma falha na localização de algumas diretivas ZCML, como por exemplo:

ConfigurationError: ('Unknown directive', u'http://namespaces.zope.org/genericsetup', u'registerProfile')

De fato, quando um erro como esse ocorre, fica difícil identificar qual é a real causa. Nesse momento é que odiamos o buildout com todas as forças. Mas não se desespere, existe luz no fim do tunel! Ao investigar a situação a fundo descobri uma forma simples, fácil e indolor de evitar quaisquer surpresas em ambientes Plone 2.5 com Five 1.4, apenas adicionando as seguintes linhas ao seu arquivo buildout.cfg:

[commands]
recipe = plone.recipe.command
command =

cp ${productdistros:location}/Five/skel/site.zcml ${instance:location}/etc


Não se esqueça também de incluir a seção "commands" depois de "instance" na seção principal do buildout.cfg.
Essa configuração assume que você esteja instalando o Five 1.4 em [productdistros] usando seu link para download e instalação automática.

Como pode ser observado pelo trecho acima, estamos usando a receita plone.recipe.command que nos permite executar qualquer tipo de comando shell para copiar a versão correta (que vem com o Five 1.4) do arquivo site.zcml para o diretório etc da instância Zope. A depender da configuração das suas instâncias, pode ser necessário ajustar o comando, assim como, se você já possui uma versão especial de configuração do arquivo site.zcml, o comando também deve ficar diferente.

Espero que essa dica ajude outras pessoas a conhecer o buildout e a resolver e evitar esse tipo de problemas em ambientes com o Plone 2.5 e Five 1.4, e de quebra, serva como um exemplo de utilização da receita plone.recipe.command.

quarta-feira, 30 de janeiro de 2008

Social Network Research and Plone

I will have the next 6 months to develop a framework to help fast delivery of Social Network Services - SNS, it's the implementation task of my final work graduate research and has the title: Social Network Services: component based framework. And, because I have been using Plone in some projects to deliver Content Management Applications, like: company and community web sites, intranets, etc, in the last three years (ruda_porto IRC nick), I decide to use it as a base system to construct a SNS application framework.

Of course that is not a simple task, since Social Networks Services Applications can be used for friendship, academic, professional or some kind of specialized networks, but the central point will be study the hole application domain (problem scope) and implement a framework (solution scope) to abstract social network core objects and features in a way it will be easy to extend and integrate with Plone content management core products and other third-part products for things like members, tagging, blog, wiki, audio, video, photos, files and so on.

The main focus and effort will be in walk forward to make Plone a social oriented application out-of-box installing a core set of packages, thus offering the creation of social networks that share information and content among social actors with Plone. And perhaps implementing a framework that fits academic and Plone community needs at same time is a risk and a great opportunity at same time, using small components help to isolate the general problem in a set of core packages will be a foundation to create Plone social network sites and applications.

The next step forward in my research is the creation of two questions list, one for end users of SNS sites and other Plone developers and users. The first must help to discover what users like and dislike in some existent SNS sites and so grasp functional requirements. The second is more difficult, but it intent is try to discover functional and non-functional requirements that can made the framework easy to extend and deliver SNS applications when integrated with Plone.

I'm was waiting an opportunity make all that information public available in the Plone community and after the post from Alexander Limi: 18 Things I Wish Were True About Plone, talking about social network path for Plone, I decide to make it and try to explain the scope of my research and my vision about Plone social integration and begin a discussion of how it (and other existent projects) can improve Plone social experience.

Thanks for all folks that spend time contributing to Plone and who are responsible to made this amazing community! I will appreciate all commenting! :-)

domingo, 7 de outubro de 2007

Manipulando arquivos grandes em Python

Marcelo Toledo escreveu um artigo comparando a sua implmentação em C de um corretor ortográfico poposto por Peter Norgiv com a versão original em Python.

Porém Marcelo Toledo ao realizar essa comparação não levou em consideração que o exemplo desenvolvido por Peter Norvig era apensa um protótipo. Sendo assim, ele resolveu comparar ambos os programas, em C e Python, utilizando arquivos cada vez maiores e ilustrando a diferença de performance entre eles.

No código de Peter Norvig ele lê o arquivo de uma vez. Dá para imaginar o que acontenceu, baixa performance e "crash" com arquivos maiores de 100M devido a falta de RAM. :-(
Essa é a linha na qual o programa de Peter Norvig lê o arquivo e processa ele:
NWORDS = train(words(file('big.txt').read()))
Infelizmente Marcelo Toledo não procurou saber qual era o "bug" do código, deixando no ar uma idéia de que C é robusto é Python é uma linguagem não confiável.

Como eu fui questionado por um colega (Robson Peixoto) sobre o "porque" do problema com o código do corretor ortográfico. Resolvi então escrever um pequeno script que copia arquivos binários da forma correta. E assim fica claro que Python não tem problemas em manipular arquivos maiores que 100MB. ;-)

Segue um teste de uso do script copyfile.py

ruda@zion /tmp $ du -sh livecd-i686-installer-2007.0.iso
416M livecd-i686-installer-2007.0.iso

ruda@zion /tmp $ time ./copyfile.py livecd-i686-installer-2007.0
.iso teste.iso

real 0m39.708s
user 0m4.517s
sys 0m3.747s

Ou seja, sem usar muita CPU e nem mesmo RAM, esse script demorou 40
segundos para copiar um arquivo de 416MB, ou seja, 10MB/s aproximadamente.

Abaixo o código do script copyfile.py

#!/bin/env python
# -*- coding: utf-8 -*-
import sys

try:
origem = sys.argv[1]
destino = sys.argv[2]
except IndexError:
print "Modo de usar: copyfile.py origem destino"
sys.exit(1)

#Exemplo de leitura e gravação de arquivos grandes - usando modo binário
input = file(origem, 'rb')
output = file(destino, "wb")
for line in input:
output.write(line)

#Fechando os arquivos
input.close()
output.close()

sábado, 15 de setembro de 2007

Grupo de Usuários Python - Bahia

Atenção,

Eu convido todos os baianos de sangue ou de coração (como eu) e que
adoram Python a participar da criação do Grupo de Usuários Python -
Bahia.

Essa iniciativa faz parte de um conjunto de ações importantes que a
Associação Python Brasil vem coordenando para a divulgação de Python
em todo o território nacional. E visa criar e fortalecer comunidades
as regionais.

Eu tomei a iniciativa de criar uma lista de discussão para o Grupo de
Usuários Python - Bahia e convido todos os interessados a ingressar
através do endereço:

http://groups.google.com/group/grupy-ba

A idéia é se organizar para um primeiro encontro no começo de outubro.
Porém também estamos tentando inserir algo sobre Python na programação
do II ENSL que vai ser em Aracaju, e se tivermos vários membros da
comunidade presentes, já seria um ótimo momento para isso. ;-)