ワンランク上の負荷対策を Web アプリに実装するには・・・(Sledge編)

最近、お仕事で悩ましいのがデータベース負荷。結局のところ、Web サービスでボトルネックになるのは、バックグラウンドの DB 処理。特にどうしようもないのが、更新系リクエスト。つまりはマスターDB。

既に多くのところが採用している構成と思いますが、MySQL とかでよくやる手段といえば、

  • 参照系は、レプリケーション機能を使って参照系DBを用意して負荷分散。マシンを増やせば負荷に対応可能。
  • 更新系のクエリーだけは、できる限り高スペックなマシンを用意してマスターDBを構築して一手に引き受ける。増設困難で悩ましい。

もうちょい頭をひねれば、機能毎にマスターDBを分散させたり、ユーザ ID とかでパーティショニングしたりと、アプリ層で振り分ける。MySQL に限らず、Oracle とかでも同じようなことが言えます。

- スポンサーリンク -

で、マシン負荷を監視という運用業務が必須な日々を送っていた(いや、実際にはPJのメンバーがやってくれているわけですが・・・)のですが、いい加減人件費の無駄遣いをどうにかせねばと思い、アプリ層で DB 負荷を判定しながら処理分岐するなんてロジックを実装することにしました。

本当は、ちゃんとモジュールにして配布したかったのですが、Sledge 使ったアプリなので簡易的に BEFORE_DISPATCH で register_hook して実装しちゃいました。Net::SNMP 使って DB サーバの LoadAvg を計測してます。

Net::SNMP で DB サーバの負荷を見ながら処理を分岐する方法(Sledge編)

Config/_common.h
$C{SNMP_TARGET} = 'DBサーバのIP';
$C{SNMP_COMM} = 'public';
$C{SNMP_PORT} = '161';

Page/MyApp.pm

use Net::SNMP;
use Sledge::Plugin::ScratchPad; __PACKAGE__->register_hook( BEFORE_DISPATCH => sub {
my $self = shift;
my $config = $self->create_config; ## Net::SNMP session の確立
my ($session, $error) = Net::SNMP->session(
-hostname => $config->{snmp_target} || 'localhost',
-community => $config->{snmp_comm} || 'public',
-port => $config->{snmp_port} ||161
) or die $error;
## loadavg を取得
my $request = '1.3.6.1.4.1.2021.10.1.5.1';
my $result = $session->get_request( -varbindlist => [$request] ); if(defined($result)) {
$self->pad->param(SnmpLoadAvg => $result->{$request});
$self->tmpl->param(SnmpLoadAvg=> $result->{$request});
$session->close;
} else {
$session->close;
Sledge::Exception::SomeError->throw($session->error);
}
}, }

これで、プログラムの処理を記述する際に、MyApp クラス内からは、$self->pad->param('SnmpLoadAvg') で LoadAvg の値毎に処理分岐させることができるし、View の TT 内でも [% IF SnmpLoadAvg>100 %] とかすれば、ロードアベレージが1を超えていた場合に見た目を変更することが可能となります。

突貫で作ったものなので、Net::SNMP の TimeOut 処理とかちゃんと作り込んでませんが、これだけで負荷監視業務という点では、それなりに工数削減を実現することが可能となりました。

このモジュールのねらいとするところは、サーバがお腹一杯になる前に、「ただいま混み合ってます。ちょっとまってね。」的なメッセージを出力することで、負荷が原因でサービスがダウンすることを未然に防ぐという点です。

もちろん、 「混み合ってます。は格好悪い」 です。でも 「サービスダウンはもっと格好悪い」 と思ってます。

実際ユーザへの影響もサービスダウンの方が大きいでしょう・・・。現状、僕のお仕事的には、かなり負荷の高い管理者操作(いわゆる大量のオンラインデータ処理)に対して、本ロジックが動作するようになっています。ユーザ向けのトランザクション処理にはまだ組み込んでません。

サーバの負荷を計測してアプリの挙動を変更する。これでワンランク上の負荷対策を構築することが可能となると思います。Sledgeや Catalyst のプラグインとして欲しいところなので、暇を見つけて実装したいところです。(が、年度内はむりか・・・)

- スポンサーリンク -