SlideShare a Scribd company logo
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
print STDERR “timeoutn”;

timeout


warn(“timeout”);

timeout at test.pl line 8.
sub logf {
    my ($level,$message) = @_;
    my ($pkg,$file,$line) = caller;
    my @time = localtime;
    warn sprintf "%04d-%02d-%02dT%02d:%02d:%02d 
      [%s] %s at %s line %d.n",
        $time[5]+1900, $time[4]+1, @time[3,2,1,0],
        $level, $message,
        $file, $line;
}

logf(“WARN”,”timeout”);
logf(“INFO”,”foo bar”);


2011-10-05T09:41:30 [WARN] timeout at test.pl line 10.
2011-10-05T09:41:30 [INFO] foo bar at test.pl line 11.
➔
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
2011-10-05T09:41:30
[WARN]
[/entry/foobar]
failed request: http://ad.net/ read timeout
at /path/to/Controler/Entry.pm line 10.
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
use Log::Minimal;

# stack trace
debugf(‘blah blah blah’);
infof(“server start $$”);
critf("%s","foo");
warnf("%d %s", 1, "foo");

# stack trace
debugff(‘blah blah blah’);
infoff(“server start $$”);
critff("%s","foo");
warnff("%d %s", 1, "foo");
use Log::Minimal;

debugf(‘blah blah blah’); #

local $ENV{LM_DEBUG} = 1;
debugf(‘blah blah blah’); #


2011-10-05T09:41:30 [DEBUG] blah.. at test.pl line 11.
#
local $Log::Minimal::PRINT = sub {
    my ( $time, $type, $message, $trace) = @_;
    warn(“$time [$type] $message $tracen”);
};

#
open( my $fh, ">>", "app.log");
local $Log::Minimal::PRINT = sub {
    my ( $time, $type, $msg, $tr, $r_msg ) = @_;
    print $fh “$time [$type] $r_msg $trn”;
};
#
local $Log::Minimal::AUTODUMP = 1;
warnf(“response => %s”,$res);


2011-05-11T15:56:14 [WARN] response => [200,
['Content-Type','text/plain'],['OK']] at ..


#
local $Log::Minimal::COLOR = 1;
warnf(“hirose31”);


2011-05-11T15:56:14 [WARN] hirose31 at ..
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
use Log::Minimal;
use Plack::Builder;
builder {
    enable "Log::Minimal", autodump => 1;
    sub {
        my $env = shift;
        warnf("warn");
        debugf("debug");
        ...
    }
};



$ plackup -a demo.psgi
2011-05-11T16:32:24 [WARN] [/foo/bar/baz] warn at /tmp/
demo.psgi line 8
2011-05-11T16:32:24 [DEBUG] [/foo/bar/baz] debug at /tmp/
demo.psgi line 9
use Log::Minimal;
use Parallel::Prefork;

my $pm = Parallel::Prefork->new();
while ( $pm->signal_received ne 'TERM' ) {
    $pm->start(sub {
        local $Log::Minimal::AUTODUMP = 1;
        local $Log::Minimal::COLOR = 1;
        while (1) {
            my $job = $queue->dequeue;
            local $Log::Minimal::PRINT = sub {
                 my ( $time, $type, $message, $trace) = @_;
                warn(“$$ [“,$job->name,”] [$type] $message $trace”);
            };
            ...
        }
    });
}
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
SELECT   * FROM entries
 WHERE   created_at >= '2011-10-05 00:00:00'
   AND   created_at < '2011-10-06 00:00:00'
   AND   status != 0;




Data::Entry->search({
    -and => [
        created_at => {'>=','2011-10-05 00:00:00' },
        created_at => {'<','2011-10-06 00:00:00' },
    ],
    status => { '!=', 0 }
});
SELECT   * FROM entries
 WHERE   created_at >= '2011-10-05 00:00:00'
   AND   created_at < '2011-10-06 00:00:00'
   AND   status != 0;




Data::Entry->search({
    -and => [
        created_at => {'>=','2011-10-05 00:00:00' },
        created_at => {'<','2011-10-06 00:00:00' },
    ],
    status => { '!=', 0 }
});
SELECT   * FROM entries
 WHERE   created_at >= '2011-10-05 00:00:00'
   AND   created_at < '2011-10-06 00:00:00'
   AND   status != 0;




Data::Entry->search({
    -and => [
        created_at => {'>=','2011-10-05 00:00:00' },
        created_at => {'<','2011-10-06 00:00:00' },
    ],
    status => { '!=', 0 }
});
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
my $dbh = DBIx::Sunny->connect(
 ‘dsn’,‘user’,‘passwd’,
);


✓   RaiseError => 1
✓   PrintError= > 0
✓   ShowErrorStatement => 1
✓   AutoInactiveDestroy => 1
✓   sqlite_unicode/mysql_enable_utf8 => 1
✓   mysql_auto_reconnect => 0
my $sth = $dbh->prepare(“SELECT *
 FROM entries
 WHERE ..”);




