Hatena::Groupcside

Cside::StudyMemo このページをアンテナに追加 RSSフィード

メインブログに書くまでもない自分用メモを垂れ流す。日々是勉強也。

カテゴリー

2011-03-11

[][]続・ソケット

IO
:Socket:いい感じにソケット作成などを抽象化してくれる、OOPインターフェイスなモジュール。詳しくは以下を参照。

forkによるマルチプロセスについて

上のサイトでは「マルチスレッド」って解説されてたけど、forkはプロセスのコピーだからマルチプロセスじゃね…?

# listenなsocketを作ってから、

while (1){
    $new_socket = $listening_socket->accept();

    if ( $pid = fork() ){           # 親プロセス

        $new_socket->close();

    } else {                 # 子プロセス
        $listening_socket->close();

        select($new_socket); $|=1; select(STDOUT);

        while (<$new_socket>){
            print $new_socket $_;
        }

        $new_socket->close();
        exit;
    }
}
4引数の select() とは
指定した(複数の)ファイルディスクリプタ(ファイルやソケット、標準入出力などをOSが識別するための番号)に、読み込むべきデータがあるかどうかを調べることができる。
例として、こちらではマルチスレッドなechoサーバを書いている。対してこちらでは、複数のページを並行で読み込んでいる。

2011-03-10

[][]AnyEventでJSONを読み書きするサーバを立てて、通信

引き続きAEの勉強。

listenする側はtokuhiromさんの はてなブログ のコードのままに。

#!/opt/perl/bin/perl
use strict;
use Socket;
use IO::Socket::INET;
use AnyEvent::Socket;
use AnyEvent::Handle;
use YAML;

my $cv = AnyEvent->condvar;

my $hdl;

warn "listening on port 34832...\n";

AnyEvent::Socket::tcp_server undef, 34832, sub {
   my ($clsock, $host, $port) = @_;
   print "Got new client connection: $host:$port\n";

   $hdl =
      AnyEvent::Handle->new (
         fh => $clsock,
         on_eof => sub { print "client connection $host:$port: eof\n" },
         on_error => sub { print "Client connection error: $host:$port: $!\n" }
      );

   $hdl->push_read (json => sub {
        my (undef, $msg) = @_;
        print Dump($msg);
        $hdl->push_write(json => $msg);
        $hdl->push_shutdown();
   });
};

$cv->wait;
はてなブログ

書きこむ側のコードはこんな感じ。

TODO
たぶんこのコードもAEで書ける
use strict;
use warnings;

use Socket;

# ソケットを作成する
my $sock;
socket( $sock, PF_INET, SOCK_STREAM, getprotobyname('tcp' ) )
    or die "Cannot create socket: $!";

my $remote_host = 'localhost';
my $packed_remote_host = inet_aton( $remote_host )
    or die "Cannot pack $remote_host: $!";

my $remote_port = 34832;

my $sock_addr = sockaddr_in( $remote_port, $packed_remote_host )
    or die "Cannot pack $remote_host:$remote_port: $!";

connect( $sock, $sock_addr )
    or die "Cannot connect $remote_host:$remote_port: $!";

my $old_handle = select $sock;
$| = 1;
select $old_handle;

use JSON::XS;
my $json = encode_json {foo => 'bar'};

print $sock $json;

shutdown $sock, 1;

while( my $line = <$sock> ){
    print $line;
}

close $sock;

[]ソケットに関するメモ

サンプルコードPerl入門読みながら理解していく。

ソケットを作成する:socket()

socket( $sock, PF_INET, SOCK_STREAM, getprotobyname('tcp' ) );
第二引数:ドメイン*1
ドメイン範囲
PF_UNIX*2ローカル
PF_INETインターネット
第三引数:タイプ
タイプ通信方式
SOCK_STREAMTCP(信頼性が高い。相手との接続を確認してからデータの交換)
SOCK_DGRAMUDP(頼性が低いですが速い。相手との接続を確認しない)
第四引数:プロトコル番号

