2010年8月アーカイブ

調査のついでに作ってみた。cのgearmandで動いてます。PP版は確認してない

gearmandのステータスは、telnetでアクセスして、statusコマンドを発行するととれる

$ telnet localhost 4730
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
status
resize     3       3       78
.

数値は、キュー数、実行中のキュー、Workerの数となってる。キュー数には実行中のキューも含むらしい。

ソースはgist

追記
元記事はDBサーバだったようですね。読んでないのバレバレでした。ただ、アプリケーションサーバでforkを多用しサーバが重いケースは何回か見てきているパターンなので負荷の高いアプリケーションを作成するときの要注意ポイントとして読んでいただければと思います。
/追記

クラウドがネットワークゲーム開発者にもたらしてくれたもの - Keep Crazy;shi3zの日記

クラウドはあまり関係がないんだけど、CPUのSystemを使い杉ってことで、どういうことをやるとSystemを使うのか再現実験。おそらくfork(2)が原因だと予想。flashの生成でswfmillコマンドを叩いているとか

以下のコードは無限ループでforkを行っています。子プロセスは何もせずにすぐに終了し、親プロセスは子プロセスの終了を確認した後、すぐにforkを行います。

#!/usr/bin/perl

use strict;
use warnings;
my $pid;
while(1) {
    $pid = fork;
    if ( $pid ) {
        waitpid( $pid, 0 );
    }
    else {
        exit;
    }
}

waitpid( $pid, 0 );

このコードを実行し、CPU使用率をmpstatで見てみます

$ mpstat 5  
Linux 2.6.28-15-server (vs1-1)  08/26/10        _x86_64_        (2 CPU)

01:13:55     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
01:14:00     all   10.20    0.00   40.10    0.00    0.00    0.10    0.00    0.00   49.60
01:14:05     all    8.00    0.00   42.40    0.00    0.00    0.10    0.00    0.00   49.50
01:14:10     all    8.30    0.00   40.40    0.00    0.00    0.00    0.00    0.00   51.30
01:14:15     all    8.80    0.00   39.70    0.00    0.00    0.00    0.00    0.00   51.50
01:14:20     all    9.60    0.00   35.10    0.00    0.00    0.00    0.00    0.00   55.30

Systemに40%、Userに10%ぐらい。同じようなCPU使用率が再現できていると思いますが、どうでしょう? forkは新しいプロセスを作成するkernel内部の処理。Systemはkernelが使用したCPU時間から計算されます。

あわせて読みたい: ライブドア、携帯電話向けのソーシャルゲーム環境に最適な、 フラッシュコンテンツの動的合成配信ASPサービス 「DATAHOTEL(データホテル) FLDS(エフエルディーエス)」の提供を開始

鉄分が高い息子に、奥さんのお母さんと弟さん(おばあちゃんと叔父さん?)からプラレールの成田エクスプレスを頂きました。

R0013286.jpg

大喜びで電車や車のおもちゃと並べて(連結して?)遊んでます。 東海道線、新幹線つばめに続いて3両目のプラレールです。成田エクスプレスは近所でも見ることができるのでイイネ!(ソーシャルフィードバック)

技術評論社のgihyo.jp上での連載「memcachedの活用と運用 実践編」の第二回が公開されました。今回の内容はmemcachedを安全に運用するために気を付けた方が良い、セキュリティと脆弱性の話です。

memcachedの活用と運用 実践編:第2回 memcachedのセキュリティと脆弱性|gihyo.jp … 技術評論社

連載記事の最初で紹介しているスラッシュドットのもとネタは結構ひどい(?)事になってます。これを笑って見れるようにしておきたいものです。

後半にはMemcached Injectionの話題を紹介していますが、大きな問題になることは少ないかなぁと思っています。それは外部からkeyとdataをセットで指定できるようなことはWebアプリケーションにおいてはなかなか無いんじゃないかと思うからです。それでも気持ちいいものではないので、memcachedを利用している方は一度確認をお勧めします。

1つだけ思いついているアレゲなInjection利用法としてはmemcachedのincrを使ったアクセスブロック破りです。ほとんどの場合、アプリケーションサーバの前にリバースプロキシーを設置しますが、その際アプリケーションサーバでアクセス元のIPアドレスを取得するのにヘッダのX-Forwarded-Forを使うことがあります。

my $cnt = $mem->incr( $ENV{X_FORWARDED_FOR} );
if ( $cnt > $LIMIT ) {
    return "402 Payment Required";
}

こんな感じで連続アクセスを防ぐことがあると思いますが、この際、X_FORWARDED_FOR に「スペース」が含まれることがあります。cacheのkeyにスペースが入るとmemcachedのプロトコルエラーとなりincrは正しく動きません。結果として連続アクセスブロックも機能しなくなります。情報漏洩にはなりませんがWebアプリケーションの運営上、何か問題がでるかもしれません。

どうやって、この脆弱性を防ぐかは、連載に書かせていただいてますので、ぜひ読んでくださいませ〜。

