という話

技術ブログにしたい

ネットワーク初心者が、さくらクラウドからAWSに移行した時のメモ

ネットワーク素人が、さくらクラウドで負荷分散構築した時のメモ1【準備編】 - なりせなるてず

この記事を4月に書いてからたった5ヶ月ですがAWSに半分移行しました。

AWSに移行するきっかけ

嬉しいことに自社サービスが順調に成長してて、アクティブユーザーがだいたい常時300以上、多い時は1500から3000位にまでアクセスが集まるようになったことです。
勿論さくらクラウドでも対応出来るんですが、瞬間的に通常時の5倍から10倍のアクセスを捌きつつ、通常時はサーバーを減らして安く抑えたいという要求を叶えるためにはさくらクラウドじゃムリだろうということになりました。
さくらクラウドはオートスケーリング対応してませんし、今のところその予定もなさそうなのでAWSの出番というわけです。

オートスケールに対応したクラウドサービスはAWS以外にもありますが、まぁAWS一択でしょう。

AWSのお勉強

AWSはオートスケール出来て凄い!くらいの知識しか無かったのでお勉強です

これと

自分がしたいと思ってたことはほぼこの2つに概要からやり方まで書いてあり、非常に参考になりました。
ただ、AWSのコンソール画面はしょっちゅう変わってるので、AWSコンソールからオートスケーリングさせる設定は
AWS - 【AutoScalingをManagementConsoleから設定してみる】 - Qiita
こちらを参考にしました。

EC2のインスタンスを作るときにAmazon Linuxを選ぶと、スペックはしょぼいですが1年間無料で使えるプランがあるので色々テストできます。
クラウドサービス無料利用枠 | アマゾン ウェブ サービス(AWS 日本語)


サーバー構成

先ほどのスライドにありますが、こういう構築にしたほうがいいよ!ってのをほぼ丸パクリして構築しようと考えました。
f:id:ichiy:20140917183229p:plain


オートスケーリングを使う流れとしては、
1.EC2でwebサーバーとして機能するものを作る。起動時に自動で最新のプロジェクトがデプロイする仕組みを作っておく
2.EC2でwebサーバーが出来たら、インスタンスをstopして、AMIを作る
3.ロードバランサーを作る
4.オートスケーリングの設定を作る

こんな感じで作って移行してみたんですが、移行3時間で転送量がめちゃめちゃかかってやばい事が判明。
このまま行くと月額80万位かかる計算でした・・・(゚д゚;)
冷や汗が止まらなかったです。
急いで転送量がかからないさくらクラウドに画像を置くことにしました。

で、結局最終的にはこういう構築になりました。
f:id:ichiy:20140917183200p:plain

画像をNFSでさくらクラウドのファイルサーバーにアップロードして、画像のURLをさくらクラウド側にしアクセスさせるようにしました。
webサーバーはオートスケーリング出来るAWSを使い、画像は転送量でお金がかからないさくらクラウドにして、両者のいいとこ取りを実現しました。


戸惑ったこと

移行するにあたって色々ハマった事があったのでメモ

RDSはUTC固定

RDSのタイムゾーンUTC固定で基本的には変更できません。
色々変更する方法はあるっぽいですが、定期メンテナンス時に落ちるとかいう人て怖いのでやってません。

RDSのストレージは追加出来るけど減らすことは出来ない

作ったあとでこんなに容量要らないやと思い容量の変更をしようと思ったのですが、追加することは出来ても削除することは出来ませんでした。

CentOSが色々入ってない

vimとかwgetとか、あと色々サービス群が入ってませんでした。
さくらクラウドCentOSには初期から色々サービスが入っててすぐ使えるので便利でした。
ただその反面初期から起動してるサービスはそのままにしてると、かなりの確率でDDosなどの踏み台にされるので対応しなければならず面倒です。
当然といえば当然ですが、AWSCentOSは余計なサービスは入っておらず軽量です。

topコマンドで見れるCPU使用率があてにならない

ApacheBenchで負荷テストをしてる時、同時接続数をいくら増やしても40%位を限度にそれ以上CPU使用率が上がりませんでした。
Amazon EC2 インスタンスの負荷測定 : まだプログラマーですが何か?
こういう理由があるみたいです。

ELBはIPアドレスがない

