工場長のブログ

日々思ったことを書いてます。

各LL言語でのライブラリパス追加の仕方

いつも忘れるのでメモ

Python

Perl5

ruby

$ruby -l PATH_TO_LIB hoge.rb
  • 環境変数RUBYLIBにパスを追加する
  • rubyスクリプト内から追加するなら
$LOAD_PATH.push('PATH_TO_LIB')

php

  • php.iniのinclude_pathに追加する
  • phpスクリプト内から追加するなら
// 相対パス。PHPではスクリプトの場所がカレントディレクトリになる
set_include_path(dirname(__FILE__) . "/../class/class.php");
// 絶対パス
set_include_path("PATH_TO_LIB");

EC2でnginx動かしてパフォーマンス検証した。

ひとまず動かしてみる。

yumでインストール。楽でいいね。

$ sudo yum install nginx
==snip==
Running Transaction
  Installing : libxslt-1.1.26-2.6.amzn1.x86_64                               1/5
  Installing : GeoIP-1.4.8-1.5.amzn1.x86_64                                  2/5
  Installing : libXpm-3.5.8-2.8.amzn1.x86_64                                 3/5
  Installing : gd-2.0.35-10.9.amzn1.x86_64                                   4/5
  Installing : nginx-1.0.15-1.9.amzn1.x86_64                                 5/5
==snip==
Installed:
  nginx.x86_64 0:1.0.15-1.9.amzn1

Dependency Installed:
  GeoIP.x86_64 0:1.4.8-1.5.amzn1         gd.x86_64 0:2.0.35-10.9.amzn1
  libXpm.x86_64 0:3.5.8-2.8.amzn1        libxslt.x86_64 0:1.1.26-2.6.amzn1

いろいろ一緒にインストールされた。
起動してみる。

$ sudo nginx

ブラウザからアクセスしたら無事にページが表示されました。

パフォーマンスを検証する

  • 比較対象がないとということでapacehと比較することにした。
  • 条件を決める
    • 測定にはjmeterを使うことにする。
    • webサーバーによく使われそうなm1.smallとm1.largeでそれぞれ検証する
    • スレッドグループのパラメータは以下の感じ
      • スレッド数を5, 30でそれぞれ計測
      • スレッドグループをそれぞれ60秒間動かしたときのlatency, スループットを計測
      • 接続もしくはレスポンスに300ms以上かかったものはエラーとみなし、エラーレートも計測する。
    • リクエストで1KBのデータを投げてレスポンスも1KBのデータを返すことにする。
      • ちょっとはまったのが、nginxはPOSTリクエストに対して静的ファイルを返せないらしい。405 not allowedが返ってしまう。なので、queryストリングに1KB分のデータを載せることにした。

結果は以下のとおり。

  • m1.small
計測項目 apache nginx
5スレッド latency(平均値) 27 13
latency(中央値) 5 13
スループット 153.4req/s 321.2req/s
エラーレート 0.09% 0.00%
30スレッド latency(平均値) 113 13
latency(中央値) 39 13
スループット 261.0req/s 1904.7req/s
エラーレート 33.40% 0.00%
  • m1.large
計測項目 apache nginx
5スレッド latency(平均値) 4 13
latency(中央値) 5 13
スループット 875.3req/s 322.1req/s
エラーレート 0.01% 0.00%
30スレッド latency(平均値) 5 13
latency(中央値) 5 13
スループット 3823.4req/s 1903.9req/s
エラーレート 0.00% 0.00%

nginxは環境に左右されずにそれなりの性能を出す。
apacheは負荷<リソースな状態なときに高い性能を出す(ようにみえる。)
ちょっと気になったのでm1.largeで更に大きな負荷(500スレッド)をかけてみた。

  • m1.large
計測項目 apache nginx
500スレッド latency(平均値) 83 24
latency(中央値) 23 18
スループット 5118.7req/s 9697.2req/s
エラーレート 15.78% 0.00%