SELECT /* test.pl line 941 */ *
  FROM entries
  WHERE ..
selectrow_arrayref($query, {}, @bind);




selectrow_hashref($query, {}, @bind);




selectall_arrayref($query, { Slice => {} }, @bind);




prepare($query) && execute(@bind)
my $builder = SQL::Maker->new(
    driver => 'mysql',
);
my $dbh = DBIx::Sunny->connect(...);

my ($sql, @binds) = $builder->select(
    'user',
    ['*'],
    {name => 'john'},
    {order_by => 'user_id DESC'}
);

my $rows = $dbh->select_row($sql,@binds);
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
my $dbh = DBI->connect($dsn,$user,$pass,{...});
while ( my $job = $queue->dequeue ) {
    ....
}


my $DBH;
sub get_dbh {
    $DBH ||= DBI->connect($dsn,$user,$pass,{...});
    $DBH;
}
while ( my $job = $queue->dequeue ) {
    my $dbh = get_dbh();
    ....
}


sub get_dbh {
    DBI->connect_cached($dsn,$user,$pass,{...});
}
while ( my $job = $queue->dequeue ) {
    my $dbh = get_dbh();
    ....
}
my $dbh = DBI->connect($dsn,$user,$pass,{...});
while ( my $job = $queue->dequeue ) {
    ....
}


my $DBH;
sub get_dbh {
    $DBH ||= DBI->connect($dsn,$user,$pass,{...});
    $DBH;
}
while ( my $job = $queue->dequeue ) {
    my $dbh = get_dbh();
    ....
}


sub get_dbh {
    DBI->connect_cached($dsn,$user,$pass,{...});
}
while ( my $job = $queue->dequeue ) {
    my $dbh = get_dbh();
    ....
}
> SHOW PROCESSLIST;
+--------+-------------+--------------------+---------+---------+-------+----------+------+
| Id     | User        | Host               | db      | Command | Time | State     | Info |
+--------+-------------+--------------------+---------+---------+-------+----------+------+
|      1 | system user |                    | NULL    | Connect | 4851 | Wait... | NULL |
|      2 | system user |                    | NULL    | Connect | 1     | Has r... | NULL |
| 235873 | www-slave   | 10.0.xxx.39:33018 | cluster | Sleep    | 8     |          | NULL |
| 278334 | www-slave   | 10.0.xxx.39:37627 | cluster | Sleep    | 1206 |           | NULL |
| 365403 | www-slave   | 10.0.xxx.39:43957 | cluster | Sleep    | 1259 |           | NULL |
| 378019 | www-slave   | 10.0.xxx.39:45098 | cluster | Sleep    | 138   |          | NULL |
| 397336 | www-slave   | 10.0.xxx.39:48595 | cluster | Sleep    | 377   |          | NULL |
| 404611 | www-slave   | 10.0.xxx.206:60525 | cluster | Sleep   | 44    |          | NULL |
| 405048 | www-slave   | 10.0.xxx.206:60645 | cluster | Sleep   | 119   |          | NULL |
| 405091 | www-slave   | 10.0.xxx.58:51982 | cluster | Sleep    | 1104 |           | NULL |
.....
811 rows in set (0.00 sec)
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
my $sc = start_scope_container(); #
scope_container(‘key1’,‘value1’);
$value = scope_container(‘key1’); #value

sub hoge {
    scope_container(‘key2’,‘foobar’);
}

{
    my $sc2 = start_scope_container(); #
    $value = scope_container(‘key1’); #value
    scope_container(‘key1’,‘blahblah’);
    hoge();
    $value = scope_container(‘key1’); #blahblah
    $value = scope_container(‘key2’); #foobar
    undef $sc2;
}

$value = scope_container(‘key1’); #value
$value = scope_container(‘key2’); #undefined
my %DATA; #
$DATA{'key1'} = 'value1';
$value = $DATA{'key1'} #value

sub hoge {
    $DATA{'key2'} = 'foobar';
}

{
    local %DATA; #
    $value = $DATA{'key1'} #value
    $DATA{'key1'} = ‘blahblah’
    hoge();
    $value = $DATA{'key1'}; #blahblah
    $value = $DATA{'key2'} #foobar
}

$value = $DATA{'key1'}; #value
$value = $DATA{'key2'}; #undefined
sub get_dbh {
    my $dsn = shift

    my $cache = scope_container($dsn);
    reutrn $cache if $cache;

    my $dbh = DBIx:Sunny->connect($dsn,$user,$pass);
    scope_container($dsn, $dbh);
    return $dbh;
}

while ( my $job = $queue->dequeue ) {
    my $sc = start_scope_container();
    my $dbh = get_dbh(); #new connection
    my $dbh2 = get_dbh(); #cached
    ..
    # disconnect
}
use Scope::Container;
use Scope::Container::DBI;

