Hatena::ブログ(Diary)

(ひ)メモ このページをアンテナに追加 RSSフィード

2013-01-21 (Mon)

aws-cliのラッパーモジュールを作りました - AWS::CLIWrapper

先日公開されたaws-cliPerlのラッパーモジュールを作りました。


PerlでAWS EC2のAPIを叩くにはNet::Amazon::EC2が便利です。

一昔前に比べると多くのAPIに対応しているし、パッチ(pullreq)を送るとすぐにお返事が返ってくるのでいい感じです。

が、VPC関連のAPIサポートが乏しく、ちくちくパッチを送るのもしんどいなぁと思っていたところ、先日公開されたAWS本家のaws-cliが、

  • Pythonで書かれている
    • 既存のec2-*コマンドはJavaなんで起動時に時間がかかる
  • レスポンスがJSONなのでparseしやすい
  • awsコマンドだけでEC2やELBなどいろんなサービスに対応してる

と、いい感じだったんで週末サクッとラッパーモジュールを書いてみた次第です。

こんな感じ:

use AWS::CLIWrapper;

my $aws = AWS::CLIWrapper->new(
    region => 'us-west-1',
   );

my $res = $aws->ec2('describe-instances');

if ($res) {
    for my $rs ( @{ $res->{reservationSet} }) {
        for my $is (@{ $rs->{instancesSet} }) {
            print $is->{instanceId},"\n";
        }
    }
} else {
    warn $AWS::CLIWrapper::Error->{Code};
    warn $AWS::CLIWrapper::Error->{Message};
}

ほぼaws-cliのコマンドにまるなげで、やってることは

  • JSONをPerlのHashRefにして返す
  • エラーだったら undef 返して $AWS::CLIWrapper::Error に詰めて返す

ぐらいなんですが、生でコマンド実行するよりかは楽だと思います。


ちなみに、aws-cli(0.4.5)でregion指定の環境変数 AWS_DEFAULT_REGION が効かないのは、

の2行パッチで治るので、/usr/{,local/}lib/python2.6/site-packages/awscli/clidriver.py とかにある clidriver.py をいじればいいと思います。

Enjoy!

2013-01-16 (Wed)

perlのデバッグビルド

perlの配布物の中にあるINSTALLの"Building a debugging perl"セクションにある通り、-DDEBUGGING=ナニガシを指定すればよい。

指定する値によって、

  • "perl internal debugging code"とデバッグシンボルの両方が有効になったもの (-DDEBUGGINGもしくは-DDEBUGGING=both)
  • デバッグシンボルが有効になったもの (-DDEBUGGING=-g)

とできあがるperlが異なる。

"perl internal debugging code"を有効にすると、"much, much more slowly"になるとINSTALLには書かれている。

Note that a perl built with -DDEBUGGING will be much bigger and will run

much, much more slowly than a standard perl.


ビルド済みのperlが、どんなデバッグオプションでビルドされたかを確認するには、perl -Vをみればよい。

$ perl -V
Summary of my perl5 (revision 5 version 16 subversion 2) configuration:

  Platform:
    osname=linux, osvers=2.6.38-13-generic, archname=x86_64-linux
    uname='linux goa 2.6.38-13-generic #54~lucid1-ubuntu smp wed jan 4 13:00:37 utc 2012 x86_64 gnulinux '
    ...
  Compiler:
    cc='cc', ccflags ='-DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2 -g',
    cppflags='-DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ...
Characteristics of this binary (from libperl):
  Compile-time options: DEBUGGING HAS_TIMES PERLIO_LAYERS
                        PERL_DONT_CREATE_GVSV PERL_MALLOC_WRAP
                        ...
  Built under linux
  ... 

着目するのは「Compiler:」の「optimize」と、「Compile-time options:」の2つ。

  • perlbrew install --notest perl-5.16.2
  • perlbrew install --notest perl-5.16.2 --as=perl-5.16.2-both -DEBUGGING=both
  • perlbrew install --notest perl-5.16.2 --as=perl-5.16.2-g -DEBUGGING=-g