handlersocket plugin や mycached を使えば memcached は不要か、それとも使うべきケースがあるか。考察せよ [10点] kazuho (Kazuho Oku)

http://twitter.com/kazuho/status/21477219149

考えて答えてみる。

HandlerSocketやmycachedを利用し、MySQLへの接続数が数万単位で行えるようになったり、より多くのクエリ数が発行できるようになっても、memcachedは不要ではないし、使うべきケースもあります。

memcachedは単なるKVSではなく、ExpiresとLRUがついたキャッシュサーバです。キャッシュオブジェクトには期限を付ける事ができ、期限が過ぎたキャッシュは無効にされ、またアクセスがされていない不要になったオブジェクトは削除され、空いたスペースは新しいキャッシュオブジェクトのために再活用されます。これらが自動で行われるのがmemcachedです。そしてこの特徴をもっとも生かす使い方がこそが、汎用的に利用できる一時的なデータ保存、キャッシュだと考えます。

memcachedをWebアプリケーションで利用する際に、よくあるパターンとしてORM(ORマッパー)にmemcachedを組み込み、PRIMARY KEYなどの検索結果をそのままmemcachedに格納することがあります。しかし、この使い方ではデータソース(データベース)の出力結果をキャッシュするだけです。memcachedにはもっと多くの種類のデータ、なんらかの処理結果や処理途中のデータも期限をつけて格納することができます。

memcachedが有効であるパターンとして以下が考えられます。

  • データベース以外のデータソース。外部APIなど
  • テキストデータの変換、データ集計など比較的重い処理の結果
  • 連続アクセスblockなどの軽いセッション処理

外部APIのデータでmemcachedを利用するケースとしてはソーシャルアプリケーションが上げられます。ソーシャルアプリケーションにおいてはOpenSocial APIに問い合わせを行いユーザデータを取得することがありますが、その際ユーザのアクセスがあるたびにAPIへ問い合わせを行っていては、レスポンス速度に影響でますし、サービスをスケールさせていくことができません。そこでOpenSocial APIの問い合わせ結果をソーシャルアプリケーションを提供するサーバ側に置き、2度目以降はそれを参照することが必須となります。 mixiアプリではOpenSocial APIで取得したユーザデータの保存は24時間までとされており、24時間以内に更新または削除が必要となります。データベース等にOpenSocial APIの問い合わせ結果を入れてしまうと、別途cronで削除または更新することになりますが(この削除スクリプトの設計もデータが多くなると難しい)、memcachedであれば、有効期限を24時間としてキャッシュするだけで、(memcachedの容量が足りていれば)有効期限までデータを保持し、自動的に有効期限が切れればキャッシュの参照ができなくなります。削除されたデータは次回ユーザのアクセスがあった際に再度OpenSocial APIに問い合わせればサービスに影響はでません。

また、有効期限がきたら削除されることを期待した利用方法として、大量のデータからの一部のデータを抜き出すときや、最新情報のキャッシュがなどがあげられます。twitterのフォロワーのような多くのユーザリストから、ランダムに数件を表示したいと言ったときに、毎回すべてのフォロワーのリストをデータベース上でランダムに並べ替え、一部だけ抜き出して利用するのはデータベースサーバの負荷が大きくなることが予想できます。そこでフォロワーのリストを一度そのままmemcachedに入れ事も考えられますが、全部で数万となる可能性があるリストが毎回アプリケーションサーバとmemcachedサーバの間で転送されるのはそれはそれで負担が大きくなります。そこで表示する全件よりすくなく、件数よりも若干多い表示用リストを生成し、それを有効期限をつけてmemcachedに入れることにします。表示するときはこの表示用リストからランダムに表示します。これだけだとすべてからフォロワーからランダムに表示とは言えませんが、表示用リストは有効期限があるため、指定した時間後にmemcached上の表示用リストが無効になり、再度全件からリストを作り直すことになるので長い時間として見れば、ランダムが実現できます。この方法であれば無駄なデータのやり取りは少なく負荷も増えないと思われます。

すこし以前から言われていることですが、ORMをMVCモデルにおけるModelそのものとして扱うことで、本来Modelで扱うビジネスロジックをControllerに書いてしまい、Controllerのロジックが増大し、結果的にメンテナンスがしにくい、拡張が難しいコードが生まれてしまいがちです。

mvc.png

この状態でmemcachedをORMに組み込んでしまうことで、より汎用的な使い方ができないままであり、無理にORMの外でもmemcachedを利用しようとすると、余計にControllerの厚さが増していってしまう。その対策として、Modelを見直しを行い、ORM、DBI、Web API、他のKVS、そしてmemcachedなどマルチソースでビジネスロジックを記すレイヤーとしての位置づけとすることを考えてみたい。多くの情報を扱う今、こちらの考え方が自然に設計ができると考えます。

mvc2.png

多くのアプリケーションでは、データベースの入出力が処理の大部分を占めていると思われますが、Webアプリケーションで多様なデータを扱うようになってくる今、memcachedをより汎用的に使うことでまだまだ高速なレスポンスが実現できるはずです。