やはり負荷が高なくなってくるとリソースが比較的豊富なm1.largeでもapacheの性能が落ちてきた。

まとめ

nginxは少ないリソースでも安定した高いスループット性能を提供してくれる。
apacheと違ってリソースが潤沢でもレイテンシーが小さくなることはないが、逆にリソースが貧弱でもレイテンシーが大きくなりにくい。

という感じでしょうか。

EC2にfluentdをいれてapacheのアクセスログをs3に保存してみる。

ruby1.9.2以降の環境を作る

fluentdにはruby1.9.2以上が必要らしいのでruby1.9.xをインストール。
rvmで1.9.3をインストールしました。
ちなみにこの記事を書いてる時点でのAmazon Linuxrubyは1.8.7。
rvmでruby環境をインストールする場合、fluentdのプラグインに必要なライブラリを、
事前にOSにインストールしておかないまずい。今回の場合、以下のライブラリが必要。
libxml2-devel, libxslt, openssl

$ curl -L get.rvm.io | bash -s stable
$ export PATH=$PATH:~/.rvm/bin
$ source ~/.rvm/scripts/rvm
$ rvm install 1.9.3
$ rvm use 1.9.3
$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]

fluentdのインストール

gemをつかってfluentdをインストール

gem install fluentd
.
.
.
Successfully installed msgpack-0.4.7
Successfully installed json-1.7.5
Successfully installed yajl-ruby-1.1.0
Successfully installed iobuffer-1.1.2
Successfully installed cool.io-1.1.0
Successfully installed http_parser.rb-0.5.3
Successfully installed fluentd-0.10.25

いろいろ一緒にインストールされた。

ひとまず動かしてみる

$ fluentd --setup ./fluent              # configファイルが作成される
Installed ./fluent/fluent.conf. 
$ fluentd -c ./fluent/fluent.conf -vv & # これでfluentdが起動する
$ echo '{"json":"hello fluentd"}' | fluent-cat debug.text
2012-09-20 08:00:34 +0000: plugin/in_forward.rb:139:initialize: accepted fluent socket object_id=19099020
2012-09-20 08:00:34 +0000 debug.text: {"json":"hello fluentd"}
2012-09-20 08:00:34 +0000: plugin/in_forward.rb:180:on_close: closed fluent socket object_id=19099020

configファイルを見ると下記のような記述になっているので、上記のように標準出力にjsonが表示されてるのでOKとおもわれる。

## match tag=debug.** and dump to console
<match debug.**>
  type stdout
</match>

あと、こんなconfigファイルの記述があったのでhttp経由でのログ出力もためしてみた。

# HTTP input
# http://localhost:8888/<tag>?json=<json>
<source>
  type http
  port 8888
</source>

こんな感じ。

$ curl http://localhost:8888/debug?json=%7b%22title%22%3a%22hello%20fluentd%22%7d
2012-09-20 08:12:56 +0000 debug: {"title":"hello fluentd"}

fluentdでapacheのアクセスログを監視するように設定する

fluentd-plugin-s3をインストール

$ gem install fluent-plugin-s3
.
.
.
Successfully installed uuidtools-2.1.3
Successfully installed multi_json-1.3.6
Successfully installed multi_xml-0.5.1
Successfully installed httparty-0.9.0
Successfully installed nokogiri-1.5.5
Successfully installed aws-sdk-1.1.4
Successfully installed fluent-plugin-s3-0.2.2
7 gems installed
.
.
.

いろいろインストールされた。

次にfluentdのconfigファイルを書く

<source>
  type tail
  format apache
  path /var/log/httpd/access_log
  tag apache.access
</source>