ELBにはIPアドレスが無く、EIPを使っても設定することが出来ません。
つまりAレコードでDNSを設定することが出来ず、CNAMEしか無理ということです。

不勉強で知らなかったのですが、CNAMEはサブドメインしか指定することが出来ないので、
「www.example.com」みたいなアドレスで良ければいいのですが、「example.com」みたいなURLでアクセスさせることが出来ません。

これを解決するにはRoute53を使うしかありません。よく出来てますね・・・。
営業でも簡単!Route 53の基本設定 « サーバーワークス エンジニアブログ
上記を見て設定しました。

オートスケーリンググループの設定を変えると突然EC2が死ぬことがある

AMIを更新してオートスケーリンググループも変更したりするんですが、それをやると数時間後(タイミングは不明)で突然EC2群が死んで、新しいAMIで立ち上がります。
検索しても出てこない現象なので詳細は不明です。


よく出てくる意味分からなかった単語

AMI

Amazon Machine Imageの略。
インスタンスを作るときのひな形。
ApachePHPなど必要なものをインストールしておいて、オートスケーリングするときになどにこのひな形を元にインスタンスを自動追加出来る。

ELB

Elastic Load Balancingの略。
ロードバランサです。ただし普通のロードバランサと違い、ロードバランサ自体がスケールアップ出来る。

EBS

Elastic Block Storeの略。
ストレージのこと。
起動中のEC2にストレージを追加できたりする。

AZ

Availability Zoneの略。
データセンターの中で、電源などが物理的に分かれている場所の事らしいです。
Multi-AZは別々のAZにEC2やRDSを配置することで、天災時などで万が一どちらかの電源が落ちたりしても別のAZにはアクセスでき、耐障害性に優れているということみたいです。

IOPS

I/O per Secondの略。
HDDなどのディスクが1秒間に出来るI/O処理の数のことらしい。
この数値が高いほど性能がいいということ。100IOPSだったら1秒間に100回トランザクション処理が出来る(多分)



さくらクラウド vs AWS

さくらクラウドが有利だと思う点

1. さくらのほうが1インスタンスに対しての費用対スペックがいいです。
例えば社内向けのコミュニケーションツールみたいに、ある程度アクセスする人数やPVがわかっている状態ではさくらクラウドで構築したほうが安上がりになると思います。

2. ドキュメントやコンソールが日本語
AWSのように頻繁にコンソール画面が変わることが無いのでドキュメントやブログで見た情報のまま使えることが多いです

3. 転送量がかからない
標準的なWebサービスAWSで運用する時、最もお金がかかるのが画像などの転送量だと思います。
ここにお金がかからないのは相当デカイです。

AWSが有利だと思う点

1. セキュリティグループ
これのお陰でiptablesとか書かなくてもいいし、余程変な設定にしない限りセキュリティの穴になることもないのかなぁと思います。

2. オートスケーリング
これがさくらクラウドからAWSに移行した決め手です

3. 起動中のインスタンスにストレージ追加出来る
見積もってたより多くのストレージが必要になった時、サーバーを止めること無くストレージを追加出来るのでサービスに影響なく進められます

4. 圧倒的な多機能
何がなんだか分からないサービスがいっぱいあります


おわりに

移行する前はAWSに移行したら全部解決できるみたいな幻想があったんですが、勿論実際にはそんなことはなく、さくらクラウドのほうが優れている部分も多く、工夫次第でどうにかなるなぁと思いました。

FuelPHPで全てのコントローラーにフィルタをかける

全部のコントローラーで決まった処理、例えば認証処理とかを行いたい場合、Symfonyみたいな全部のコントローラーにかかるフィルタが欲しいところですが、用意されてないようです(見つけられてないだけかも)

なので今までずっと、それぞれのコントローラーにbefore(),after()メソッドを書いていたんですが公式ドキュメントをちゃんと読んだら解決できました。

ベースコントローラー

コントローラ - 概要 - FuelPHP ドキュメント

<?php
class Controller_Public extends Controller_Template
{
  public function before()
  {
    parent::before();

    // 認証処理などの共通処理を記述
  }

  public function after($response)
  {
    $response = parent::after($response); 

    // アクション実行後に行いたい共通処理を記述
    return $response;
  }
}

こんな感じで共通処理だけを記述したベースとなるコントローラーを作成します。
そして共通処理を行いたいコントローラーに継承させます。