sub get_dbh {
    Scope::Container::DBI->connect($dsn,$user,$pass,{}):
}

for my $id (1..$max) {
    my $sc = start_scope_container();

    get_dbh()->do(...); #new connection
    get_dbh()->select_row(...); #cache

    undef $sc; #
}
# DBI
local $Scope::Container::DBI::DBI_CLASS = “Amon2::DBI”;
my $dbh = Scope::Container::DBI->connect(
    $dsn,$user,$pass,{});



#       slave    1
my $dbh = Scope::Container::DBI->connect(
    [$dsn1,$user,$pass,{}],
    [$dsn2,$user,$pass,{}],
    [$dsn3,$user,$pass,{}],
);
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
use Plack::Builder;

builder {
    enable “Scope::Container”;
    $app;
};



# Plack::Middleware::Scope::Container
sub call {
    my ( $self, $env) = @_;
    my $container = start_scope_container();
    $self->app->($env);
}
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
key1   key2   key3   key4   key5   key6    key7   key8   key9




        memcached1      memcached2        memcached3
key1   key2   key3   key4   key5   key6    key7   key8   key9




        memcached1      memcached2        memcached3
key1   key2   key3   key4   key5   key6    key7   key8   key9




        memcached1      memcached2        memcached3
key1   key2   key3   key4   key5   key6    key7   key8   key9




        memcached1      memcached2        memcached3
App   App




mem       DB
App   App      App   App




mem       DB   mem
App   App      App   App




mem       DB   mem       DB
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
use Cache::Memcached::IronPlate;
use Cache::Memcached::Fast;

my $memd = Cache::Memcached::IronPlate->new(
    cache => Cache::Memcached::Fast->new(...),
);

$memd->get
$memd->get_multi
$memd->set
$memd->add
$memd->replace
$memd->append
$memd->prepend
$memd->incr
$memd->counter
$memd->decr
$memd->delete
set(‘key:dup’,val,exp)     get(‘key:dup’)




      IronPlate               IronPlate


 set key:dist:{1..3}     get key:dist:{1..3}



mem1 mem2 mem3           mem1 mem2 mem3
set(‘key:dist’,val,exp)      get(‘key:dist’)




       IronPlate                IronPlate


 set key:dist:{1..30}     get key:dist:rand(30)



 mem1 mem2 mem3           mem1 mem2 mem3
use Cache::Isolator;
use Cache::Memcached::Fast;
 
my $isolator = Cache::Isolator->new(
    cache => Cache::Memcached::Fast->new(...),
);

$isolator->get(key);
$isolator->set(key,val,expires);
set(‘key’,val,30)                 set(‘key’,val,30)




         Isolator                          Isolator


set key 30      set key:earlyexp 20




     mem1      mem2                   mem1       mem2
use Cache::Isolator;
use Cache::Memcached::Fast;
 
my $isolator = Cache::Isolator->new(
    cache => Cache::Memcached::Fast->new(...),
    early_expires_ratio => 10,
    expires_before => 10
);

$isolator->get(key);
$isolator->set(key,val,expires);
use Cache::Isolator;
use Cache::Memcached::Fast;
 
my $isolator = Cache::Isolator->new(
    cache => Cache::Memcached::Fast->new(...),
    concurrency => 3,
);

$isolator->get_or_set(key, sub {
    my $dbh = get_dbh();
    $dbh->select_all(heavy_sql);
}, expires);
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
DB


response   memcached
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
use Plack::Builder;
use File::Temp;

builder {
  enable "ServerStatus::Lite",
    path => '/___server-status',
    allow => [‘127.0.0.1’,‘192.168.0.0/16’],
    scoreboard => File::Temp::tempdir(CLEANUP => 1);
  $app
};
$ curl http://localhost:5000/___server-status
Uptime: 1318372692
BusyWorkers: 3
IdleWorkers: 27
--
pid status remote_addr host method uri protocol
1522 A 127.0.0.1 localhost:5000 GET /___server-status HTTP/1.1
1523 _ 192.168.67.3 192.168.67.4:5000 GET /foo/bar HTTP/1.0
1526 _ 192.168.67.5 192.168.67.4:5000 GET /foo/bar HTTP/1.0
...
use Parallel::Prefork;
use Parallel::Scoreboard;

my $sb = Parallel::Scoreboard->new(
  base_dir => ‘/var/run/example_worker’ );

my $pm = Parallel::Prefork->new({...});
while ( $pm->signal_received !~ m!^(?:TERM|INT)$! ) {
  $pm->start(sub{
    $sb->update('.');
    while(1) {
      my $job = $queue->dequeue;
      $sb->update('A');
      #work work work
      $sb->update('.');
    }
  });
}
use Parallel::Prefork;
use Parallel::Scoreboard;

