カテゴリー別アーカイブ: LAMP[Linux, Apache, MySQL, PHP]

nginxで、入り口でまとめて認証をかける

 リリース前のサイトを本番環境でテストするとき、認証をかけたりするよね。
 DNSラウンドロビンとかLVSでバランシングしているときは、各ホストに.htaccessと.htpasswd書いたりするわけだけど、nginxでバランシングしている場合は、nginxの設定ファイルにまとめてかける。

server {
listen 80;
server_name hoge.tld;

location / {
auth_basic “auth”;
auth_basic_user_file “/usr/share/nginx/.htpasswd”;
proxy …
}
}

みたいな感じ。

nginxで認証を要求せず、裏のサーバが認証要求した場合には裏の認証要求が通る。
両方で認証を要求すると同じユーザ名:パスワードのセットで認証出来れば通るけど、それ以外の時は認証不能になる。

(336)

カテゴリー: サーバ設定 | コメントをどうぞ

NGINXをProxy利用 = UpstreamでKeepaliveを使う

 バランシングのテストにお名前.com VPS(KVM)を3台契約して、1台をバランサ、2台をアプリケーションサーバ(Apace)として構築して試験中。

 デフォルト設定でNGINXを通すと、NGINX-Apache間がHTTP 1.0 Closeコネクションになるため、abとかで叩くとApacheのスレッドが大量に立ち上がる。 この状態だと、リクエストのたびに新しい通信が立ち上がってくるし、Apacheのプロセスが切り替わりまくるからパフォーマンス的に美味しくない。
 調べてみると、最近のNGINXではupstream.keepaliveのディレクティブを使うことで、裏の通信をKeepAlive接続にできるようになるので、早速導入して評価。

と、設定前に負荷試験。

abで同時接続100、10000回のGETを実行(400KBのHTML、GZIPで60KBになるファイル)
NGINXでGZIP/SSL処理してAPACHEにつなぐと、200requests/sec程度のスループットだった。

#nginx.conf

upstream appservers {
server 192.168.10.10:80;
server 192.168.10.11:80;
keepalive 1000;
}

server {
listen 443;
server_name _;

location / {
proxy_http_version 1.1;
proxy_set_header Connection “”;
proxy_pass http://appservers;
}
}

 upstream.keepaliveをセットするのと、proxy_http_versionを1.1に(KeepAlive実装)、proxy_set_headerでConnectionを空にする(デフォルトでは、Connection: closeを送信してしまうため)

 Apache側は

KeepAlive On
MaxKeepAliveRequests 1000
KeepAliveTimeout 15

としてみた。

 先と同じようにabを実行してみた結果、210requests/sec程度になった。 もともと、ネットワーク転送量がワイヤースピード近くに達していたため、速度的にはそれほど改善していない。
 しかし、サーバのリソース的には相当改善が見られた。 CPU使用率のSys値(ユーザプログラム以外の部分で消費される無駄)が低下した。
 重いアプリケーションを動作させている場合には、オーバーヘッドが低下する分だけ応答速度の向上が期待できそうだ。

(1965)

カテゴリー: サーバ設定 | コメントをどうぞ

NGINXを使う(Proxy利用)

 Webサーバとしては使い慣れていることもあってApacheをずっと使い続けてきたが、細かい設定がしにくいという点があり、今回NGINXを使用することにした。
 ただし、今回はApacheを代替するわけではなく、Proxyとして利用することにした。
 バランシングのテストにはお名前.com VPS(KVM)を3台契約して実装してみた。

 まずは、基本のProxy構成。
 と言っても、何も難しいことはない。

server {
listen 80 default_server;
server_name _;

location / {
proxy_pass http://localhost:10080;
}
}

 これだと、NGINXがポート80で待ち受けて、すべてのリクエストをlocalhostポート10080に送る(Apache等をポート10080で待たせておく)
このままだと何も効果がないから、ここから色々追加していく。

location /php/ {
proxy_pass http://localhost:10080;
}
location /ruby/ {
proxy_pass http://localhost:20080;
}

 こうなると、/phpに来たリクエストは10080に、/rubyに来たリクエストは20080に行くので、apache + passengerを一つの入口で受けられるようになる。 localhostの部分を変えて、192.168.10.10とかにすれば、別サーバに流れていくから、一つの入口からアプリ単位で内部では別サーバで動かすことができる。

 更に、ロードバランシングも簡単に作れる。

upstream appservers {
server 192.168.10.10:80;
server 192.168.10.11:80;
}

server {
listen 80 default_server;
server_name _;

location / {
proxy_pass http://appservers;
}
}

 これで、来たリクエストは192.168.10.10と11に分配される。

 upstream.serverには簡単に重み付けが出来るので、

server 192.168.10.10:80 weight=5;
server 192.168.10.11:80 weight=10;

みたいにすることで、アプリケーションサーバの重み付けができる。

 さらに、スタンバイ構成も簡単で

server 192.168.10.10:80;
server 192.168.10.11:80;
server 192.168.10.12:80 backup;