<?php
class Controller_Top extends Controller_Public
{
  public function before()
  {
    parent::before();
  }

  public function after($response)
  {
    $response = parent::after($response); 
    return $response;
  }

  public function action_index()
  {
     // 処理
  }
}


Controller_Publicを継承することで、毎回before()メソッドなどに処理を書かなくてよくなります。
今回はベースコントローラーをController_Templateを継承して作成しましたが、Controller_HybridでやればTemplateもRestも対応できます。


ちゃんとドキュメント読まなきゃダメですね

FuelPHPで画像圧縮と圧縮率

webページの表示速度を上げるうえで必ずネックになる画像。
圧縮するとどのくらい変わるものなのか調査してみました。

FuelPHPで画像圧縮

いつもどおりFuelPHPです

$filepath = 'image.jpg';
Image::forge(array('quality' => 90))->load($filepath)->output();

Image::forgeメソッドに配列でqualityキーと値を渡します。
qualityが90%になるように?圧縮してくれます。

圧縮率

元画像が307KBでした。
クオリティ90%で110KB
80%で75KB
70%で60KB
60%で51KB
50%で45KB
40%で39KB
30%で33KB
20%で25KB
10%で17KB

と、なりました。
90%の時点で約3分の1にまで小さくなるでの非常に有効ですね。

勿論画像自体も汚くなるのですが、僕の見た限りでは70%くらいまでは余裕で使えるなーという感じでした。
参考画像を上げれなくて申し訳ないです。

圧縮の不思議

JPGは圧縮すると素直に容量も小さくなったのですが、PNGは圧縮すると逆に容量が大きくなりました。
またGIFはほぼ変わりませんでした。

GDのせいなのか、はたまたPNG,GIFアルゴリズムのせいなのかは分かりません。
webで使われてるのは圧倒的にJPGが多いので、JPGだけ圧縮するようにして対応してます。

Chromeで日本語変換中の文字色が変わる時の対処

Chromeアップデートしたら日本語変換中に文字が消えてしまい、調査した結果。


Chromeのバージョン36から変換中の文字に、選択時の文字色CSSが反映されるようになったみたいです。
つまり日本語変換中に文字色が変わる場合は::selectionでcolorなどを弄ってるはずなので、そこを削除すればなおります。

::selection {
  background-color: #999;
  color: #fff;
}
::-moz-selection {
  background-color: #999;
  color: #fff;
}

僕はこんな感じで指定していたので変換中は文字色が白になってしまい、あたかも消えたようになって見えたのでした。

::selection {
  background-color: #999;
}
::-moz-selection {
  background-color: #999;
}


こうすることで直りました。
が、テキスト選択中の色が普通のままなので見づらくなりました。対策方法は見当たりません。


変換中の文字に選択中のCSSを当てるのはいいとして、何故文字色だけにしたんでしょう。

日本語ドメインからfile_get_contentsを使ってHTMLを取得する

file_get_contentsって日本語ドメインに対応してないので、

$url = 'http://日本語.jp/';
$html = file_get_contents($url);
echo $html;

とかやろうとすると

PHP Warning:  file_get_contents(http://日本語.jp/): failed to open stream: php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known in nihongo_domain.php on line 2

とか出て怒られます。

punycode

日本語ドメインってpunycodeという、普通のURLと同じような半角英数で出来たURLに変換されるようです。

日本語.jpだと
http://xn--wgv71a119e.jp/
というURLに変換されます。

このURLならfile_get_contentsでも取得できそうです。

日本語ドメインpunycodeに変換する

PHP標準ライブラリでは変換出来ないのでPEARのライブラリを使います。

sudo pear channel-update pear.php.net
sudo pear install Net_IDNA2-0.1.1

PHPで日本語ドメインを扱う方法(Punycode変換)
ここを参考にしてやってたんですが、

Non-static method NET_IDNA2::getInstance() should not be called statically.

ってエラーが出たのでちょっと変えてこうします

require_once 'Net/IDNA2.php';

$idna = new Net_IDNA2();
$idna_instance = $idna->getInstance();

$url = 'http://日本語.jp/';
$encoded_url = $idna_instance->encode($url);

$html = file_get_contents($url);
echo $html;

これで日本語ドメインpunycode変換してfile_get_contentsでhtmlを取得できます