<match apache.access>
  type s3
  aws_key_id YOUR_AWS_ACCESS_KEY
  aws_sec_key YOUR_AWS_SECRET_KEY
  s3_bucket factory-fluentd
  s3_endpoint s3-ap-northeast-1.amazonaws.com
  path /
  buffer_path /tmp/fluentd_s3
  time_slice_format %Y%m%d-%H
  time_slice_wait 10m
  #flush_interval 5s これを書くと、timesliceを無視して指定したインターバルごとにs3にflushされる。
  utc
</match>

これでapacheにアクセスしてログを吐かせるとs3にちゃんとオブジェクト(ファイル)ができあがってました。便利。
f:id:imai-factory:20120927000129j:plain


ログも1行ずつs3に書きに行くわけではなくてある程度バッファして書き込んでいってくれるのでs3のAPI叩きすぎてクラウド破産、なんてことにはならずに済みそうですね。

あとは、転送失敗時の処理とか、バッファファイルのためのディスク領域が足りなくなっちゃった時の対処とか気になるところですが今回はこれでおしまいということで。

PHP5.3で無名関数を使う

PHP5.3の無名関数でちょっとハマったのでメモ。
どうやら無名関数(だけじゃなくて普通の関数もだと思うけど。)はPHPの実行前のフェーズで検証がされる模様。

ちゃんと動く。

<?php
$a = array(1,2,3,4,5);
$b = array_map(function($item){return $item * 10;},$a);

print_r($b);

/*
Array
(
    [0] => 10
    [1] => 20
    [2] => 30
    [3] => 40
    [4] => 50
)
*/

これがうまく動かない。

  • $bがarrayじゃないと言われてる。これって、無名関数の初期化がPHP実行時の一番最初のほうのフェーズで行われているということなんだろうか。
<?php

$a = array(1,2,3,4,5);
$b = array();
array_map(function($item){array_push($b, $item * 10);},$a);

print_r($b);

/*
[23-Aug-2012 05:01:33 UTC] PHP Warning:  array_push() expects parameter 1 to be array, null given in /home/aaa/array.php on line 5
*/

これはもちろん大丈夫だった。

<?php

$a = array(1,2,3,4,5);
$b = array();
foreach($a as $item){
    array_push($b, $item * 10);
}

print_r($b);


/*
Array
(
    [0] => 10
    [1] => 20
    [2] => 30
    [3] => 40
    [4] => 50
)
*/

というか、PHPは関数を実行前に検証しますよっていうだけの話だったのかも。

LLでのDNSルックアップはどこかにキャッシュされるのか。

rubypythonphpperlで試してみた。
それぞれの言語ごとに下記のコードを動かしながら、

tcpdump dst port 53

でチェックしてみた。結果としてはすべての言語においてDNSレコードはキャッシュされることなく毎回DNSルックアップしてた。JavaだとVM上にDNSレコードがキャッシュされるらしい。

LLだと毎回DNSルックアップされるということがわかったので、通信処理のオーバーヘッドが気になる時、もしくは気にしなきゃいけないくらいの頻度で通信するようなアプリケーションを使うならhostsに書くなどがよさげ。

逆にDNSを使った負荷分散の時は、このへん特にケアしなくて良い感じですね。

  • php
<?php
require("HTTP/Request.php");

$args = $_SERVER["argv"];
$url  = $args[1];

$http = new HTTP_Request($url);

$count = 0;
for(;;){
    $response = $http->sendRequest();
    print $count++ . "\n";
    sleep(5);
}
#!/usr/bin/perl

use strict;
use warnings;

use LWP::UserAgent;

my $ua = LWP::UserAgent->new();

my $count = 0;
while(1){
    $ua->get($ARGV[0]);
    print $count++ . "\n";
    sleep(5);
}
from urllib import urlopen
import sys
import time

argvs = sys.argv
count = 0

while True:
    urlopen(argvs[1])
    count += 1
    print count
    time.sleep(5)
require 'net/http'
require 'uri'

url = URI.parse(ARGV[0])

count = 0
while 1 > 0
    Net::HTTP.start(url.host, url.port){|http|
        http.get('/')
    }
    sleep 5
end