とすると、10,11が応答しない時だけ12に振り分けることもできる(backupと書かれたサーバが正常時待機系となる) 10,11のいずれかが復帰すればbackupは待機状態に戻る。
VerisgnのSSL証明書はバランシングすると台数分の取得を要求されるが、ホットスタンバイ・コールドスタンバイであれば、同時に動作する台数分で良いのこんなかんじで設定できるのは便利。

 HTTPのgzip圧縮をNGINX側に任せられるので、アプリケーションサーバを本来の処理に専念させることもできる。

server {
listen 80 default_server;
server_name _;

gzip on;

location / {
proxy_pass http://appservers;
}
}

 また、SSL処理もNGINX側で行う事になる。

server {
listen 443;
server_name _;

ssl on;
ssl_certificate /etc/pki/tls/certs/ssl.crt;
ssl_certificate_key /etc/pki/tls/private/server.key;

location / {
proxy_pass http://appservers;
}
}

 NGINXでは帯域制限が容易にできるので、

location / {
proxy_pass http://appservers;
}

location /file/ {
limit_rate 2m;
proxy_pass http://appservers;
}

こんなふうにすると、file配下のダウンロードを2Mに制限できるので、ファイルダウンロードのせいでアプリが遅くなるみたいなことの解消が期待できる。

 また、制御構造を使って、

location / {
proxy_pass http://appservers;
if ($http_user_agent ~* “msnbot”){
limit_rate 1m;
}
}

みたいなこともできるので、BOT様の速度を制限して通常接続の帯域を確保できる。

 色々、更に便利な機能があるから、しばらく検証しよう。

(620)

カテゴリー: サーバ設定 | コメントをどうぞ

安物のRAID装置は禍の元

 サーバの記憶装置では通常RAID構成がされていますよね。

 以前の職場で、なぜかRocketRAIDアダプタが乗っているサーバがあって、RAID5構成になっていました。 予算をケチって安く売っているカードを買って自前で組んだのでしょう。

 そのサーバであるときファイルが読めなくなりました。 アレイマネージャを確認すると何もエラー無し。
論理エラーかとも思ったのですが、システムが異常停止したわけでもない状態のサーバ機で論理エラーが発生することはあまりありません(主記憶やバスはECCで保護されているので)
OSのシステムログを確認するとデバイスドライバの応答停止エラーが発生していました。
しかし、他のファイルのアクセスは全く問題なく、システムの再起動を実行してもそのファイルだけアクセス不能。
システムを落として、別マシンで個別ドライブをフルリードスキャンしてみた結果、1台のドライブで読み込み不能セクタが発生していました(アクセスすると数十秒応答停止して、SMARTを確認すると再配置待ちセクタなどの値が変化する状態)
どうやら、このRAIDアダプタはドライブがデバイスタイムアウトした場合の扱いがしっかり実装されておらず、ドライブが応答しないときにアダプタもタイムアウトしてしまうお粗末な物だったようです。
結局、該当のドライブを外した状態で電源投入すると、Critical状態でシステムが起動して、該当ファイルは読み込めました。

 確かに、RAID5の仕様である、ストライピング&パリティ書き込みを実行して、高速化と1デバイスが喪失された状態でデータ復元は出来ましたが、冗長構成はエラーが発生しても処理を継続し、かつ正常にエラーが検出できなければ実用に耐えません。 このアダプタの存在によって、障害の切り分けが困難になったという点は特に問題ですね。

 やはり、価格差はあってもメジャーブランドの製品を選択するべきだと認識させられました。 予算的にハードウェアRAID構成が難しい場合は、無理にRAIDアダプタを搭載せずソフトウェアRAIDで構成しておく方がベターでしょう。

(117)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP] | コメントをどうぞ

Office365をはじめました

 先日、Office2013がリリースされて、1台導入したのだけど、PCを多数保有しているとちょっと不便。
 楽天などで怪しいOEMライセンスの激安品を売っているけど、途中でProductキーがロックされたりして安心して使えないようだ(キー自体は正式なものだが、キーの用途が不正なので、購入していても正式ライセンスではない)

 そこで、この度、個人的にOffice365の契約を検討することになった。
 現在、30日の無料試用が利用できるので、早速申し込んで試用開始。

 今回のプランはOffice365 SmallBusinessPremiumで、月額1250円or年額12360円のクラウド型ビジネス向けサービスで、ビジネス向けではあるが1アカウントから契約できる。

 25GBのメールボックス、7GBのストレージ、Webベースのオフィスアプリなどが利用できるところまではGoogleAppsと大差ないけど、これに加えてSBPではOffice365 ProPlus(最新のOfficeスイートが利用できるサービスで、現状はOffice2013 ProPlusのデスクトップアプリ)が利用できる。
 Office365 ProPlusで利用したデータは標準でクラウドストレージに保存されていて、Officeのライセンスとストレージのアカウントが統合されているから、自宅でも外出先でも会社でも、同じようにアカウントでログインしてOfficeを使えば同じファイルを共有して作業ができる。

 SBPは1アカウントあたり5台のデバイスにOffice365 ProPlusを導入できるそうだ。
 私は自宅のメインデスクトップとメインノート、外出用のモバイルノート、MacのBootCamp環境で利用したいので多くのデバイスに入れられるこの契約は非常に有利だ。

 このサービスを会社で導入してくれると、自宅のPCで持ち帰った仕事をするためだけにオフィスを購入すると言う必要もなくなるのは大きな利点だろう(会社のアカウントでログインすればそのまま使える)
 クラウド型はもたつく印象もあるが、デスクトップ版を一度導入しておけば、普段は意識することなく利用できる感じで、問題は無さそうだ。

 Officeを複数導入する必要がある、イニシャルコストを抑えたいというニーズでは、Office365月額プランはかなり有利そうだ。

