Kirbi: arquitetura do coletor de metadados

0 views
Skip to first unread message

Luciano Ramalho

unread,
Aug 5, 2007, 11:46:31 AM8/5/07
to grok-br
Pessoal,

O Kirbi precisa buscar dados sobre livros em catálogos remotos como
Amazon, Tempo Real, Submarino etc. Gostaria de ouvir suas opiniões
sobre as alternativas que estou considerando, e se estou viajando
demais...

Ano passado eu implementei isso em PHP com MySQL de um jeito bem
simples e funcionou legal. Ficou assim:

MODELO A

1- um usuário cadastra no Kirbi um livro fornecendo apenas o ISBN
2- a cada 5 segundos, o cron aciona um script coletor externo que
pergunta ao MySQL se existem livros com ISBN porém sem título
3- para cara ISBN retornado na consulta acima, o script coletor faz
uma requisição a um catálogo remoto, mastiga o XML ou HTML retornado e
faz um POST no Kirbi passando os dados mastigados em forma de
dicionário.

Essa arquitetura tem a vantagem de ser assíncrona e pouco acoplada. Se
o catálogo externo não está disponível, a performance do Kirbi não é
afetada porque o Kirbi nunca fica esperando pela resposta que vem de
fora. O pior que acontece é ir aumentando o backlog de registros sem
título para serem buscados depois.

Este ano, refazendo o esquema em Python, me deu vontade de fazer algo
usando o Twisted. Em vez de um simples script acionado pelo cron,
fiquei com vontade de usar um daemon escrito em Twisted, porque
ficaria muito mais xique (perigo!). O daemon chama-se Kirbifetch.

Inicialmente eu pensei (e comecei a implementar) o seguinte esquema:

MODELO B

1- um usuário cadastra no Kirbi um livro fornecendo apenas o ISBN; um
evento no container de livros verifica se o livro tem ISBN mas não tem
título e coloca o ISBN numa lista de pendentes
2- a cada segundo, Kirbifetch acessa o Kirbi via XML-RPC e pega a
lista de ISBNs pendentes; o Kirbi deleta de sua lista de pendentes
cada ISBN fornecido ao Kirbifetch.
3- para cara ISBN retornado na consulta acima, o Kirbifetch faz uma
requisição a um catálogo remoto, mastiga o XML ou HTML retornado e faz
chama, via XML-RPC, outro método no Kirbi passando os dados mastigados
em forma de dicionário.

Depois de trabalhar na implementação do esquema acima, o passo 2
começou a me incomodar, por alguns motivos: a) parece um desperdício o
Kirbifetch ficar cutucando o Kirbi a cada segundo; b) este pooling
aumenta a latência do sistema de coleta como um todo; c) o
acomplamento entre o Kirbi e o Kirbifetch ficou um pouco maior do que
eu gostaria.

O contato com o Twisted me fez pensar numa outra arquitetura:

MODELO C

1- um usuário cadastra no Kirbi um livro fornecendo apenas o ISBN; um
evento no container de livros verifica se o livro tem ISBN mas não tem
título, coloca o ISBN numa lista de pendentes e invoca via XML-RPC um
método "fetch" no Kirbifetch passando esta lista;
2- o método "fetch" devolve imediatamente uma resposta 'OK'; ao
recebê-la o Kirbi deleta os pendentes de sua lista.
3- para cara ISBN recebido na chamada a "fetch", o Kirbifetch faz uma
requisição a um catálogo remoto, mastiga o XML ou HTML retornado e faz
chama, via XML-RPC, outro método no Kirbi passando os dados mastigados
em forma de dicionário.

Vantagens do modelo C sobre o B:
a) o Kirbifetch só é acionado quando necessário;
b) a latência é menor, porque o Kirbifetch é notificado de cada
pendência imediatamente;
c) o acomplamento pode ser menor: o método "fetch" pode receber dois
parámetros: a lista de ISBNs e a URL do método XML-RPC a ser invocado
para devolver os resultados (isto imita o esquema de callbacks do
Twisted); desta maneira, o Kirbifetch não precisa saber nada sobre o
Kirbi, e pode prestar seus serviços de coleta para qualquer aplicação
que implmente XML-RPC

Desvantagem:
No passo 1, se o Kirbifetch estiver parado ou muito lento, uma das
preciosas threads do Kirbi vai ficar esperando uma resposta. Nos
modelos A e B isso nunca acontece.

Aos heróis que sobreviveram até aqui, a pergunta: o que vocês acham
destes esquemas?

[ ]s
Luciano

PS. Não foram adequadamente tratadas as exceções na implementação do
ano passado. Por exemplo, quando determinado ISBN não era encontrado
no catálogo remoto, ele recebia um status de falha num campo do MySQL,
e ficava lá esquecido para sempre. Este ano, meu plano é que em caso
de erro o Kirbifetch vai chamar outro método do Kirbi para informar os
ISBNs que não foram encontrados. O que o Kirbi vai fazer com esta
informação, ainda não decidi.

Luciano Ramalho