かなり脱線しましたが、HandlerSocketやmycachedでMySQLの処理が高速になったとしても、memcachedが無用になるわけではなく、高速で汎用的なキャッシュとしてWebアプリケーションのさまざまな場所で活躍できると考えています。

memcachedを落とすのは夏休みの課題だと聞きましたkazeburoです

さて、まだまだmixiのmemcachedによる障害がホットな話題の中、技術評論社様のWebサイト、gihyo.jpにてmemcachedの連載を開始しました。2年前に前坂徹氏とgihyo.jp上で連載を行っているので、今回は再連載となります。

特集:memcachedの活用と運用 実践編|gihyo.jp … 技術評論社

今回の連載では、実際にmemcachedを利用、運用している方に向けて実践的な内容となる予定です。

1回目は、以前の連載時の最新バージョンであったmemcached 1.2.5と現在の最新バージョンである 1.4.5の起動オプションを比較しつつ、実際の運用で役に立ちそうなオプションを紹介しています特にmixiの障害の引き金となった同時接続数のあたりはmemcachedを利用している方は要チェックだと思われます。

次回は脆弱性や安全に使うための対策について紹介します。

あわせて読みたい

「memcached 1.4の到来」は前坂氏による連載です

先週のmixiの大規模な障害は、memcachedに対する接続が非常に多いところから発生したようなので、CloudForecastでその接続数をモニタリングできるようにしてみました。

(mixiではたぶんおそらくmemcachedは専用のサーバとなっているので、通常のTCP Established数がそのんままコネクション数になるはず)

グラフは以下のように出力されます

memcached_conn.png

赤いラインが起動時に指定した -c の値。

ところで、このmemcachedの起動オプションを取得する方法は今までないものだと思っていたのですが、memcached 1.4以降なら「stats settings」というコマンドで取得できるようです。

% telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
stats settings
STAT maxbytes 67108864
STAT maxconns 1024
STAT tcpport 11211
STAT udpport 11211
STAT inter NULL
STAT verbosity 0
STAT oldest 0
STAT evictions on
STAT domain_socket NULL
STAT umask 700
STAT growth_factor 1.25
STAT chunk_size 48
STAT num_threads 4
STAT stat_key_prefix :
STAT detail_enabled no
STAT reqs_per_event 20
STAT cas_enabled yes
STAT tcp_backlog 1024
STAT binding_protocol auto-negotiate
STAT auth_enabled_sasl no
STAT item_size_max 1048576
END

この機能、知らなかった!と思ってぐぐったら、gihyo.jpの前坂氏の連載にすでに紹介されてた。読んでないのバレタ!

あとはNagiosプラグインを書いて、一定のコネクション数よりも大きくなったらアラートとかあると良いかもですね。

もはや親の趣味

最近、息子は新幹線の本に夢中。ページめくっては大興奮な毎日です。そんな息子に(という名目で?)九州新幹線800系 つばめの6両編成セット買ったよ

R0013268.jpg

かなりディテールに凝っていてかっこいい!

E217系東海道線車両に続いて2両目のプラレール。まだ線路はありません

息子が夢中な本はこちら

2010年代にどのMTAを使うのがいいかよくわからないkazeburoです

qmailのキュー数をCloudForecastで監視するためのモジュールを書いてみました。

gistです

このリソース定義を使うには、メール配送サーバのsnmpd.confに

extend qmail /var/qmail/bin/qmail-qstat

を追加する必要があります。snmpdがroot以外で実行されている場合は、sudoとか使えばいいのかな。

snmpgetでextendで指定したコマンドの実行結果をとるには、

$ snmpget -c public -v 2c myserver 'nsExtendOutputFull."qmail"'
NET-SNMP-EXTEND-MIB::nsExtendOutputFull."qmail" = STRING: messages in queue: xxxx
messages in queue but not yet preprocessed: 0

のような方法が使えます。しかし、perlのSNMP.pmモジュールでは「qmail」の指定をうまく行う事ができませんでした。

my $s=SNMP::Session->new(
    Community=>"public",
    Version=>"2c",
    DestHost=>"myserver"
);
print $s->get(["nsExtendOutputFull",q!"qmail"!]); #NOSUCHINSTANCE

そこで、一度extendの設定に関する情報が入るnsExtendConfigTableを取得し、qmailコマンドのoidを調べてからgetを行うようにしています。

print Dumper( $s->gettable('nsExtendConfigTable') );
=comment
$VAR1 = {
      '5.113.109.97.105.108' => {
                                  'nsExtendArgs' => '',
                                  'nsExtendToken' => 'qmail',
                                  'nsExtendCacheTime' => '5',
                                  'nsExtendInput' => '',
                                  'nsExtendStatus' => '1',
                                  'nsExtendExecType' => '1',
                                  'nsExtendRunType' => '1',
                                  'nsExtendCommand' => '/var/qmail/bin/qmail-qstat',
                                  'nsExtendStorage' => '4'
                                }
};
# 5.113.109.97.105.108がoid
=cut
$s->get(['nsExtendOutputFull', '5.113.109.97.105.108']);

この方法は汎用的に使えそう