(660)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP] | コメントをどうぞ

jQueryで非同期処理の完了を待つ(jQuery.Deferred())

 jQueryのAJAX実装をすると、通常、通信が戻ってくるのを待たずに次の処理に進んで、通信の結果はコールバックで処理するよね。

function getResponse(url, parameters, target){
  jQuery.post(url, parameters, function(response){
    for(i in response){
      $(target).html(response[i]);
    }
  });
}

みたいな感じね。

 でも、この処理をまたどこからか呼び出していて、呼び出し元で、この通信が終了している必要がある場合(たとえばappendした結果に対して何か処理したいとか)、普通に

getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’);
alert($(‘#targetArea’).html());

とかすると、getResponseは要求を作っただけで戻ってきてしまうので、alertの中身は空っぽ、みたいな事になる。
で、これに対応するためにどうするかというと、jQueryのDeferredを使うと良いようだ。

ファンクションの方は

function getResponse(url, parameters, target){
  var def = jQuery.Deferred();
  jQuery.post(url, parameters, function(response){
    for(i in response){
      jQuery(target).html(response[i]);
    }
    def.resolve();
  });
  return def.promise();
}

みたいな感じで、Deferred.promise()を戻すようにする。
AJAXの戻り値を待つ必要がない既存のコードは、特に何も変えなければそのまま動く。 そして、先のように待機する必要がある場合のコードでは、

jQuery.when(
  getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’)
).done(
  function(){
    alert($(‘#targetArea’).html());
  }
);

みたいな感じにすると、getResponseが返したDeferredがresolveを実行次第doneの中身が呼び出される。
done()は、Deferredにバインドしている形なので、

jQuery.when(
  getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’)
).done(
  function(){
    alert($(‘#targetArea’).html());
  }
);
window.close();

みたいにすると、表示してから閉じると言う動きにはならず、すぐ閉じてしまう。

なお、失敗時のために、resolve doneの組み合わせに対して、reject failがある。。

jQuery.when( asyncFunc() ).done( trueFunc() ).fail( failFunc() );

みたいにすれば、asyncFunc()の返したDeferredでresolve()が実行されればtrueFunc()を、reject()が実行されればfailFunc()が実行されるようになる。

 ファンクションが何かの値を戻していた場合、普通に書き換えるとDeferredを戻さなくてはならなくなると言う問題があるが、resolve/rejectに引数として与えると、done/failの引数として引き継がれる。

function getResponse(url, parameters, target){
  var def = jQuery.Deferred();
  jQuery.post(url, parameters, function(response){
    for(i in response){
      jQuery(target).html(response[i]);
    }
    def.resolve(response.length);
  });
  return def.promise();
}

jQuery.when(
  getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’)
).done(
  function(len){
    alert(len + ‘:’ + $(‘#targetArea’).html());
  }
);

みたいな感じ。

whenはDeferredを複数くっつけるための物なので、1個の実行を待つだけならDeferredを戻すファンクションに対して、 asyncFunc().done(trueFunc()) 的な呼び出しでも良いっぽい。

(10635)

カテゴリー: jQuery | コメントをどうぞ

RTX1000で複数の経路を切り替える

 RTX1000を1台使用したネットワークで2本のプロバイダ接続を行って、使用する経路を切り替える。
 宛先毎にルートを指定する場合は、スタティックルーティングで

ip route 8.8.8.8 gateway pp 1
ip route default gateway pp 2

みたいにするわけだけど、今回の要望は同じサブネット上に存在する特定の端末について、回線を切り替える必要が生じた。

この場合は、フィルタ型ルーティングと言う方法を利用して、

ip filter 101 pass 192.168.0.0/24 * * * *
ip filter 201 pass 192.168.0.100 * * * *
ip route default gateway pp 2 filter 201 gateway pp 1 filter 101

のようにすると、各ゲートウェイに対してフィルタを適用して、先頭から順次チェックして通れるゲートウェイを通過するようになる。
この場合は、192.168.0.100から送出されたパケットはpp2を通り、それ以外の192.168.0.0/24ネットワークから送出されたパケットはpp1を通る。
pp2を通るPCを追加する場合は、

ip filter 202 pass 192.168.0.101 * * * *
ip route default gateway pp 2 filter 201 202 gateway pp 1 filter 101

みたいな感じで並べる。
連続IPなら、

ip filter 201 pass 192.168.0.100-192.168.0.101 * * * *

でもOK。

(1693)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP] | コメントをどうぞ