my $sb = Parallel::Scoreboard->new(
  base_dir => ‘/var/run/example_worker’ );

my $pm = Parallel::Prefork->new({...});
while ( $pm->signal_received !~ m!^(?:TERM|INT)$! ) {
  $pm->start(sub{      idle
    $sb->update('.');
    while(1) {
      my $job = $queue->dequeue;
      $sb->update('A');
      #work work work       busy
      $sb->update('.');
    }
  });                     idle
}
# scoreboard.psgi
my $sb = Parallel::Scoreboard->new(
  base_dir => ‘/var/run/example_worker’ );
sub {
  my $env = shift;
  my $stats = $scoreboard->read_all();
  my $busy = 0;
  my $idle = 0;
  for my $pid ( sort { $a <=> $b } keys %$stats) {
    if ( $stats->{$pid} =~ m!^A! ) {
      $busy++;
    } else {                       busy
      $idle++;
    }
  }
  return [200,['Content-Type'=>'plain/text'],
           ["BusyWorkers: $busynIdleWorkers: $idle"]];
};
#
$ plackup -p 5001 -a scoreboard.psgi

#
$ curl http://localhost:5001/___server-status
BusyWorkers: 6
IdleWorkers: 4
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
192.188.67.2
               idle




                  busy
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011

More Related Content

PDF
The History of PHPersistence
PDF
Database Design Patterns
PDF
Nubilus Perl
PDF
Design Patterns avec PHP 5.3, Symfony et Pimple
PDF
Command Bus To Awesome Town
KEY
Perl Web Client
PDF
Models and Service Layers, Hemoglobin and Hobgoblins
PDF
Teaching Your Machine To Find Fraudsters
The History of PHPersistence
Database Design Patterns
Nubilus Perl
Design Patterns avec PHP 5.3, Symfony et Pimple
Command Bus To Awesome Town
Perl Web Client
Models and Service Layers, Hemoglobin and Hobgoblins
Teaching Your Machine To Find Fraudsters

What's hot (20)

PDF
Doctrine fixtures
PDF
Debugging: Rules And Tools - PHPTek 11 Version
PDF
PHP 5.3 and Lithium: the most rad php framework
PDF
Things I Believe Now That I'm Old
PDF
Drush. Secrets come out.
PDF
The Zen of Lithium
PDF
Doctrine MongoDB ODM (PDXPHP)
PDF
Silex meets SOAP & REST
PDF
Lithium: The Framework for People Who Hate Frameworks
PPT
An Elephant of a Different Colour: Hack
PDF
Dependency Injection IPC 201
KEY
Crazy things done on PHP
PDF
From mysql to MongoDB(MongoDB2011北京交流会)
PDF
The Origin of Lithium
TXT
Daily notes
PPTX
Drupal 8 database api
ODP
Rich domain model with symfony 2.5 and doctrine 2.5
PDF
News of the Symfony2 World
ODP
Symfony2, creare bundle e valore per il cliente
Doctrine fixtures
Debugging: Rules And Tools - PHPTek 11 Version
PHP 5.3 and Lithium: the most rad php framework
Things I Believe Now That I'm Old
Drush. Secrets come out.
The Zen of Lithium
Doctrine MongoDB ODM (PDXPHP)
Silex meets SOAP & REST
Lithium: The Framework for People Who Hate Frameworks
An Elephant of a Different Colour: Hack
Dependency Injection IPC 201
Crazy things done on PHP
From mysql to MongoDB(MongoDB2011北京交流会)
The Origin of Lithium
Daily notes
Drupal 8 database api
Rich domain model with symfony 2.5 and doctrine 2.5
News of the Symfony2 World
Symfony2, creare bundle e valore per il cliente
Ad

Similar to Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011 (20)

KEY
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
KEY
Good Evils In Perl (Yapc Asia)
PDF
PHP Tips & Tricks
KEY
Operation Oriented Web Applications / Yokohama pm7
PDF
R57shell
PPTX
Basics of Working with PHP and MySQL.pptx
PDF
Dirty Secrets of the PHP SOAP Extension
PPTX
DrupalCamp Foz - Novas APIs Drupal 7
PDF
Introdução ao Perl 6
PDF
20 modules i haven't yet talked about
PDF
Desarrollo de módulos en Drupal e integración con dispositivos móviles
PPTX
What mom never told you about bundle configurations - Symfony Live Paris 2012
 
PPT
Database api
PDF
Redis for the Everyday Developer
DOC
KEY
循環参照のはなし
TXT
R57.Php
PPTX
Php functions
PDF
Zendcon 2007 Api Design
PDF
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Good Evils In Perl (Yapc Asia)
PHP Tips & Tricks
Operation Oriented Web Applications / Yokohama pm7
R57shell
Basics of Working with PHP and MySQL.pptx
Dirty Secrets of the PHP SOAP Extension
DrupalCamp Foz - Novas APIs Drupal 7
Introdução ao Perl 6
20 modules i haven't yet talked about
Desarrollo de módulos en Drupal e integración con dispositivos móviles
What mom never told you about bundle configurations - Symfony Live Paris 2012
 