TCP、UDPなどのトランスポート層のプロトコルを番号*3で指定する。プロトコル名からプロトコル番号を取得するには、getprotobyname関数を使用する。

ソケットの接続先の情報を作成する

my $remote_host = 'localhost';
my $packed_remote_host = inet_aton( $remote_host )
    or die "Cannot pack $remote_host: $!";
my $remote_port = 9000; 

my $sock_addr = sockaddr_in( $remote_port, $packed_remote_host )
    or die "Cannot pack $remote_host:$remote_port: $!";
IPアドレスやホスト名をバイナリ形式に変換:inet_aton()

IPアドレスやホスト名は文字列のままでは使用できないので inet_aton()*4 関数でバイナリに変換。

ポート番号とIPアドレスをひとまとめにする:sockaddr_in()

ポート番号とIPアドレスをsockaddr_in関数を使ってひとまとめにする。

このようにして作成した $sock_addr が接続のためのconnect関数の引数に渡されることになる。

クライアント側とサーバ側の違い

クライアントは(かなりざっくり書くと)こんな感じで、

# ソケット作ってから、
connect( .... );

print $sock "Hello";

shutdown $sock 1;  # 書込を終了

print $_ for while (<$sock>);

close $sock;

サーバーはこんな感じ。


# ソケット作ってから、
listen( .... );  # 接続を受け付ける準備をする

# 接続を受け付けて応答する
while ( accept( my $sock_client, $sock) ) {
    # クライアントからのデータ読み込み
    my $content;
    $content .= $_ while <sock_client>

    # クライアントへのデータ書き込み
    print $sock_client $content;

    colse $sock_client;
}

補足:コマンドバッファリングについて

他のプロセスとの通信や、ソケットで通信する場合などは、ブロックバッファリングをコマンドバッファリングに切り替える。

ブロックバッファリングは、出力を書き込みバッファに貯めて、蓄積した分を一度に書き出すもの。コマンドバッファリングは、printというコマンドが終わった時点で、書き込みを行うもの。

切り替えのおまじないはこんな感じ。

my $oldfh = select $fh;  # デフォルトの出力ハンドルを変更
$| = 1;  # コマンドバッファリングを有効にする
select $oldfh; # 元のファイルハンドルに選択しなおす。

select関数は、現在のデフォルトの出力先を返却するので、保存しておいて、$| を操作した後、元に戻しておく。