の3つのperlでここらへんの値がどうなってるかは次の通り。

Compiler: optimizeCompile-time options
standard-O2 なし
-g -O2 -g なし
both -O2 -g DEBUGGING

「-O2じゃなくて-O0がイイ!」という向きは、

  • perlbrew install --notest perl-5.16.2 --as=perl-5.16.2-O0 -DDEBUGGING=-g -Doptimize=-O0

とかするといいと思います。

注意点としては:

  • Perl 5.8.9では-DEBUGGING-DDEBUGGINGの別名として使えますが、5.8.8では-DEBUGGINGは使えません。-DDEBUGGINGを指定しましょう。
  • Perl 5.8.8では-DDEBUGGING=-gが効きません。指定してもデバッグシンボルがつきません。デバッグシンボルをつけるには、-Doptimize='-O2 -g'を指定すればいいのですが、optimizeに-gが含まれているとDEBUGGINGまで有効になってしまいます。。。デバッグシンボルだけつけたいのですが、install時のオプションではどうしようもなさそうだったので、Configureにパッチ(↓のパッチはCentOSperlから拝借しました)を当てて(perlbrewの場合は、patchperlにDEBUGGINGを有効にしないようにするパッチを当てて)ビルドするようにしました。。
    • 5.8.9なら-DDEBUGGING=-gが効きます。
--- perl-5.8.7/Configure.orig   2005-08-28 18:48:03.000000000 -0400
+++ perl-5.8.7/Configure        2005-08-28 18:49:28.000000000 -0400
@@ -4707,9 +4707,6 @@
        case "$gccversion" in
        1*) dflt='-fpcc-struct-return' ;;
        esac
-       case "$optimize" in
-       *-g*) dflt="$dflt -DDEBUGGING";;
-       esac
        case "$gccversion" in
        2*) if test -d /etc/conf/kconfig.d &&
                        $contains _POSIX_VERSION $usrinc/sys/unistd.h >/dev/null 2>&1

packageごとのメモリ使用量(と増分)を確認できる Plack::Middleware::MemoryUsage

packageごとのメモリ使用量とリクエストを処理する前後の増分を確認できるPlack::Middlewareを作りました。

時間が経つとぶくぶく太るプロセスがいるときに、犯人特定の助けになると思います。

要、B::TerseSizeB::Size2::Terse, Devel::Symdumpです。

新しめ(5.10以降?)のPerlでB::TerseSize (B::Size)がエラーになってインストールできないときは、

のを入れてください。

を入れてください。

使い方は、

  use Plack::Builder;
  builder {
      enable "MemoryUsage",
          callback => sub {
              my ($env, $res, $before, $after, $diff) = @_;
              my $worst_count = 5;
              for my $pkg (sort { $diff->{$b} <=> $diff->{$a} } keys %$diff) {
                  warn sprintf("%-32s %8d = %8d - %8d [KB]\n",
                               $pkg,
                               $diff->{$pkg}/1024,
                               $after->{$pkg}/1024,
                               $before->{$pkg}/1024,
                              );
                  last if --$worst_count <= 0;
              }
          };
        $app;
  };

な感じで、

  パッケージ名                         増分  req処理後  req処理前
  ====================================================================
  MemoryEater                         36864 =    36873 -        9 [KB]
  B::TerseSize                          191 =      645 -      453 [KB]
  B::AV                                  21 =       37 -       16 [KB]
  B::HV                                   4 =       18 -       14 [KB]
  B::NV                                   0 =        8 -        8 [KB]

な出力が得られます。MemoryUsageをenableするときは、builderの中で一番最初に指定して一番外側のMiddlewareとして処理されるようにした方がいいんでないかと思います。