unread,
Aug 5, 2007, 11:49:23 AM8/5/07
to grok-br
> b) este pooling aumenta a latência do sistema de coleta
> como um todo;

/pooling/polling/

[ ]s
Luciano

Leonardo Rochael Almeida

unread,
Aug 5, 2007, 5:44:48 PM8/5/07
to gro...@googlegroups.com
Eu não gosto muito do modelo C. Pior do que uma thread preciosa de
trabalho ficar presa esperando o kirbifetch é o a requisição do
browser ficar esperando isso.

Porém a idéia do Zope fazer a requisição para o kirbifetch não é de
todo ruim, especialmente se puder ser feita de maneira assincrona.
Existe um pacote para zope3 que implementa requisições assincronas,
"scheduler":

http://svn.zope.org/scheduler/trunk/src/scheduler/

Esse pacote implementa 3 tipos de task. Uma que, quando executada,
calcula a próxima vez que deve ser executada, uma que é executada a
intervalos fixos (loop) e uma que é executada a intervalos calculados
por uma especificação semelhante a do cron. Se entendi corretamente,
cada task que vai ser executada é uma utility implementando uma
determinada interface. O pacote faz o lookup de todas as utilities
implementando essa interface e as executa no tempo correto.

Sugiro fazer a notificação do kirbifetch via uma task dessas ou ainda
implementar o kirbifetch inteiro como uma tal task (embora acho que
prefiro a primeira opção, para reduzir a quantidade de tempo que uma
thread fica com a conexão do ZODB aberta enquanto espera a resposta de
servidores longínquos).

Luciano Ramalho

unread,
Aug 5, 2007, 8:16:56 PM8/5/07
to gro...@googlegroups.com
On 8/5/07, Leonardo Rochael Almeida <leoro...@gmail.com> wrote:
> Eu não gosto muito do modelo C. Pior do que uma thread preciosa de
> trabalho ficar presa esperando o kirbifetch é o a requisição do
> browser ficar esperando isso.

Só.

> Porém a idéia do Zope fazer a requisição para o kirbifetch não é de
> todo ruim, especialmente se puder ser feita de maneira assincrona.
> Existe um pacote para zope3 que implementa requisições assincronas,
> "scheduler":
>
> http://svn.zope.org/scheduler/trunk/src/scheduler/
>
> Esse pacote implementa 3 tipos de task. Uma que, quando executada,
> calcula a próxima vez que deve ser executada, uma que é executada a
> intervalos fixos (loop) e uma que é executada a intervalos calculados
> por uma especificação semelhante a do cron. Se entendi corretamente,
> cada task que vai ser executada é uma utility implementando uma
> determinada interface. O pacote faz o lookup de todas as utilities
> implementando essa interface e as executa no tempo correto.
>
> Sugiro fazer a notificação do kirbifetch via uma task dessas ou ainda
> implementar o kirbifetch inteiro como uma tal task (embora acho que
> prefiro a primeira opção, para reduzir a quantidade de tempo que uma
> thread fica com a conexão do ZODB aberta enquanto espera a resposta de
> servidores longínquos).

Valeu a dica, Leo! Vou investigar esse scheduler.

Como você não chegou a achar o modelo C bom, mas apenas não de todo
ruim, eu acho que por enquanto vou ficar com o modelo B que já está
funcionando (quando estiver no SVN do Zope eu aviso). Os modelos A e B
são o velho esquema assíncrono que a gente sempre usou nos nossos
coletores de notícias na Hiperlógica, lembra? É um esquema robusto e
escalável, mas não tão sexy e nem muito ágil na resposta. Porém com o
polling acontecendo a cada 2 ou 3 segundos acho que a carga é pequena
e a demora não chega a incomodar.

Muito grato pela sua análise, Leo!

[ ]s
Luciano

Leonardo Rochael Almeida

unread,
Aug 6, 2007, 11:55:09 AM8/6/07
to gro...@googlegroups.com
Minha idéia, na verdade seria um modelo D:

* Usuário cadastra ISBN sem mais detalhes e ISBN não está no sistema,
este ISBN entra cadastrado como "não pesquisado"

* task baseada no scheduler roda de tempos em tempos pegando todas as
ISBNs que ainda não foram pesquisadas e envia para kirbifetch,
marcando-as como "sob-pesquisa".

* outra task baseada no scheduler consulta kirbifetch de tempos em
tempos e coleta todos os ISBNs retornados, marcando-os como
"pesquisado-ok" ou "pesquisado-falhou", de acordo com o que o
kirbifetch retornar. Nota, o kirbifetch não precisa retornar status
para todos os ISBNs, somente para aqueles que ele terminou a pesquisa,
com sucesso ou não.

- para os pesquisados-ok, essa task atualiza os dados correspondentes.

note que a comunicação com o kirbifetch pode ser feita de várias
maneiras: consultas num SQL, leitura e escrita de arquivos, XML-RPC,
etc... Note também que, no esquema acima, o kirbi inicia todo contato
com o kirbifetch, o que pode ser interessante do ponto de vista de
segurança.