なお、このselect関数は、select(2)のシステムコールであるselect関数とはまた別物らしい。(perl には2種類の select がある - kameidの備忘録 - Sharpen the Saw!

*1:ホスト名とよく似た意味で利用されるドメイン名とは何の関係もないらしい。

*2:PF = Protocol Family

*3:UNIXなら/etc/protocolsにある

*4:aton = ascii network on

2011-03-01

[]サーバ/インフラを支える技術

[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)ちょっとサーバ寄りの話になるとすぐ分からなくなってしまってまずいので、この本を読んでみた。僕がこのあたりの知識に弱いせいもあるだろうが、それにしても濃い内容の本だった。これでだいぶ、はてブやtwitter上で飛び交うネットワーク関連の話は「とりあえず何の話をしてるか」分かるようになったように思う。

で、読みながら用語をひたすらメモしたり調べたりしてた。知らなかった用語とか、知ってたけど理解が曖昧だった/知識が間違っていた用語とかも全部ひっくるめてまとめ。

用語の整理

APサーバ (Application Server)
動的コンテンツを返すサーバ。Apache + mod_perlが動いているサーバなど。
CDN (Content Delivery Network)
コンテンツを配信するためのネットワークシステム。Akamaiなどいくつかの商用サービスが存在する。
ロードバランサ / 負荷分散機
クライアントからのリクエストをバックエンドの複数のサーバに適宜分散する役割の装置のこと。複数のサーバを束ねて1つの高性能な仮想的なサーバに見立てているとも言える。
LVS (Linux Virtual Server)
Linuxで、スケーラブルで可用性の高いシステムをつくろうと目指しているプロジェクト。本来はプロジェクト名だが、慣例的に「LVS」を「Linuxで作ったロードバランサ」という意味に使うこともある。
IPVS (IP Virtual Server)
ロードバランサに不可欠な「負荷分散」の機能を実現するもの。LVSの成果物。 
NIC (Network Interface Card) / LANカード / ネットワークカード / ネットワークアダプタ
本来は、ネットワーク機能を追加するためのカードを指す言葉だが、カードやオンボードを問わず、ネットワークインターフェースの総称として使われることもある。
Netfilter
ネットワークパケットを操作するためのフレームワーク。iptables(パケットフィルタリングを行う)やIPVSもこのNetfilterの機構を利用している。
OSI参照モデル (Open Systems Interconnection)
ネットワーク層を説明したモデル。(レイヤ7:アプリケーション層、レイヤ4:トランスポート層、レイヤ3:ネットワーク層、レイヤ2:データリンク層など。) また「L2スイッチ」など、レイヤnは「Ln」と表記することもある。
VIP (Virtual IP Address) / 仮想IPアドレス
物理的なサーバやNICではなく、不動的にサービスや役割に割り当てられるIPアドレスのこと。
可用性 (Availablity)
システムの停止しにくさのこと。
サーバファーム
たくさんのサーバが集まってできたインフラシステムのこと。
スイッチングハブ / L2スイッチ
ネットワークの中継機器であるハブの一種。送り先を解析し、関係のあるデータだけを送信するのでセキュリティ上よい。 
スケールアウト
サーバを複数台並べて分散することにより、システム全体の性能を向上させること。
スケールアップ
サーバ単体の性能を上げることにより、システム全体の性能を向上させること。
ステージング環境
本サービスに投入する前に、最終的な動作確認を行うための環境。
単一故障点
そこが故障するとシステム全体が停止してしまう個所。
ネットワークセグメント
ブロードキャストパケットが届く範囲のネットワークのこと。
ネットワークブート
ネットワーク越しに、起動に必要なブートルータやカーネルイメージなどを入手して起動すること。ちなみにPXEは、ネットワークブートを実現するための仕様のひとつ。
パケット / IPパケット
IPにおけるデータの最小単位の塊。
フェイルオーバ
冗長化されたシステムにおいて、Activeなノード(サーバやネットワーク機器など)が停止した際に、自動的にBackupノードに切り替わること。(手動でやること:スイッチオーバ)
フェイルバック
Acriveノードが停止しフェイルオーバした状態から、もとの正常な状態に復帰すること。
フレーム / Ethernetフレーム
おもにEthernetにおけるデータの最小単位の塊。
ブロックされる
I/O処理待ちのため、他の処理が何もできない状態のこと。
ラウンドロビン
複数のノードに対して順番に割り振ったり分散したりすること。たとえば、1つのFQDN(Fully Qualified Domain Name:完全修飾ドメイン名)に複数のIPアドレスを割り当ててアクセスを分散する「DNSラウンドロビン」や、複数のサーバに順番にリクエストを分散するようなロードバランサのバランスアルゴリズムなどがある。
レイテンシ
データが届くまでの時間。

1. サーバ/インフラ構築入門

コールドスタンバイ
予備機は普段使わず、現用機が故障したら予備機を接続する運用体制。ルータの故障の対応などに用いられる。
ホットスタンバイ
予備機・現用機両方のサーバを常に稼動させておき、常に同じ状態に保っておく運用形態。Webサーバの故障の対応などに用いられる。
DNSラウンドロビンとロードバランサの違い
DNSラウンドロビンではWebサーバごとに異なるグローバルアドレスを割り当てる必要があったが、ロードバランサを利用するとグローバルアドレスの節約ができる。また、DNSラウンドロビンではWebサーバ側で工夫して冗長構成をクムが、ロードバランサではその必要がない。
ipvsadm
IPVの開発源が提供しているCLツール。
keepalived
LVS と組み合わせて使う、ロードバランサの冗長性確保用デーモン。
VRRP (Virtual Router Redundancy Protocol)
ルータやロードバランサの冗長化を行うためのプロトコル。

2. ワンランク上のサーバ/インフラの構築

リバースプロキシ
ロードバランサとWebサーバの間に挟むことで、より柔軟な負荷の分散が可能となる。Apacheにmod_proxyやmod_proxy_balancerを組み込んで構築できるが、Apache以外でもlighttpdやSquidなどでも代用可。具体的な機能としては、HTTPリクエストの内容に応じたシステムの動作の制御、システム全体のメモリ使用効率の向上、Webサーバが応答するデータのバッファリングの役割、Apacheモジュールを利用した処理の制御 などがある。
Keep-Alive
HTTPの仕様。一度確立した接続をしばらく維持し、後続のリクエストでその接続を使い回すことにより、1本の接続でまとめて多数のリクエストが処理できる。
mod_proxy_balancer
リバースプロキシを行うにあたって、プロキシ先のホストが複数ある場合でもそれらにリクエストが分散して振り分けられるよう計らってくれるモジュール。
Squid
HTTPプロトコルのキャッシュ機能を前提としたキャッシュサーバ。ページ全体をキャッシュ出来るようなケースで有効。リバースプロキシとしても利用出来る。
memcached
HTTPレベルでなく、データ単位でキャッシュを管理する、高速なネットワーク対応の分散キャッシュサーバ。ストレージにはOSのメモリを利用する。
レプリケーション
データのバックアップを物理的に異なるサーバへリアルタイムにとること。
マスタ
クライアントからの更新と参照の両方のクエリを受け付けるサーバ。
スレーブ
クライアントからの更新は受けつけず、データの更新はマスタとの連携でのみ行う役割のサーバ。

3. 止まらないインフラを目指すさらなる工夫

リゾルバ / レゾルバ
IPアドレスとドメイン名を結びつけるDNSにおいて、ネームサーバにホスト名を通知してIPアドレスの検索を依頼したり、その逆を依頼したりするクライアント側のプログラム。
RAID (Redundant Arrays of Inexpensive Disks)
複数の外部記憶装置(ハードディスクなど)をまとめて一台の装置として管理する技術。データを分散して記録することにより、高速化や耐障害性の向上が図られる。
ブロック・デバイス
ハード・ディスクやCD-ROMドライブ,フロッピ・ディスクなどのディスク装置全般。データの読み書きが,ある大きさのブロック単位で行えるデバイス。
DRBD (Distributed Replicated Block Device)
ネットワークを通じてハードディスク(ブロックデバイス)をリアルタイムに複製(同時複製)するソフトウェア。大切なデータを失わないためのバックアップや、サービスの冗長化などに広く用いられている。
NFS (Network File System)
UNIXシステムで利用されるファイル共有システム。UNIX系OSにおける標準的な分散ファイルシステムとなっている。
Bondingドライバ
Linuxに用意されているネットワークドライバの1つ。複数の物理的なネットワークカードをまとめて、1つの論理的なネットワークカードとして扱えるようにする。リンクの冗長化などに用いられる。
RSTP (Rapid Spanning Tree Protocol)
各スイッチが協調してネットワーク上にできたループを検出し、自動的に冗長な接続を遮断するための、データリンク層のプロトコル。
データリンク層
OSI参照モデルにおけるL2。上層のネットワーク層からのサービス要求に応え[2]、下層の物理層に対してサービスを要求する。
BPDU (Bridge Protocol Data Unit)
STPで,ループの検出を行い,論理的ループを切断するためのマルチキャスト・フレーム。
LAN (ローカル・エリア・ネットワーク)
広くても一施設内程度の規模で用いられるコンピュータネットワークのこと。
WAN (Wide Area Network)
LANやMANに比較して広い範囲(市街地を越え郊外、県外や国際の範囲)におよぶネットワークのこと。広義には、非常に広大な面的広がりを持つインターネットとほぼ同義の言葉として使われる一方、狭義には、点在するLANとLANを接続する線としてのネットワークというような意味合いでも使われる。
VLAN (Virtual Local Area Network)
物理的な接続形態とは別に仮想的なネットワークを構成することである。1台のスイッチで複数のセグメントを管理できる、サーバ追加/置き換え、故障時の代替機による復旧が容易になる、などのメリットがある。

4. 性能向上、チューニング

ロードアベレージ
システム全体の負荷
レジスタ
コンピュータのプロセッサ(CPU、DSP、GPUなど)が内部に保持する少量で高速な記憶装置。
スレッド / LWP (Light Weight Process)
スレッドはプロセスよりも細かな実行単位。プロセスの中で複数のスレッドを動作させることができる(マルチスレッド)。
マルチプロセス
プロセスを複数生成するモデル。基本的にプロセス間でメモリを直接共有することはできない。メモリ空間が独立していて安全。
マルチスレッド
プロセスより小さい単位のスレッドを複数生成するモデル。メモリ空間全体で複数のスレッドを共有するため、スレッド切り替えのコストが少なく済むが、リソース競合が発生しないよう気をつける必要がある。(ゆえにプログラミングが複雑になりがち。)
イベントドリブン
入出力を監視してイベント発生のタイミングで処理を切り替え、シングルスレッドで並行処理を行うモデル。
ページキャッシュ
一度ディスクから読み出したデータをメモリにキャッシュしておくこと。
prefork
c予め複数のプロセスを生成(プリフォーク)してクライアントの接続に備えるマルチプロセスモデル。
worker
UNIX環境における代表的なMPM。マルチスレッドとマルチプロセスのハイブリッド型。prefolkよりリソース消費量が少なくて済むので、大規模な開発ではこちらを選ぶのがベター。
lighttpd
最近人気のあるOSSのWebサーバ。少ないメモリで大量のアクセスを同時並行的に処理することを主眼に置いた高速な実装。Apacheに比べ汎用性は劣るが、そのぶん1リクエストあたりの計算量が少ないためCPUに優しい。シングルプロセスで、メモリ使用量がApacheより遥かに小さい。Apacheのmod_rewriteやmod_proxyに相当する基本的な機能は全てカバーしている。FastCGIにも対応しており、PerlやPHP、Rubyで記述されたWebアプリケーションを高速化しAPサーバとしても利用出来る。
FastCGI
CGIの動作方法の仕様の一つである。プロセスをメモリ上に永続化させることで、その起動と終了にかかる時間をカットし、結果としてプログラム動作速度の向上およびサーバ負荷の低下が可能となる。
nginx
軽量高性能なWebサーバ/リバースプロキシであり、同時に電子メール(IMAP/POP3)プロキシ。高いパフォーマンスと安定性、豊富な機能、設定の容易さ、消費リソースの低さで知られている。(現在のシェアは7.5%。)

5. 省力運用

Nagios
OSSのサービスかどう監視ツールで最も有名なもの。稼動状態といった死活監視から、負荷状態の監視、稼働率の計測まで面倒を見てくれる。
Ganglia
サーバリソースのモニタリング/グラフ化ツール。大量ノード向け。モニタリングツールには他に、Munin、Cacti、CloudForecastなどもある。
Puppet
効率的なサーバ管理を実現するツール。各サーバにログインして手作業で行ってきた設定がほぼ自動化できる。新規サーバの投入や既存サーバの設定変更における設定の反映を省略化できる。
daemontools
デーモンプロセスの開始、終了、再起動、プロセスが落ちた場合の自動起動、といったデーモンプロセスの管理を行うためのプログラム群。
ネットワークブート
マシンがブート(電源を入れてから操作可能な状態になるまでの流れ)するために必要なデータやファイルを(通常ハードディスクから読み出すのに対して)ネットワークから取得してブートすること。これを使えば、マシンの起動にローカルの二次記憶装置は必要なくなる。ハードディスクはマシンの構成要素の中でも最も故障率の高い部品なので、ディスクレス構成にすればサーバの故障率はぐっと下がる。
initramfs
ネットワークブートで使われるしくみ。カーネルがルートファイルシステムをマウントしてinitを起動する前に、カーネルの内部でしか行い得ない初期化をする。典型的な役割は、カーネルがルートファイルシステムにマウントするのに必要とするドライバモジュールを、カーネルにロードすること。
PXE (Pre-eXection Environment)
ネットワークブートの枠組みで、x86系のアーキテクチャでメジャーなもの。Intel社が規格化。

6. あのサービスの舞台裏

[][]httpd.confについて僕も調べたのでまとめる

ディレクトリごとの設定

ディレクトリごとの設定で重要な役割を果たすのが、OptionsディレクティブとAllowOverrideディレクティブの2つ。

<Directory />
    Options FollowSymlinks
    AllowOverride None
    Order deny,allow
    Deny from all
</Directory>
Optionsディレクティブ

CGIやSSIなど、そのディレクトリに対してどのようなWebサーバの機能を許可するかをしていする。

ExecCGICGIの実行を許可
IncludesSSIを許可
IncludesNoEXECSSIを許可(ただし #exe, #cmd, #include によるプログラムの実行を許可しない)
Indexesindex.htmlがない場合にディレクトリインデックスを表示
FollowSymLinksシンボリックリンクをたどることを許可
SymLinksIfOwnerMatchリンク先が同じオーナーのときだけシンボリックリンクをたどることを許可
MultiViewsコンテンツネゴシエーションを許可(主に言語別のファイルをクライアントに送信するために使用される)
Allすべて有効にする
Noneすべて無効にする
AllowOverrideディレクティブ

アクセスコントロールファイル(.htaccess)にどこまで上書きを許すかを指定。

AuthConfig認証に関する設定を許可
FileInfoドキュメントタイプの設定を許可
Indexesディレクトリインデックスに関する設定を許可
Limitアクセス制御の設定を許可
OptionsOptionsによる設定を許可
Allすべて有効にする
Noneすべて無効にする

ユーザー認証の設定

Basic認証のための設定
Digest認証のための設定

2011-02-28

[][]Catalystアプリをmod_perl環境にデプロイする際の設定

MyAppというアプリの場合

LoadModule perl_module modules_mod_perl.so      # mod_perlのロード
# ... 中略 ...
PerlSwitches -I "/path/to/myapp/lib"            # モジュールへのパスを設定
PerlSetEnv CATAL_DEBUG 0                        # デバッグモードを無効化

PerlModule MyApp                                # アプリケーションのロード

<Location /myapp>                               # /myappパスへの設定
    SetHandler modperl                          # modperlハンドラを設定
    PerlResponseHandler MyApp                   # レスポンス生成に使用するハンドラを設定
</Location>

Alias /myapp/static /path/to/MyApp/root/static  # staticディレクトリへのエイリアス
<Directory /path/to/MyApp/root/static>
    allow from all                              # staticディレクトリへのアクセスを許可
</Directory>
<Location /myapp/static>
    SetHandler default-handler                  # staticディレクトリを静的ファイルとして処理
</Location>

2011-02-18

[][]Apache全然分からんから勉強する

今までコピペでデプロイやり過ごしてたツケがいよいよ回ってきたので真面目に勉強することにした。

バージョン確認
httpd -v
組み込まれている性的モジュールを確認
httpd -l
Apacheのプロセス
ps ax | grep httpd
Document Root
コンテンツを配置する場所
DirectoryIndex
index.htmlとか
起動・再起動(さくらVPSでは)
sudo service httpd start

CGI

AddHandler cgi-script .cgi .pl     

<Directory "/var/www/cgi-bin">
    Options Indexes MultiViews ExecCGI
    AllowOverride AuthConfig
</Directory>
403とか500とか出る場合は
chmod 755 cgi.cgiとか

つづく・・・