Database api
Redis for the Everyday Developer
循環参照のはなし
R57.Php
Php functions
Zendcon 2007 Api Design
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Ad

More from Masahiro Nagano (20)

PDF
Advanced nginx in mercari - How to handle over 1,200,000 HTTPS Reqs/Min
PDF
Rhebok, High Performance Rack Handler / Rubykaigi 2015
PDF
Big Master Data PHP BLT #1
PDF
Stream processing in Mercari - Devsumi 2015 autumn LT
PDF
メルカリのデータベース戦略 / PHPとMySQLの怖い話 MyNA会2015年8月
PDF
ISUCONの勝ち方 YAPC::Asia Tokyo 2015
PDF
Norikraで作るPHPの例外検知システム YAPC::Asia Tokyo 2015 LT
PDF
メルカリでのNorikraの活用、 Mackerelを添えて
PDF
Gazelle & CPAN modules for performance. Shibuya.pm Tech Talk #17 LT
PDF
Mackerel & Norikra mackerel meetup #4 LT
PDF
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
PDF
Isucon makers casual talks
PDF
blogサービスの全文検索の話 - #groonga を囲む夕べ
PDF
Gazelle - Plack Handler for performance freaks #yokohamapm
PDF
Dockerで遊んでみよっかー YAPC::Asia Tokyo 2014
PDF
Web Framework Benchmarksと Perl の現状報告会 YAPC::Asia Tokyo 2014 LT
PDF
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
PDF
Webアプリケーションの パフォーマンス向上のコツ 実践編
PDF
Webアプリケーションの パフォーマンス向上のコツ 概要編
PDF
Webアプリケーションとメモリ
Advanced nginx in mercari - How to handle over 1,200,000 HTTPS Reqs/Min
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Big Master Data PHP BLT #1
Stream processing in Mercari - Devsumi 2015 autumn LT
メルカリのデータベース戦略 / PHPとMySQLの怖い話 MyNA会2015年8月
ISUCONの勝ち方 YAPC::Asia Tokyo 2015
Norikraで作るPHPの例外検知システム YAPC::Asia Tokyo 2015 LT
メルカリでのNorikraの活用、 Mackerelを添えて
Gazelle & CPAN modules for performance. Shibuya.pm Tech Talk #17 LT
Mackerel & Norikra mackerel meetup #4 LT
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
Isucon makers casual talks
blogサービスの全文検索の話 - #groonga を囲む夕べ
Gazelle - Plack Handler for performance freaks #yokohamapm
Dockerで遊んでみよっかー YAPC::Asia Tokyo 2014
Web Framework Benchmarksと Perl の現状報告会 YAPC::Asia Tokyo 2014 LT
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
Webアプリケーションの パフォーマンス向上のコツ 実践編
Webアプリケーションの パフォーマンス向上のコツ 概要編
Webアプリケーションとメモリ

Recently uploaded (20)

PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
A Presentation on Artificial Intelligence
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Modernizing your data center with Dell and AMD
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PPT
Teaching material agriculture food technology
PPTX
MYSQL Presentation for SQL database connectivity
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
NewMind AI Monthly Chronicles - July 2025
PDF
KodekX | Application Modernization Development
PDF
Machine learning based COVID-19 study performance prediction
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Mobile App Security Testing_ A Comprehensive Guide.pdf
Understanding_Digital_Forensics_Presentation.pptx
Spectral efficient network and resource selection model in 5G networks
A Presentation on Artificial Intelligence
“AI and Expert System Decision Support & Business Intelligence Systems”
Modernizing your data center with Dell and AMD
Building Integrated photovoltaic BIPV_UPV.pdf
Teaching material agriculture food technology
MYSQL Presentation for SQL database connectivity
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
NewMind AI Monthly Chronicles - July 2025
KodekX | Application Modernization Development
Machine learning based COVID-19 study performance prediction
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Reach Out and Touch Someone: Haptics and Empathic Computing
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Advanced methodologies resolving dimensionality complications for autism neur...
Encapsulation_ Review paper, used for researhc scholars
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025

Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011

  • 21. sub logf { my ($level,$message) = @_; my ($pkg,$file,$line) = caller; my @time = localtime; warn sprintf "%04d-%02d-%02dT%02d:%02d:%02d [%s] %s at %s line %d.n", $time[5]+1900, $time[4]+1, @time[3,2,1,0], $level, $message, $file, $line; } logf(“WARN”,”timeout”); logf(“INFO”,”foo bar”); 2011-10-05T09:41:30 [WARN] timeout at test.pl line 10. 2011-10-05T09:41:30 [INFO] foo bar at test.pl line 11.
  • 22.
  • 28. use Log::Minimal; # stack trace debugf(‘blah blah blah’); infof(“server start $$”); critf("%s","foo"); warnf("%d %s", 1, "foo"); # stack trace debugff(‘blah blah blah’); infoff(“server start $$”); critff("%s","foo"); warnff("%d %s", 1, "foo");
  • 29. use Log::Minimal; debugf(‘blah blah blah’); # local $ENV{LM_DEBUG} = 1; debugf(‘blah blah blah’); # 2011-10-05T09:41:30 [DEBUG] blah.. at test.pl line 11.
  • 30. # local $Log::Minimal::PRINT = sub { my ( $time, $type, $message, $trace) = @_; warn(“$time [$type] $message $tracen”); }; # open( my $fh, ">>", "app.log"); local $Log::Minimal::PRINT = sub { my ( $time, $type, $msg, $tr, $r_msg ) = @_; print $fh “$time [$type] $r_msg $trn”; };
  • 31. # local $Log::Minimal::AUTODUMP = 1; warnf(“response => %s”,$res); 2011-05-11T15:56:14 [WARN] response => [200, ['Content-Type','text/plain'],['OK']] at .. # local $Log::Minimal::COLOR = 1; warnf(“hirose31”); 2011-05-11T15:56:14 [WARN] hirose31 at ..
  • 37. use Log::Minimal; use Plack::Builder; builder {     enable "Log::Minimal", autodump => 1;     sub {         my $env = shift;         warnf("warn");         debugf("debug");         ...     } }; $ plackup -a demo.psgi 2011-05-11T16:32:24 [WARN] [/foo/bar/baz] warn at /tmp/ demo.psgi line 8 2011-05-11T16:32:24 [DEBUG] [/foo/bar/baz] debug at /tmp/ demo.psgi line 9
  • 38. use Log::Minimal; use Parallel::Prefork; my $pm = Parallel::Prefork->new(); while ( $pm->signal_received ne 'TERM' ) { $pm->start(sub { local $Log::Minimal::AUTODUMP = 1; local $Log::Minimal::COLOR = 1; while (1) { my $job = $queue->dequeue; local $Log::Minimal::PRINT = sub { my ( $time, $type, $message, $trace) = @_; warn(“$$ [“,$job->name,”] [$type] $message $trace”); }; ... } }); }
  • 44. SELECT * FROM entries WHERE created_at >= '2011-10-05 00:00:00' AND created_at < '2011-10-06 00:00:00' AND status != 0; Data::Entry->search({ -and => [ created_at => {'>=','2011-10-05 00:00:00' }, created_at => {'<','2011-10-06 00:00:00' }, ], status => { '!=', 0 } });
  • 45. SELECT * FROM entries WHERE created_at >= '2011-10-05 00:00:00' AND created_at < '2011-10-06 00:00:00' AND status != 0; Data::Entry->search({ -and => [ created_at => {'>=','2011-10-05 00:00:00' }, created_at => {'<','2011-10-06 00:00:00' }, ], status => { '!=', 0 } });
  • 46. SELECT * FROM entries WHERE created_at >= '2011-10-05 00:00:00' AND created_at < '2011-10-06 00:00:00' AND status != 0; Data::Entry->search({ -and => [ created_at => {'>=','2011-10-05 00:00:00' }, created_at => {'<','2011-10-06 00:00:00' }, ], status => { '!=', 0 } });
  • 50. my $dbh = DBIx::Sunny->connect( ‘dsn’,‘user’,‘passwd’, ); ✓ RaiseError => 1 ✓ PrintError= > 0 ✓ ShowErrorStatement => 1 ✓ AutoInactiveDestroy => 1 ✓ sqlite_unicode/mysql_enable_utf8 => 1 ✓ mysql_auto_reconnect => 0
  • 51. my $sth = $dbh->prepare(“SELECT * FROM entries WHERE ..”); SELECT /* test.pl line 941 */ * FROM entries WHERE ..
  • 52. selectrow_arrayref($query, {}, @bind); selectrow_hashref($query, {}, @bind); selectall_arrayref($query, { Slice => {} }, @bind); prepare($query) && execute(@bind)
  • 53. my $builder = SQL::Maker->new( driver => 'mysql', ); my $dbh = DBIx::Sunny->connect(...); my ($sql, @binds) = $builder->select( 'user', ['*'], {name => 'john'}, {order_by => 'user_id DESC'} ); my $rows = $dbh->select_row($sql,@binds);
  • 55. my $dbh = DBI->connect($dsn,$user,$pass,{...}); while ( my $job = $queue->dequeue ) { .... } my $DBH; sub get_dbh { $DBH ||= DBI->connect($dsn,$user,$pass,{...}); $DBH; } while ( my $job = $queue->dequeue ) { my $dbh = get_dbh(); .... } sub get_dbh { DBI->connect_cached($dsn,$user,$pass,{...}); } while ( my $job = $queue->dequeue ) { my $dbh = get_dbh(); .... }
  • 56. my $dbh = DBI->connect($dsn,$user,$pass,{...}); while ( my $job = $queue->dequeue ) { .... } my $DBH; sub get_dbh { $DBH ||= DBI->connect($dsn,$user,$pass,{...}); $DBH; } while ( my $job = $queue->dequeue ) { my $dbh = get_dbh(); .... } sub get_dbh { DBI->connect_cached($dsn,$user,$pass,{...}); } while ( my $job = $queue->dequeue ) { my $dbh = get_dbh(); .... }
  • 57. > SHOW PROCESSLIST; +--------+-------------+--------------------+---------+---------+-------+----------+------+ | Id | User | Host | db | Command | Time | State | Info | +--------+-------------+--------------------+---------+---------+-------+----------+------+ | 1 | system user | | NULL | Connect | 4851 | Wait... | NULL | | 2 | system user | | NULL | Connect | 1 | Has r... | NULL | | 235873 | www-slave | 10.0.xxx.39:33018 | cluster | Sleep | 8 | | NULL | | 278334 | www-slave | 10.0.xxx.39:37627 | cluster | Sleep | 1206 | | NULL | | 365403 | www-slave | 10.0.xxx.39:43957 | cluster | Sleep | 1259 | | NULL | | 378019 | www-slave | 10.0.xxx.39:45098 | cluster | Sleep | 138 | | NULL | | 397336 | www-slave | 10.0.xxx.39:48595 | cluster | Sleep | 377 | | NULL | | 404611 | www-slave | 10.0.xxx.206:60525 | cluster | Sleep | 44 | | NULL | | 405048 | www-slave | 10.0.xxx.206:60645 | cluster | Sleep | 119 | | NULL | | 405091 | www-slave | 10.0.xxx.58:51982 | cluster | Sleep | 1104 | | NULL | ..... 811 rows in set (0.00 sec)
  • 60. my $sc = start_scope_container(); # scope_container(‘key1’,‘value1’); $value = scope_container(‘key1’); #value sub hoge { scope_container(‘key2’,‘foobar’); } { my $sc2 = start_scope_container(); # $value = scope_container(‘key1’); #value scope_container(‘key1’,‘blahblah’); hoge(); $value = scope_container(‘key1’); #blahblah $value = scope_container(‘key2’); #foobar undef $sc2; } $value = scope_container(‘key1’); #value $value = scope_container(‘key2’); #undefined
  • 61. my %DATA; # $DATA{'key1'} = 'value1'; $value = $DATA{'key1'} #value sub hoge { $DATA{'key2'} = 'foobar'; } { local %DATA; # $value = $DATA{'key1'} #value $DATA{'key1'} = ‘blahblah’ hoge(); $value = $DATA{'key1'}; #blahblah $value = $DATA{'key2'} #foobar } $value = $DATA{'key1'}; #value $value = $DATA{'key2'}; #undefined
  • 62. sub get_dbh { my $dsn = shift my $cache = scope_container($dsn); reutrn $cache if $cache; my $dbh = DBIx:Sunny->connect($dsn,$user,$pass); scope_container($dsn, $dbh); return $dbh; } while ( my $job = $queue->dequeue ) { my $sc = start_scope_container(); my $dbh = get_dbh(); #new connection my $dbh2 = get_dbh(); #cached .. # disconnect }
  • 63. use Scope::Container; use Scope::Container::DBI; sub get_dbh { Scope::Container::DBI->connect($dsn,$user,$pass,{}): } for my $id (1..$max) { my $sc = start_scope_container(); get_dbh()->do(...); #new connection get_dbh()->select_row(...); #cache undef $sc; # }
  • 64. # DBI local $Scope::Container::DBI::DBI_CLASS = “Amon2::DBI”; my $dbh = Scope::Container::DBI->connect( $dsn,$user,$pass,{}); # slave 1 my $dbh = Scope::Container::DBI->connect( [$dsn1,$user,$pass,{}], [$dsn2,$user,$pass,{}], [$dsn3,$user,$pass,{}], );
  • 70. use Plack::Builder; builder { enable “Scope::Container”; $app; }; # Plack::Middleware::Scope::Container sub call { my ( $self, $env) = @_; my $container = start_scope_container(); $self->app->($env); }
  • 73. key1 key2 key3 key4 key5 key6 key7 key8 key9 memcached1 memcached2 memcached3
  • 74. key1 key2 key3 key4 key5 key6 key7 key8 key9 memcached1 memcached2 memcached3
  • 75. key1 key2 key3 key4 key5 key6 key7 key8 key9 memcached1 memcached2 memcached3
  • 76. key1 key2 key3 key4 key5 key6 key7 key8 key9 memcached1 memcached2 memcached3
  • 77. App App mem DB
  • 78. App App App App mem DB mem
  • 79. App App App App mem DB mem DB
  • 81. use Cache::Memcached::IronPlate; use Cache::Memcached::Fast; my $memd = Cache::Memcached::IronPlate->new( cache => Cache::Memcached::Fast->new(...), ); $memd->get $memd->get_multi $memd->set $memd->add $memd->replace $memd->append $memd->prepend $memd->incr $memd->counter $memd->decr $memd->delete
  • 82. set(‘key:dup’,val,exp) get(‘key:dup’) IronPlate IronPlate set key:dist:{1..3} get key:dist:{1..3} mem1 mem2 mem3 mem1 mem2 mem3
  • 83. set(‘key:dist’,val,exp) get(‘key:dist’) IronPlate IronPlate set key:dist:{1..30} get key:dist:rand(30) mem1 mem2 mem3 mem1 mem2 mem3
  • 84. use Cache::Isolator; use Cache::Memcached::Fast;   my $isolator = Cache::Isolator->new(     cache => Cache::Memcached::Fast->new(...), ); $isolator->get(key); $isolator->set(key,val,expires);
  • 85. set(‘key’,val,30) set(‘key’,val,30) Isolator Isolator set key 30 set key:earlyexp 20 mem1 mem2 mem1 mem2
  • 86. use Cache::Isolator; use Cache::Memcached::Fast;   my $isolator = Cache::Isolator->new(     cache => Cache::Memcached::Fast->new(...), early_expires_ratio => 10, expires_before => 10 ); $isolator->get(key); $isolator->set(key,val,expires);
  • 87. use Cache::Isolator; use Cache::Memcached::Fast;   my $isolator = Cache::Isolator->new(     cache => Cache::Memcached::Fast->new(...),     concurrency => 3, ); $isolator->get_or_set(key, sub { my $dbh = get_dbh(); $dbh->select_all(heavy_sql); }, expires);
  • 88. DB response memcached
  • 89. DB response memcached
  • 90. DB response memcached
  • 91. DB response memcached
  • 92. DB response memcached
  • 93. DB response memcached
  • 94. DB response memcached
  • 95. DB response memcached
  • 96. DB response memcached
  • 97. DB response memcached
  • 98. DB response memcached
  • 99. DB response memcached
  • 104. use Plack::Builder; use File::Temp; builder { enable "ServerStatus::Lite", path => '/___server-status', allow => [‘127.0.0.1’,‘192.168.0.0/16’], scoreboard => File::Temp::tempdir(CLEANUP => 1); $app };
  • 105. $ curl http://localhost:5000/___server-status Uptime: 1318372692 BusyWorkers: 3 IdleWorkers: 27 -- pid status remote_addr host method uri protocol 1522 A 127.0.0.1 localhost:5000 GET /___server-status HTTP/1.1 1523 _ 192.168.67.3 192.168.67.4:5000 GET /foo/bar HTTP/1.0 1526 _ 192.168.67.5 192.168.67.4:5000 GET /foo/bar HTTP/1.0 ...
  • 106. use Parallel::Prefork; use Parallel::Scoreboard; my $sb = Parallel::Scoreboard->new( base_dir => ‘/var/run/example_worker’ ); my $pm = Parallel::Prefork->new({...}); while ( $pm->signal_received !~ m!^(?:TERM|INT)$! ) { $pm->start(sub{ $sb->update('.'); while(1) { my $job = $queue->dequeue; $sb->update('A'); #work work work $sb->update('.'); } }); }
  • 107. use Parallel::Prefork; use Parallel::Scoreboard; my $sb = Parallel::Scoreboard->new( base_dir => ‘/var/run/example_worker’ ); my $pm = Parallel::Prefork->new({...}); while ( $pm->signal_received !~ m!^(?:TERM|INT)$! ) { $pm->start(sub{ idle $sb->update('.'); while(1) { my $job = $queue->dequeue; $sb->update('A'); #work work work busy $sb->update('.'); } }); idle }
  • 108. # scoreboard.psgi my $sb = Parallel::Scoreboard->new( base_dir => ‘/var/run/example_worker’ ); sub { my $env = shift; my $stats = $scoreboard->read_all(); my $busy = 0; my $idle = 0; for my $pid ( sort { $a <=> $b } keys %$stats) { if ( $stats->{$pid} =~ m!^A! ) { $busy++; } else { busy $idle++; } } return [200,['Content-Type'=>'plain/text'], ["BusyWorkers: $busynIdleWorkers: $idle"]]; };
  • 109. # $ plackup -p 5001 -a scoreboard.psgi # $ curl http://localhost:5001/___server-status BusyWorkers: 6 IdleWorkers: 4
  • 111. 192.188.67.2 idle busy

Editor's Notes