DESCRIPTIONにも書きましたが、MemoryUsageをenableにすると、性能劣化が炸裂するので、開発環境でのみenableにするとか、本番環境でenableにするならPlack::Middleware::Conditionalを使ってある程度まびいた方がいいと思います。

  builder {
      ## 1/3の確率で enable
      enable_if { int(rand(3)) == 0 } "MemoryUsage",
          callback => sub {
          ...
  builder {
      ## リクエストヘッダに X-Memory-Usage があったときのみ enable
      enable_if { exists $_[0]->{HTTP_X_MEMORY_USAGE} } "MemoryUsage",
          callback => sub {
          ...

謝辞

Plack::Middleware::MemoryUsageは、@ さんのPlack::Middleware::GTop::ProcMemインスパイアです!!

2013-01-08 (Tue)

check_mysql_queryで範囲指定 - InnoDBの空き容量を監視する

なぎおす!

な!なんとなく〜

ぎ!ギャグでごまかそうと〜

お!おっさんどもが〜

す!すべってゆく〜

ハイ!ガショー!!



Nagios (nagios-plugins) にcheck_mysql_queryというのがあります。

MySQLに任意のクエリを発行して、その結果を元に監視の可否をするプラグインです。

「SELECT 1」とかを発行して期待した応答が返ってくるかとか死活監視に使えますが、結果が数値の場合、範囲内/外にあるかどうかの監視もできます。

例えば、(innodb_file_per_tableしていない場合の)InnoDBの空き容量を調べる設定はこんな感じになります。

前提:

  • "infra"というデータベースに、InnoDBの"health"というテーブルがある
  • MySQLのユーザー"health"は、infra.healthにアクセスできる権限を持っている
  • 空きが、8GBを切ったらcritical、10GBを切ったらwarning
define command {
  command_name  check_mysql_data_free
  command_line  $USER1$/check_mysql_query -H $HOSTADDRESS$ -u health -q 'select data_free from information_schema.tables where table_schema = "infra" and table_name = "health"' -c '@~:$ARG1$' -w '@$ARG1$:$ARG2$' $ARG3$
}

define service {
  host_name            db001
  use                  generic-service
  service_description  MYSQL_DATA_FREE
  check_command        check_mysql_data_free!8589934592!10737418240
  servicegroups        MYSQL
}

Nagiosのプラグインの仕様に、値の範囲を指定する記法があります。

この記法を使って、空きが8G以上、10G以下ならwarning、

-w '@8589934592:10737418240'

空きが負の無限大以上、8G以下ならcritical

-c '@~:8589934592'

となるように設定しています。

ほかにもいろいろ活用できそうですね!!


蛇足#1

check_mysql_queryは-pオプションで接続ユーザーのパスワードを指定できます。

実行中は、psで見ると「-p XXXXX」と潰されているのでパスワードがだれにでも丸見えというわけではないですが、Nagiosの設定ファイル(resource.cfgに書いて、$USERXX$で参照するのがいいと思います)には書かないといけないのでちょっとアレですね。。

$HOMEをうまく設定すれば、~/.my.cnfに書いてもいけるかもしれません。

蛇足#2

サーバーによって確保している表領域の大きさがまちまちだと、空き容量ではなく、空き容量とか使用とかで監視したいわけですが、確保している表領域の大きさって簡単に知る方法ありますかね?

show variablesのinnodb_data_file_pathのibdata1:2G;ibdata2:2G;...から、単位を考慮してサイズを足しこむのが簡単かなぁと思うんですが、MySQLは返すデータの長さに上限があって(うろおぼえ。8KBぐらい?)、深遠な理由で細かく2G刻みで超絶たくさん並べているとちょん切れちゃって正確な値が取れなかったりするんで、ssh db001 'cat /etc/my.cnf|grep innodb_data_file_path'とかしないとかなぁと思ったり。

2003 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 05 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 12 |
2012 | 01 | 02 | 03 | 06 | 08 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 |
2015 | 01 | 02 | 07 | 10 |
2016 | 01 | 05 | 10 | 12 |
2017 | 07 |
2018 | 05 |