という話

技術ブログにしたい

9ヶ月で月間1000万PVにスケールするまでに躓いたこと

2月にベータ版を公開してから、9ヶ月(2014年11月)でPVが1000万を超えた記念。
サービスがスケールするにつれて、ググっても同じ悩みを持つ人が少なくなっていって問題解決に時間がかかった。
参考になるかは分からないけどメモ。
そんなの当たり前だろ!ってことも多いですが初めはそういうもんだということで。
お仕事で作ったサービスなのでサービス名は伏せときます。

時系列で躓いた点を上げていきます。まずはスペック

スペック

クラウド     : AWS, さくらクラウド
・言語       : PHP, javascript
フレームワーク  : FulePHP
・Webサーバー   : Apache(EC2)
・DBサーバー    : Mysql(RDS)
・キャッシュサーバー: Redis(EC2)

俺スペック

・PHPer歴2年
Linux歴2年


躓いたところ

画像の動的作成は非常に重い処理(2014年3月ごろ)

そんなに重い処理だとはつゆ知らず、URLに幅を指定してやれば動的に画像をリサイズする処理を入れてたんですが、すぐサーバー落ちました。
同時アクセス5くらいで落ちてましたw

対策:画像をアップロードするときにリサイズするようにした。
デザインが毎週コロコロ変わるとかで無ければアップロード時にリサイズした方がいいです。
計測してみたらHTMLをレンダリングするまでの時間が300ms位だったのに対し、画像1枚に300〜500ms(デカイ画像だと1秒)とかかかってた。
画像1枚の処理に、URLパースしてDB接続して色々計算してみたいな処理を全部終えるのと同じかそれ以上かかるわけです。
20枚画像あったら20倍ですよ、やばい。

webサーバー1台の限界(2014年4月ごろ)

この頃からグノシーさんとかに補足され始めてちらほらアクセスが集まって来ました。
それまではwebサーバー1台DBサーバー1台でやってて、アクセスが上がるたびに一回サービス止めてインスタンスを良い奴にして再起動みたいな事してました。
ですがある程度のスペックまで上げると、それ以上良いインスタンス使ってもアクセスが捌けなくなりました。

対策:負荷分散しました
このへんは4回に分けて記事書きました。

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


転送量が多すぎる(2014年9月ごろ)

PHPなどの処理はAWSで、画像などの静的ファイルは転送量課金が無いさくらクラウドから配信していたのですが、アクセスが集まると画像だけ非常に遅く表示されるようになりました。
ISDNの古き良き時代を思い出させるサービスとして、これはこれでいいかという気の持ちようで居たのですが上司からダメ出しをくらいました。
さくらクラウドの標準ネットワーク速度は100Mbpsなのでそれをぶっちぎってたわけです。

対策:サーバーの追加と静的ファイルの圧縮
単純に1台サーバーを追加すれば200Mbpsになるので、サーバーを追加しました。
それでは根本的な解決ではないので、静的ファイルを圧縮しました。
javascriptcssはGruntを使いminifyします。
静的な画像はPNGならtinypngで、JPEGoptimizillaで極限まで圧縮しました。
転送量が3分の1位まで減りました。サーバー費も浮きますね。

瞬間的アクセスで落ちる(2014年11月ごろから現在)

これはまだ解決しきれてない問題ですが一応。
iPhoneアプリのユーザーが増えてきてアプリでPUSHを送ると瞬間的(5秒間位)に秒間100アクセス以上あり、いつもは秒間5〜10アクセス位なので当然捌ききれず2,3分サービスがほぼ停止状態に陥る。

対策:データの持たせ方の変更と、サーバーの追加
この問題には複数の原因がありました。
・原因1
瞬間的アクセスがあるとすぐにDBが息しなくなるので原因調査したらデータの持たせ方に問題がありました。
アクセス数をページ毎に持たせていたのですが、1ページ1レコードでした。
Update文を発行すると対象行はロックされます。秒間100アクセスなのでロック待ちの処理が大量発生しレスポンスが返ってこなかったのです。
アクセス数を1ページ30レコード位に増やし、ランダムでインクリメントし、表示時は足して表示するようにしました。
これでロック待ちの処理は30分の1になりました。

・原因2
タイムアウトまでの時間が短すぎました。
タイムアウトを5秒に設定していたので高負荷時はレスポンスを返せませんでした。

・原因3
単純にWebサーバーの力不足。
平常時の秒間5アクセス位に合わせてサーバーを建ててるので瞬間的なアクセスには耐えられません。
オートスケールでは秒単位のアクセス増加には間に合いません。
サーバーをずっと建てとけばいいんですが、サーバー費がガッツリかかるのでそれも出来ません。
ここの折り合いがつかず、まだ解決しきれてません。


おわりに

元々プログラマとしてしか仕事してなかったのでサーバー構築・管理は未だに分からない事だらけです。
月間1000万PVとか昔は信じられなかったですが、意外と一人でもなんとかなるもんですね

3ヶ月AWS使ってでハマったこと

EC2とRDSとElastiCache位しか使ってないのでそんなにありませんけども、一応メモ。

RDS

Storage TypeにGeneral Purpose (SSD)というのがあるが、これは気をつけたい。
これを選択した状態でAllocated Storageを100GB未満の数値にすると性能が著しく落ちる時があります。
f:id:ichiy:20141208185151j:plain

青文字で書いてある部分に詳細が載っているですけどね。
英語分からないし、青文字で重要そうじゃないので読まずにハマっただけです、ハイ。

Redis on ElastiCache

リクエスト毎の性能差が凄いです。
これはRedisのせいみたいなんですが、EC2から同じデータをGETするのに早い時で10msec位、遅い時で200msec位でした。