Note também que sempre é possível pegar a lista de ISBN
"pesquisados-falhou" e transformar em "não-pesquisados" para tentar
passá-los pelo sistema novamente.

On 8/5/07, Luciano Ramalho <luc...@ramalho.org> wrote:

> [...]

Dirceu Pereira Tiegs

unread,
Aug 9, 2007, 9:46:13 PM8/9/07
to gro...@googlegroups.com
Em 05/08/2007, às 12:46, Luciano Ramalho escreveu:
> Pessoal,

Oi Luciano,

> O Kirbi precisa buscar dados sobre livros em catálogos remotos como
> Amazon, Tempo Real, Submarino etc.

[corta]

Talvez seja interessante dar uma olhada no módulo lovely.remotetask,
usado pela Lovely Systems no http://www.lovelybooks.de/:

" high jump: make as much asynchronous as possible

As mentioned, we’re getting pretty often data from external sites.
The duration of Amazon queries ranges from several milliseconds to
multiple seconds. Due to the nature of Zope the threads handling
requests are blocked during that time.
The amazonasync module provides a way to do amazon queries
ansynchronous to the zope threads.
There is another problem when doing amazon lookups, if we are doing
to many queries in to short time it is possible that amazon doesn’t
answer queries and locks us completely for some time.

We are using lovely.remotetask to do the amazon lookup. First we try
to put the amazon tasks in one queue and therefore serialize all
queries.
lovely.remotetask would also allow us to forward the queries to any
machine which runs the amazon async service.

1. browser request wants to do an amazon search
2. a job is inserted into the remotetask
3. the browser returns some ajax code to the browser which is
polling for the result

That saved our lives threads once more :) There are now several
places where we’re queueing asynchronous tasks in lovely.remotetask. "

Fonte: http://www.lovelysystems.com/batlogg/2007/03/30/the-decathlon-
of-computer-science/

Abraço,
--
Dirceu Pereira Tiegs - http://dirceu.info/
Weimar Consultoria

Hospedagem Plone, Zope e Python
http://www.pytown.com


Luciano Ramalho

unread,
Aug 9, 2007, 9:58:33 PM8/9/07
to gro...@googlegroups.com
Valeu a dica. Dirceu. Neste exato momento o %$#! servidor de DNS do
Virtua não sabe o onde fica "lovelysystems.com" então não tenho como
ler o post do Jodok.

Por outro lado, o que eu já fiz está funcionando bem para Amazon.com.
O próximo desafio seria usar interfaces para facilitar a criação de
plugins para outras fontes de livros (a Amazon não é a melhor fonte
para livros Brasileiros, Espanhóis etc.). Sobre isso eu mandei uma
mensagem errada (em português) para a lista grok-dev. Vou mandá-la
para cá tb.

Mas na verdade ontem o Martijn me falou para não dedicar mais tempo a
esse assunto da coleta de dados, porque já tenho algo funcionando e
isso não tem nada a ver com Grok na realidade. Portanto essa pesquisa
vai ter que ficar para depois...

De qualquer forma, agradeço bastante o seu interesse em contribuir, Dirceu!

[ ]s
Luciano

Luciano Ramalho

unread,
Aug 9, 2007, 10:28:13 PM8/9/07
to gro...@googlegroups.com
On 8/9/07, Luciano Ramalho <luc...@ramalho.org> wrote:
> Valeu a dica. Dirceu. Neste exato momento o %$#! servidor de DNS do
> Virtua não sabe o onde fica "lovelysystems.com" então não tenho como
> ler o post do Jodok.

Agora consegui ler.

> O próximo desafio seria usar interfaces para facilitar a criação de
> plugins para outras fontes de livros (a Amazon não é a melhor fonte
> para livros Brasileiros, Espanhóis etc.). Sobre isso eu mandei uma
> mensagem errada (em português) para a lista grok-dev. Vou mandá-la
> para cá tb.

Na verdade, eu já tinha mandado para cá: o assunto é "Exemplo de uso
de interfaces fora do Zope".

O Jodok da Lovelysystems me escreveu logo no começo do Summer of Code
propondo trocar figurinhas. Depois sumiu (estou até hoje aguardando
que ele responda uma mensagem que eu mandei para ele).

Na verdade, a Kirbi é muito mais modesto que o LovelyBooks, porque o
Kirbi é para ser uma aplicação-exemplo para quem está aprendendo Grok,
então, por exemplo, eu não quero usar muitos módulos externos ao Grok
e Zope 3. Se eu soubesse do amazonasync antes, talvez tivesse usado
ele, porque como eu disse antes esse tema de coleta de dados na amazon
não tem muito a ver com Grok, mas é uma peça essencial para o Kirbi...

Mas agora o Kirbifetch está funcionando, e com boa performance, então
vou ficar com ele. O que tem para melhorar no Kirbifetch é o lance de
plugar outras fontes de dados, e também a parte de instalação
(buildout) e testes (ainda não vi como automatizar testes de chamadas
asíncronas com a infra de testes do Zope 3).

[ ]s
Luciano

Reply all
Reply to author
Forward
0 new messages