Upload
phunganh
View
233
Download
0
Embed Size (px)
Citation preview
Распределенная обработка потоковых данных
May Perl, Москва, 16-17 мая 2009 года
Вячеслав Матюхин
Потоки данных
Потоки данных
• Лог в локальной FS
Какими они бывают?
Какими они бывают?Потоки данных
• Лог в локальной FS
• Таблица в БД
Потоки данных
• Лог в локальной FS
• Таблица в БД
• HTTP-поток
Какими они бывают?
Демоны
- синхронность
- init-скрипт, pid-файл, watchdog
- утечки памяти
Потоки данныхКак обрабатывать?
cron
- асинхронность
- простота написания
- надежность
- интеграция с unix-утилитами
VS
Потоки данных
• Веб-сервера
Логи
Потоки данных
• Веб-сервера
• Базы данных
Логи
Потоки данных
• Веб-сервера
• Базы данных
• Скрипты
Логи
Потоки данных
• Веб-сервера
• Базы данных
• Скрипты
• Модули (log4perl)
Логи
ЛогиОсобенности• Надежность
ЛогиОсобенности• Надежность
• Простота чтения
ЛогиОсобенности• Надежность
• Простота чтения
• Ротация!
SchedulerПример
Будем выкачивать rss.Шедулер будет вести лог /var/spool/scheduler.log:
1000 http://dolboeb.livejournal.com/data/rss1017 http://avva.livejournal.com/data/rss1018 http://drugoi.livejournal.com/data/rss...
SchedulerПример
scheduler.pl /var/spool/scheduler.log
Yandex::Unrotate
SynopsisYandex::Unrotate
use Yandex::Unrotate;
my $reader = Yandex::Unrotate->new({LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/robot.pos”,
});while ($reader->readline) {
...}$reader->commit;
SynopsisYandex::Unrotate
use Yandex::Unrotate;
my $reader = Yandex::Unrotate->new({LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/robot.pos”,
});while ($reader->readline) {
...}$reader->commit;
SynopsisYandex::Unrotate
use Yandex::Unrotate;
my $reader = Yandex::Unrotate->new({LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/robot.pos”,
});while ($reader->readline) {
...}$reader->commit;
SynopsisYandex::Unrotate
use Yandex::Unrotate;
my $reader = Yandex::Unrotate->new({LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/robot.pos”,
});while ($reader->readline) {
...}$reader->commit;
SynopsisYandex::Unrotate
use Yandex::Unrotate;
my $reader = Yandex::Unrotate->new({LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/robot.pos”,
});while ($reader->readline) {
...}$reader->commit;
РоботПример
scheduler.pl
/var/spool/scheduler.log
robot.pl
robot.ya.ru
ВозможностиYandex::Unrotate
• CheckInode
ВозможностиYandex::Unrotate
• CheckInode• CheckLastline
ВозможностиYandex::Unrotate
• CheckInode• CheckLastline• ->commit(); ->commit($position);
ВозможностиYandex::Unrotate
• CheckInode• CheckLastline• ->commit(); ->commit($position);• ->lag();
ВозможностиYandex::Unrotate
• CheckInode• CheckLastline• ->commit(); ->commit($position);• ->lag();
Ближайший аналог: File::LogReader
file: /var/spool/scheduler.logposition: 120000inode: 4815162342lastline: 21903 http://tema.livejournal.com/data/rss
Файл состоянияYandex::Unrotate
file: /var/spool/scheduler.logposition: 120000inode: 4815162342lastline: 21903 http://tema.livejournal.com/data/rss
Файл состоянияYandex::Unrotate
$ unrotate -n 10 robot.pos$ unrotate -n 10 --commit robot.pos
А распараллелить?Yandex::Unrotate
$reader = Yandex::Unrotate::Chunk->new(LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/robot.pos”,ChunkDir => “/var/lib/robot/chunks/”,ChunkCount => 5,ChunkSize => 5000,
); # откусить новый chunk или взять свободный существующийwhile ($reader->readline) {
...}$reader->commit; # стереть chunk
Робот с chunk’ами Пример
scheduler.pl /var/spool/scheduler.log
robot.pl
robot.pl
robot.pl
/var/spool/robot/chunks/chunk1
/var/spool/robot/chunks/chunk2
/var/spool/robot/chunks/chunk3
robot.ya.ru
МониторингYandex::Unrotate
• Да здравствует Log::Log4perl!
МониторингYandex::Unrotate
• Да здравствует Log::Log4perl!
• /var/log/unrotate/failures.log
МониторингYandex::Unrotate
• Да здравствует Log::Log4perl!
• /var/log/unrotate/failures.log
• ...и /var/log/unrotate/failures.pos
А если машин много?
propagateРасссылка данных
system(qq{cat $tmpfile | ssh robot1 ‘accept scheduler.log’});# или:system(q{tar c index | ssh search-host ‘accept index.tar});
acceptРассылка данных
my $fname = shift @ARGV or die "missing fname";
@modules = ( (grep { ! m#\.[^/]*$# } glob "/etc/accept.d/*"), );for (@modules) { my $object = do ($_); warn $@ if $@; push @objects, $object if $object;}for my $object (@objects) { exit(0) if $object->process($fname);}
die "no module to process $fname";
propagate.dРасссылка данных
$ cat /etc/propagate.d/scheduler{
LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/propagate.pos”,Acceptors => [
{Host => “robot1”,Key => “/var/lib/ppb_key.rsa”,User => “ppb”,
},{
Host => “robot2”,Key => “/var/lib/ppb_key.rsa”,User => “ppb”,
},],Limit => 5000,
}
propagate.dРасссылка данных
Или так:$ cat /etc/propagate.d/scheduler{
LogFile => “/var/spool/scheduler.log”,PosFile => “/var/lib/propagate.pos”,Acceptors => connectdb(“meta”)->selectall_arrayref(q{ SELECT host AS Host, “ppb” AS User, “/var/lib/ppb-key.rsa” AS Key FROM RobotHosts}, { Slice => {} }),Limit => 5000,
}
Много роботовПример
scheduler.pl
/var/spool/scheduler.log
/var/spool/scheduler.log
robot.pl
/var/spool/scheduler.log
robot.pl
/var/spool/scheduler.log
robot.pl
scheduler.ya.ru
robot1.ya.ru robot2.ya.ru robot3.ya.ru
PPB::Join
• из файла
• из базы
• из памяти
Для работы с отсортированными потокамиPPB::Join
PPB::Join
$seq = file_seq(xopen(“/var/log/robot/links.log”);print $seq->shift; # 1000 http://ya.ruprint $seq->shift; # 1017 http://www.ruprint $seq->shift; # 1017 http://google.comprint $seq->shift; # 1018 http://mail.ru
file_seq
PPB::Join
$seq = map_seq(sub {shift =~ /^(\d+)\t(\S+)$/}, $file_seq);$seq->shift; # (1000, “http://ya.ru”)$seq->shift; # (1017, “http://www.ru”)$seq->shift; # (1017, “http://google.com”)$seq->shift; # (1018, “http://mail.ru”)
map_seq
PPB::Join
$seq = split_seq($file_seq, “link”, qr/\t/);$seq->shift; # (1000, {link => “http://ya.ru”})$seq->shift; # (1017, {link => “http://www.ru”})$seq->shift; # (1017, {link => “http://google.com”})$seq->shift; # (1018, {link => “http://mail.ru”})
split_seq
PPB::Join
$seq = group_seq($dbh_seq);$seq->shift; # (1000, {link => [“http://ya.ru”]})$seq->shift; # (1017, {link => [“http://www.ru”, # “http://google.com”]})$seq->shift; # (1018, {link => “http://mail.ru”})
group_seq
PPB::Join
$seq = dbh_seq( $db->prepare(“select id, url from feeds”), “id”);$seq->shift; # (1000, {url => “http://dolboeb.livejournal.com”})$seq->shift; # (1017, {url => “http://avva.livejournal.com”})$seq->shift; # (1018, {url => “http://drugoi.livejournal.com”})
dbh_seq
PPB::Join
$seq = join_seq($dbh_seq, $group_seq);$seq->shift; # (1000, { # url => “http://dolboeb.livejournal.com”, # link => “http://ya.ru” # })$seq->shift; # (1017, { # url => “http://avva.livejournal.com”, # link => [“http://www.ru”, # “http://google.com” # ] # })$seq->shift; # (1018, { # url => ”http://drugoi.livejournal.com”, # link => “http://mail.ru” # })
join_seq
robot3.ya.rurobot2.ya.ru
robot.pl
Много роботов с обратной связьюПример
scheduler.pl
/var/spool/scheduler.log
/var/spool/scheduler.log
robot.pl
/var/spool/scheduler.log /var/spool/scheduler.log
scheduler.ya.ru
robot1.ya.ru
robot.pl
/var/log/links.log /var/log/links.log /var/log/links.log
/var/lib/link_chunks/* scheduler_rebuild_stat.pl
db.ya.ru
feeds
scheduler_stat
__END__
Разработчик
Россия, Москва,ул. Льва Толстого, 16.
+7 (495) 739-00-00+7 (495) 739-70-70 — факс
Вячеслав Матюхин