AWS Redis on Elastic Cache のBenchmark をしてみた - tech.guitarrapc.cóm
上記の記事で非常に詳しくベンチマークされてて、とても参考になりました。

EC2

EC2というかAWS全体的なことなのかもしれませんが、EC2からEC2、またはEC2からElastiCacheなどへの転送速度の最大値が900MB/秒(bitじゃなくてbyte)くらい?っぽい。

ElastiCacheに色々ストアしてたんですが、ある程度でレスポンスタイムが頭打ちになったので調べてみたら、EC2へのNetwork Inの値が900MB/秒付近を境に上がらなくなったので限界なのかなーと。
これももしかしたらインスタンスタイプによって違うのかもしれません。

構造化データを追加したらGoogleさんがいっぱいクロールしてくれた

構造化データってのはschema.orgとかmicrodataとかってやつです。
リッチ スニペットと構造化データについて - ウェブマスター ツール ヘルプ
schema.org に関するよくある質問 - ウェブマスター ツール ヘルプ


色々小難しいことが書いてますが、僕は「HTMLに機械が理解出来る意味を持たせる」って言う風に認識してます。

例えば記事があったとして「このHTMLは記事だよー」って教えてあげることが出来ます。

実装

<div class="article">
  <a href="/article/123">
    <h1>記事のタイトル</h1>
  </a>

  <div class="article-body">
    記事の中身
  </div>
</div>

とても簡単ですが、こんな感じの記事があった場合

<div class="article-link"  itemscope itemtype="http://schema.org/Article">
  <a href="/article/123" itemprop="url">
    <h1 itemprop="name">記事のタイトル</h1>
  </a>

  <div class="article-body" itemprop="articleBody">
    記事の中身
  </div>
</div>

こんな感じに追加します。

itemscopeはスコープを定義します。divで定義しているので、このdivが閉じるまでがスコープです。
itemtypeは何を表しているかを定義します。"http://schema.org/Article"を指定してるので記事であると言っています。
itemscopeitemtypeはセットで定義します。
itempropはプロパティを定義します。リンクならurl、タイトルならname、記事の本文でアレばarticleBodyなどです。
詳しくはhttp://schema.org/を見てください。


どの位クロールしてくれたか

f:id:ichiy:20141024113444p:plain
定義する前は1日辺り1万ページくらいのクロールだったのが、記事とかリンクとかに構造化データを定義して2日目くらいに9万ページくらいになりました。
Googleさんにいっぱい見られてる・・・しゅごぉい・・・!


実際のページの数は2万ページも無いので、重複でクロールされまくってるわけです。
おすすめ記事とか関連記事とかで同じ記事へのリンクを構造化データで定義してるので当然といえば当然ですが。


この後ずっと毎日9万ページクロールされたのか?というとそんなわけなく、ほぼ元通りに落ち着きました。
f:id:ichiy:20141024121137p:plain

まとめ

実際クロールだけされてもインデックスされなきゃ意味ないんですがね。
僕はサービスを公開してから大分時間が経過した後、構造化データを追加したのでインデックス数などはほぼ変わりませんでした。
ですが、クローラーに「記事だよー」とか「関連リンクだよー」とか教えられるので、SEO的にはいいはずです。Googleさんも推奨してますし。。

何よりオープンしたてのサービスとかで、サイトマップ送ってもクロールしに来てくれないよーみたいな状況では有意かもしれません。

yum updateしたらtwitteroauthがエラーになる

CentOStwitteroauthを利用してる方は注意が必要かも。

これを書いてる時点で最新?のnss (3.16.1-7.el6_5)にアップデートすると、twitteroauthがエラーになります。
twitteroauthに限った話しじゃ無いと思いますが、調べてないのでとりあえず。


経緯

TwitterからAPIで検索するという処理が突然死んでて、原因調査してました。
Twitterの仕様変更か?とか最近話題になったTwiccaが弾かれるなど、色々想像しましたが、
実際にエラーメッセージを取得して見ると全然関係ないエラーが出てました

Problem with the SSL CA cert (path? access rights?)

調べてみるとnssってのが原因らしい。



ことの始まりはBash脆弱性です。
先週末にパッチが公開されてアップデートして安心!!って思ってたんですが、どうもまだ脆弱性が残ってたらしく、再びパッチが出てました。
そんでもっていつもどおり気にせず

# yum update

と、やっていました。

NSSの脆弱性

このアップデートを実行した時に実は別にNSS脆弱性に関するパッチも公開されており、それも一緒にアップデートしたのが原因でした。

cURLを実行するときにCentOSではOpenSSLの代わりにnssを使っているようで、そのせいでアップデートするとエラーになったのでした。


ただ修正方法が分からず、結局このへんを見てyumでアンドゥしました。
しかしこれだと公開済みの脆弱性を思いっきり放置してる状態なので大変危険です。

対策方法がわかったら追記します。
追記(2014/09/29 17:52):
とてつもなくあっけないオチですが、アパッチをリスタートしたら大丈夫でした。

一応手順としては

$ sudo yum update

を実行したあと

$ sudo service httpd restart

これだけで正常に動きました。ハイ。

ただ、AWSでエラーが出た状態と同じインスタンスを立ち上げてみたら同じ現象は再現出来ませんでした。
俺の3時間は一体何だったのか・・・。

ネットワーク初心者が、さくらクラウドから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に移行したら全部解決できるみたいな幻想があったんですが、勿論実際にはそんなことはなく、さくらクラウドのほうが優れている部分も多く、工夫次第でどうにかなるなぁと思いました。