まめ畑

ゆるゆると書いていきます

AWS Casual Talks#3に参加した

AWS

AWS Casula Tlaks#3に参加してきました。AWS Casual Talks #3 on Zusaar
2回目までは主催していたのですが、今回から主催をCookpadの星君に移して初めての開催でしたが、過去を超えてくる濃い・本気の内容ですごく良かったです。色々忙しい中ありがとうございます!

簡単にまとめると

メインセッション

@yoshiori Elastic Transcoder でウキウキ動画配信

クックパッド料理動画 を作った話。オンプレ環境で大容量・高トラフィックな配信環境を作った時の話しとAWSで作った際の話。オンプレ環境で実現する場合はクリアしなければいけない課題をAWSのサービスでどうクリアしたかという話でした。Elastic Transcoderの実用事例を聞けた貴重な機会でした。


@myfinder 僕らの AWS 移行記

オンプレ環境からAWSに完全移行した際のお話で、オンプレで使っていたものをAWSに移行する際にどう変えて移行を実施したか、非常に勉強になる話でした。AWSは完全にオンプレで実現出来ることをそのまま実現することは出来ないので、AWSベースな考えやシステム設計にしていくことになるのですが、何を使って何を使わないか、その判断の基準など非常に勉強になりました。
Managedサービスのセグメントを分けたり、Default VPCを使わなかった話など今後参考になる方多いのではないでしょうか。mackerelはAWSに親和性高いですね。

資料: https://github.com/myfinder/aws-casual-3

@imai_factory ナウい Kinesis とか DynamoDB の話 (仮)

本舗初公開のDynamoDBのパーティショニングの話を公開しました。DynamoDBはProvisioningされたスループットをどうパーティションで割り振るかや、Unitを下げた時にどういう動作をするか今まで公開されませんでしたが、今回ついに公開しました。スループットを下げた際に、パーティションのマージは行われず、ホットパーテションの問題が起こる可能性がありますが、こちらはスループット設計時にベースunitを指定し、バースト分に関しては今まで通りスループット向上をするという方法で問題無いかと思います。この辺の話が外で公開出来るようになったことで、DynamoDBのスループット設計やスループット増減戦略が行い易くなったのではないでしょうか。詳細は今後聞いていただければお手伝い出来るところかと。
Kinesis Client LibraryもPython版がでたり進化してますね。

LT

@takipone 参考にならないAWSに関するブログの書き方の話

AWSのサービスUpdateに追従してBlogを書いて頂いている、裏話。あまり今まで語られることがなかったので新鮮でした。

@yoshidashingo VPC by Default 時代のアクセス制御

Default VPCがリリースされて久しいですが、アクセス制御をどうするか、皆さん気になっているところだと思いますが参考になったのではないでしょうか。

@myfinder Redshift vs BigQuery

こちらはよく聞かれる質問ですが、LTでも話がでた、しっかりテーブル設計をしてクエリをしっかり設計してクエリを投げるのであれば、Redshift。しかしRedshiftおじさんが必要。そうでなく、そこまで複雑でないクエリならBQと、しっかりと要点抑えられたLTでした。内容的には同意で、ストリームアップデートなども考えると性能特性などをみて適材適所ですね。気軽にビックデータ系のサービスが使えるようになったのはすごいことだなぁと改めて思いました。

@kani_b Fight Against POODLE

POODLE対応の話。SSLv3を切るという対応がいいと言われていますが、実環境での難しさとAWS
での対応を探った話。CloudFrontとELBも実は対応完了しております。

@sgwr_dts DSLネタかDynamoDBネタ (仮)

DynamoDBの前にキャッシュ置くやつー というところで耳が痛い話でしたが、参考になるところが多かったのではないでしょうか。

まとめ

今まで以上に深い話や濃い話、AWSのdeepな話が会が終わった後も聞けたので個人的には非常に満足でした。個人的にも勉強になる話が多く、参考になりました。
今後もAWS Casual Talks続いて、Deepさがましていけばいいと思いました!

運営・発表者の皆様お疲れ様でした!!

S3とCORS

最近、AWSのサービスも少し様変わりしてきて、インフラレイヤーから、アプリレイヤーまで幅広くサービスが出てきています。SDKも充実してきていて、デバイスやブラウザから直接AWSサービスにアクセスして、S3にデータをUploadしたり、DynamoDBにデータを入れたり、Kinesisにログを流し込んだりなどなど今までサーバをかえして行っていた処理が突き詰めればサーバレスで行えるようになってきました。
もちろん、データを受け取って整形など複雑な処理を行いたいという場合には今まで通りAPIサーバなりを用意する方法になるかと思います。


ここで一つ問題になるのが、認証周りかと思います。例えば、ブラウザやデバイスから直接S3にデータをUploadしたり読み出したりするアプリがあった場合、S3にアクセスするための認証情報をセットする必要があります。このキーの管理はなかなか難しいところがありますが、今までだとTVMと呼ばれるIdentity Brokerを用意して一時的なキーを払い出すという方法がありました。今だと、先日独自認証プロバイダにも対応したAmazon Cognitoを使うことで簡単に実装出来ます。Congnitoは認証だけでなく、デバイス間でのデータ同期なども備えているため是非試してみてはいかがでしょうか。
実はCognitoはデバイスアプリだけで無く、Javascript SDKでも動作するようになりました
Use Amazon Cognito in your website for simple AWS authentication - AWS Developer Blog - Mobile

 window.fbAsyncInit = function () {
     FB.init({
         appId: 'xxx'
     });

     FB.login(function (response) {
         AWS.config.region = 'us-east-1';
         AWS.config.credentials = new AWS.CognitoIdentityCredentials({
             AccountId: 'xxxxxx',
             RoleArn: 'arn:aws:iam::xxx0:role/Cognito_FBTestAuthRole',
             IdentityPoolId: 'us-east-1:xxxxxxxxx',
             Logins: {
                 'graph.facebook.com': response.authResponse.accessToken
             }
         });

         fbUserId = response.authResponse.userID;
         console.log("FB ID: " + fbUserId);

         AWS.config.credentials.get(function(err) {
             if(!err) console.log("Congnito Identity Id: " + AWS.config.credentials.identityId);
             else console.log(err, err.stack);
         });

         s3 = new AWS.S3();
         // Uploadとか
     });
   };
  };

こんなかんじで、FBのアカウントと連携して作れます。このへんは今回の本題では無いので、詳細は省略します。

本題

画像なり動画なり大きなデータをブラウザから直接S3にUploadしたいという場合、S3に対してCORSの設定をすることになりますが、一点だけ注意点があります。

Bucketを作成してすぐにCORSを設定してJavascript SDK経由でアクセスすると、CORSが効いていないよなエラーが表示されて、リクエストが失敗します。

なぜかというと、ChromeだとDeveloper Consoleに以下のような出力が出ています

XMLHttpRequest cannot load https://BucketName.s3.amazonaws.com/?prefix=facebook-xxxx. The request was redirected to 'https://BucketName.s3-ap-northeast-1.amazonaws.com/?prefix=facebook-xxxx', which is disallowed for cross-origin requests that require preflight.

見てわかると通り、S3のエンドポイントのリダイレクト(s3共有ぽいURLからリージョンスペシフィックなURL)が起こっています。このリダイレクト先がCORSを引き継いでいないため失敗しています。
これはしばらくまつとリダイレクトされなくなり、CORSも効きアクセスが成功します。

もし、新規Bucketでうまくリクエストがいかないなぁという時に確認してみてはいかがでしょうか。

おまけ

CORSは以下のような感じでBucket Properties->Permissions->Edit CORS Configurationで設定します。
AllowedMethodは許可するものを選んでください。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

また、CORSとは違いますが、Bucket PolicyでこのFacebookのこのユーザIDの人は自分のバケットだけ操作出来るというIAMで使える変数もあるのでご活用ください。
IAM Policy Variables Overview - AWS Identity and Access Management

T2インスタンスがでたので簡単に性能をみてみた

AWS

昨日、EC2の新instance familyでT2シリーズが出ました。
今まで、t1.micro/m1.smallとか言われてたシリーズの現行版で、General Purposeにカテゴリも変更されています。

リリースは以下の記事
http://aws.amazon.com/blogs/aws/low-cost-burstable-ec2-instances/
http://aws.typepad.com/aws_japan/2014/07/low-cost-burstable-ec2-instances.html

置き換えは

t1.microをt2.microへ
m1.smallをt2.smallへ
m1.mediumをt2.mediumへ

という感じです。

特徴としては、CPU(ECU)がバーストするということです。
リリースにも書かれている通りのアルゴリズムでバーストします。

また、特徴として、HVMだけ受け付けるようになり、CPUも Intel(R) Xeon(R) CPU E5-2670 v2 @ 2.50GHz が使用されています。

普段は負荷が少ないけど、ある時間のみCPUをおもいっきり使用する様なケースに置いて有用なインスタンスだと思います。
先日発表されたSSD EBS (gp2)とあわせることで、起動時の速度EBSで、処理の速度向上をt2のバーストで行なうことで、起動や処理速度の向上が期待できます。

バーストを見てみた

t2.micro or t1.microでAmazon Linux を使ったUnix Benchをしてみました。実行中はバーストが常に起こる状態です。結果をわかりやすくするため、microを使いました。

 CPU 0: Intel(R) Xeon(R) CPU E5-2670 v2 @ 2.50GHz (5000.2 bogomips)
          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER/SYSEXIT, SYSCALL/SYSRET
   10:05:14 up 10 min,  1 user,  load average: 0.06, 0.05, 0.05; runlevel 3

------------------------------------------------------------------------
Benchmark Run: Tue Jul 01 2014 10:05:14 - 10:33:19
1 CPU in system; running 1 parallel copy of tests

Dhrystone 2 using register variables       35848981.6 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     4529.7 MWIPS (10.0 s, 7 samples)
Execl Throughput                               5337.1 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks       1159756.7 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          327710.4 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       3648669.1 KBps  (30.0 s, 2 samples)
Pipe Throughput                             2117176.4 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 384038.3 lps   (10.0 s, 7 samples)
Process Creation                              17517.4 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   7047.2 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                    970.8 lpm   (60.0 s, 2 samples)
System Call Overhead                        2707725.1 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   35848981.6   3071.9
Double-Precision Whetstone                       55.0       4529.7    823.6
Execl Throughput                                 43.0       5337.1   1241.2
File Copy 1024 bufsize 2000 maxblocks          3960.0    1159756.7   2928.7
File Copy 256 bufsize 500 maxblocks            1655.0     327710.4   1980.1
File Copy 4096 bufsize 8000 maxblocks          5800.0    3648669.1   6290.8
Pipe Throughput                               12440.0    2117176.4   1701.9
Pipe-based Context Switching                   4000.0     384038.3    960.1
Process Creation                                126.0      17517.4   1390.3
Shell Scripts (1 concurrent)                     42.4       7047.2   1662.1
Shell Scripts (8 concurrent)                      6.0        970.8   1618.0
System Call Overhead                          15000.0    2707725.1   1805.2
                                                                   ========
System Benchmarks Index Score                                        1813.3
CPU 0: Intel(R) Xeon(R) CPU E5-2650 0 @ 2.00GHz (3600.0 bogomips)
          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER/SYSEXIT, SYSCALL/SYSRET
   10:05:28 up 8 min,  1 user,  load average: 0.68, 0.22, 0.10; runlevel 3

------------------------------------------------------------------------
Benchmark Run: Tue Jul 01 2014 10:05:28 - 10:33:29
1 CPU in system; running 1 parallel copy of tests

Dhrystone 2 using register variables       20450227.0 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     2382.0 MWIPS (9.9 s, 7 samples)
Execl Throughput                               1034.8 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        190620.7 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           49930.0 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks        637706.3 KBps  (30.0 s, 2 samples)
Pipe Throughput                              275945.7 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                  52613.4 lps   (10.0 s, 7 samples)
Process Creation                                785.0 lps   (30.1 s, 2 samples)
Shell Scripts (1 concurrent)                    771.1 lpm   (60.3 s, 2 samples)
Shell Scripts (8 concurrent)                     59.9 lpm   (60.1 s, 2 samples)
System Call Overhead                          97154.5 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   20450227.0   1752.4
Double-Precision Whetstone                       55.0       2382.0    433.1
Execl Throughput                                 43.0       1034.8    240.6
File Copy 1024 bufsize 2000 maxblocks          3960.0     190620.7    481.4
File Copy 256 bufsize 500 maxblocks            1655.0      49930.0    301.7
File Copy 4096 bufsize 8000 maxblocks          5800.0     637706.3   1099.5
Pipe Throughput                               12440.0     275945.7    221.8
Pipe-based Context Switching                   4000.0      52613.4    131.5
Process Creation                                126.0        785.0     62.3
Shell Scripts (1 concurrent)                     42.4        771.1    181.9
Shell Scripts (8 concurrent)                      6.0         59.9     99.8
System Call Overhead                          15000.0      97154.5     64.8
                                                                   ========
System Benchmarks Index Score                                         250.9

CPU CreditとCPU Usage

CloudWatchで見ることができます。オレンジがt1.micro / 青が t2.microです。
f:id:con_mame:20140702214124p:plain
f:id:con_mame:20140702214128p:plain

Creditを使いきってみた

f:id:con_mame:20140702214213p:plain
f:id:con_mame:20140702214218p:plain
f:id:con_mame:20140702214217p:plain


見て分かる通り、バースト中でCPUを100%使える状態から、クレジットが減少してきてt2.microのベースラインである10%に綺麗にキャップされていく様子が見れると思います。
サーバ内ではstealの割合が上昇していき、90% stealという状態になりました。実際に使えるのが10%ということですね。
System Benchmarks Index Score は 3回の平均で700程度と落ち込み、10%に完全にキャップされた状態では、t2.microでunix benchが完走しない事もありました。

クレジットは1分ごとに各インスタンスタイプ毎に決められた割合で復活していきますので、バーストを必要としない状態になったら徐々に回復していきます。
リリースやドキュメントにもある通り

t2.micro - 144 (6 CPU Minutes / hour * 24 hours)
t2.small - 288 (12 CPU Minutes / hour * 24 hours)
t2.medium - 576 (24 CPU Minutes / hour * 24 hours)

まで貯めることが出来ます。(6 CPU Minutesなどが1分間の回復量です)

まとめ

今回のT2シリーズはバーストアルゴリズムが公開されていることも去ることながら、General Purposeにカテゴライズされていることも注目だと思っています。
普段はバーストしないが、バッチの瞬間だけおもいっきりCPU使いたいとか、ある処理の瞬間だけCPUをフルに使いたいという場合にちょうど良いのではないでしょうか。お財布にやさしい感じだと思っています。

しかし、今回はt2.microを使ったため極端な性能劣化が見受けられましたが、t2.small/mediumなどワークロードにあったインスタンスを要件に合わせて使うことが大事だと思います。

JAWS DAYS 2014で「これで最強のAWSに」のセッションをやりました

AWS

JAWS DAYS 2014のセッションとして、これで最強のAWSにというセッションをやりました。 Twitterなどの反応はこちらに2014/03/15 JAWS DAYS 2014 - 『これで最強のAWSに』セッション #jawsdays #最強のAWS - Togetterまとめ まとめて頂いています。各セッションの発表資料はタイムテーブルからリンクがあります。


このセッションは、普段AWSを使っている方々をお呼びして、使っているからこそわかるAWSのイマイチなところ、イケてるところ、バッドノウハウ、こうしたら・こうなったらもっと良くなるのにという話をして頂きました。当日はOFAのMilesさんと、AWS SAの大谷さんにもご参加頂き、直接要望や実際のところどうやったらいいのさ?という事を直接伝える場があったらなと思い企画しました。(企画の大本は実はre:Invent2013開催中のラスベガスの会場にて生まれました。その時、堀内さんが撮った写真がこちら)


AWSのイベントでざっくざっく切り込んで行くスタイルをやるのは3回目くらいですが、いつ突っ込まれるか毎回ヒヤヒヤものです。

また、120分ぶっ通しのセッションかつ、裏ではImmutable Infrastructureのパネルが行われており、セッションにどのくらい人が入ってくるか不安でしたが、実際始まってみると、常時立ち見が出る状態で、終了後やTwitterなどの反応・会場での人気投票でもかなり良い評価をいただけていたようでした。
これは本当に発表していただいた3名とMilesさん・大谷さんのおかげと思っています。(自由に話していただこうと、かなりふわっとざっくりとしたお願いしかしておらず申し訳なかったです…)

発表資料

ぜんぶ AWS でやらないワケ by DeNA 坂本 卓巳 さん

発表で印象だったのは、オンプレとAWSを透過的に扱えるツールがあること。オンプレ・AWSを同じように扱えるというのはとても大事なことだと思っていて、AWSを使うとなっても運用方法が大きく変わってしまうと、それだけでも結構なコストになってしまうと思います。また、MHAに比べるとRDSのフェイルオーバーはまだまだ時間がかかるというのは自分も同じ悩みを持っていて、Milesさんが言うには今はもっと時間短縮されているとのことですが、それでも数分のオーダー。。 re:InventでもRDSチームとMTGする機会があったのですが、そこでも切実にお願いしておいた案件です。
AutoScalingやRDS、CloudWatchなどオンプレと同じ構成で自前で運用しなくてもフルマネージドサービスとしてAWSには存在しますが、ブラックボックなため障害時の切り分けやAWSならではの制約・制限に引っかかり実はすんなり移行できない併用しにくい部分というのが存在します。コストにしても。
既存の環境でツールなどが作りこまれてると、AWSに移行したとしても、自前でコントロールしたほうが案外運用しやすかったりするものです。
発表を通して、同じ悩みを抱えてる…と思っていました。

What makes AWS invincible by フリークアウト 岩尾 はるか さん

50ms or dieのフリークアウトさんの発表。EC2インスタンス同士で低遅延で通信するというオプションが無いのは確かにそうで、Placement Groupが要件を満たせそうな感じがしますが、HPC向けインスタンスなどのハイスペックインスタンスしか使えないです。AWS内部のlatencyのゆらぎもここまでシビアな要件になるとかなり影響がでるのだろうなと聞いていました。
後は、AWSの管理周りの話。Management Consoleでポチポチやることもあるけれど、UIが絶妙な感じで、Stopの上にTerminateがあったり、CLIでもRoute tableやRoute53などいじる場合やEC2インスタンスを起動するだけでもわかりにくいオプションを使わないといけない。そして、AWSはインフラをコードで管理できるが、Sandboxなどのテスト環境が無いのが辛いという話は会場やTwitterでも共感の声が多かったように思います。(オプション指定が難しすぎる…ラッパーなどを書けばいいのでしょぅが…)
Mileさんが一番食いついたのは、Record & Play機能が欲しいというもので、Management Consoleの操作を記録して、コードなどにしてくれる機能。これは確かに欲しい…
Sandboxに関しては、Eucalyptusが使えるとMilesさんからの回答がありました。CLIならdru runがあると。IAMも少し前にポリシーをテスト出来る様になったのですが、EC2もクリティカルな場所はdry runだけでなく、テストしやすい方法があると良いなと思っています。

複数VPCでのベストプラクティス by クルートテクノロジーズ 宮崎 幸恵 さん

サイト毎に1アカウント1VPCという使い方。これはお金周りなどなどの事情によるものだそうで。。そして、今70VPCを管理しているという構成図を見てかなり驚きました…そして、それぞれのVPCがオンプレや監視を行ってるVPCと通信していて、通信にはVyattaにてVPN、ルーティングやNATが行われているという、そしてVPCも頻繁に増えたり消えたりと頭蕩けそうな感じでした…
AWS公式にVPCのIGWがVPC間ルーティングをサポートしてくれるとスッキリとした感じになると思うのは凄く同意です。後、事前アンケートでも多かった、サブネットのリサイズ。最初スモールスタートやオンプレとNW周りを合わせるために小さくサブネットを切ってしまうと、インスタンスが増えてきたり、ELBが増えると(ELBは5-6個IPアドレスを消費します)IPアドレスが足りなくなってしまい、リサイズが出来ないので、VPCなりサブネット作りなおして引っ越しとなってしまします。技術的に難しいのはわかるのですが、欲しい機能の1つです。
最初からどかんと大きくサブネットを切るというのも手なのですが、そうするとサブネット数が少なくなるのでこちらも中々悩ましいところです。

まとめ

今回、登壇をお願いした方々は、ソーシャルゲーム・アドテク・エンタープライズ系と三者三様で、AWSに求める部分もそれぞれの事業形態の観点で違っていて、聞いていて非常に参考になったと同時に、JAWS DAYSを通して、AWSは本当に様々な業界や形態で使われているというのを改めて実感しました。
それぞれの要求に答えていくことは非常に難しいことだとは思いますが、その中でも共通して共感できる部分というのも少なくは無く、その部分に関して直接中の人にフィードバックしてお伝え出来てよかったかなと思っています。
Milesさんも、発表を聞きながらgood b っていう場面が何回もあったり、それいいね!ということもありました。それぞれの質問にも丁寧に答えて頂き、セッション終了後も色々話して頂きました。

AWSを使い始めよう・使い始めたばかりという方には、こういうこともあるのか、とか、普段バリバリ使ってる方には、それやっぱありますよねーみたいな感じ思っていただければ嬉しいところです。

事前に行った、バッドノウハウアンケートでも予想以上の回答があり、いくつかは直接答えていただけました。こちらもアンケートにご協力いただいた方々ありがとうございます!
ちなみに、事前アンケートで一番多かったのは、EBSの性能周りで、容量を大きく(500GB以上)そして、IOPSも高く設定して、事前に全領域にddなどで書き込んでおかないと性能が…とかもう少し1本でIOPS出したいというものでした。
他にも、CloudFormationのテンプレートの仕様やInfini bandやRDMA使いたいなどもありました。意外とバッドノウハウ集まってます…
監視についても色々ありましたが、Milesさん的にはNagiosやzabbixなどと組み合わせて、CloudWatchを使って、CloudWatchはAWS内部で取得しているメトリクスを見るのに使うのに適してるとのこと。(最小監視間隔が1分で2週間しかログを保持しないためその辺の要望が多かったです) 監視も適材適所ですね。
AutoScalingに関しては、CloudWatchに頼らず、自前のスクリプトでMax/Minのキャパシティを調整するのがいいんじゃないかなぁとのことでした。


次に突っ込んだ話は、 AWS Casual Talks#2 で!
そして、こういうバッドノウハウなどのあまり外には出してない・出しにくいノウハウ共有は別の機会にまたガツンとやりたいと思っています!

ありがとうございました!

f:id:con_mame:20140317163527j:plain

気軽なMySQLバージョンアップ

このエントリーはMySQL Casual Advent Calendar 2013 10日目の記事です。カジュアル!
このへんでそろっとカジュアル詐欺と言われるのを防止するために、カジュアルな話を書いてみました。

MySQL5.6も正式リリースされてもうすぐ1年経ち、5.7の足音も聞こえてきている今日このごろですが皆様のMySQLのご機嫌はいかがでしょうか。
新機能や性能向上/bugfixに対応するためにMySQLのバージョンアップを行う機会や性能や不具合調査を行うことも多いかと思います。データベースのバージョンアップは特にメジャーバージョンアップの場合、パラメータのデフォルト値などの変更や仕様変更の影響(オプティマイザの変更)をアプリケーションが受けないか、性能の変化などを検証すると思います。

検証

実際に検証を行う場合、本番環境で流れているクエリをバージョンアップ先のDBに実際に流してみるのが確実かつ影響を確認しやすいと思います。しかし、これは結構難しかったりします。実際に発行されるクエリを集めるのが特に面倒。。
アプリケーション規模が小さい間は、少しアプリケーションを改修して発行されるSQLをログにだすとか、 general logを有効にしてDB側で記録してしまうというのも手なのですがパフォーマンスにも影響が出てしまう可能性があるのと、アプリケーション規模やアクセス量が大きくなるとログ量がすさまじいことになってしまいかねません。(収集するサーバへのリクエスト振り分け率を落としても。。)
また、せっかく集めてもアプリケーションの機能追加などは検証中も随時行われているため、新規発行クエリをまた集めないといけません。
これはカジュアルじゃないですね。

実際に移行してみた

先日とある大きなサービスの大きめのDBバージョンアップ(メジャーバージョン2アップ)とパラメータ調整を行った際に実際に使用した方法をご紹介します。(5.6へじゃないですよ…)

まず、DBのバージョンアップを行う場合以下の様な方法で行うと思います。

左側が旧環境、右が移行先です。
f:id:con_mame:20131208133507p:plain
現在稼働している旧Slaveの下にバージョンアップ後に使う新DB masterをSlaveとして、更にその下にSlaveをぶら下げます。(新Master達はバックアップやSnapshotから複製していきます。dumpからimportした場合でない場合は、mysql_upgradeを忘れずに)

切替時は、一旦メンテナンスモードなどに入れて、レプリケーションを切り、アプリケーションの接続先を変更します。
f:id:con_mame:20131208135921p:plain

これで完了となります。

Kage

メンテナンス前の検証やパフォーマンス・チューニングではKageを使用しました。
Kageについては
cookpad/kage · GitHub
Kageを使う時にやっておくと便利なこと - まめ畑
move to mysql5.6 // Speaker Deck
を見ていただくとわかりやすいですが、リクエストを複製して、2つのバックエンドサーバにリクエストを送り、レスポンスのdiffを取ったり、新アプリケーションのパフォーマンス計測を気軽に行うことが出来ます。ユーザさんへのレスポンスはオリジナルサーバからのものが返却されるため、カジュアルにテストを行うことが出来ます。

今回は、以下の様な構成でテストを行いました(赤線はバックアップ用の設定経路です)
f:id:con_mame:20131212211354p:plain

本番環境のproxyの下にKageサーバを配置し、その下に旧DB群につながっているアプリケーションサーバと、新DB群に繋がるアプリケーションサーバを配置しました。
新旧DBはレプリケーションされていますが、書き込みテスト時にレプリケーションエラーが発生することもあるので、最初はSELECTが殆どのページを先にテストしてしまい、その後全ページをテストするという方針で行いました。また、新Masterへ書き込みが起こるのでレプリケーションエラーも発生しますが、このテストでは、アプリケーションへの影響・パフォーマンス・オプティマイザまわりを見たいため、こちらは基本的に無視をしてレプリケーションを行うようにしました。

このテストでは、Kageサーバのパフォーマンスによっては全てのリクエストをさばけないため、Kageサーバへのリクエスト振り分け率は下げてあります。

そのためDBへの負荷は既存の本番サーバよりも低くなるため、負荷テストなどは別途行います。
そのためのSQLリストを取得するためにもこの構成は有用で、テスト用のサーバからはレスポンスがユーザさんへ返却されないため、SQLのログをアプリケーションサーバで出すように気軽に出来ます。DBのパラメータ・チューニングもカジュアルに出来ます。
この構成では検証用アプリケーションサーバもデプロイターゲットにしておくことで、新機能などで新規発行されるSQLもリアルタイムに受け付けることが出来るため、常に最新の状態を検証でき、サイトの動線やユーザさんの行動もシュミレーションではなく実際のものが取れるため、推測ではない実際のトランザクションをで検証が行えます。

ご存知の方も多いと思いますが、もし、新DBが5.6でGTIDをONにするぜ!!というナウいヤング方は、この構成ではONに出来ません。(レプリケーションクラスタ全体でONにする必要があるため)そのため、アプリケーションサーバの設定を切り替えるタイミングでレプリケーションを切るので、ここでGTIDをONにしてmysqlを再起動し有効後、CHANGE MASTERでauto positionをONにします。

Kageの設定

Kageの設定はすごく簡単で、ざっくりと

require 'kage'
require 'diff/lcs'

def compare(a, b)
  # 超カンタンにdiffとってますが、もう少し詳細にとって、fluentdなどで飛ばしてためたりする
  diffs = Diff::LCS.diff(a.split(/\n/), b.split(/\n/))
  diffs.each do |diff|
    diff.each do |line|
      p line
    end
  end
end

Kage::ProxyServer.start do |server|
  server.port = 8090
  server.host = '0.0.0.0'
  server.debug = false

  server.add_master_backend(:production, 'production-app', 80)
  server.add_backend(:newdb, 'newdb-app', 80)

  server.client_timeout = 15
  server.backend_timeout = 10

  server.on_select_backends do |request, headers|
    # GETかつpathが/adsで無いものだけ比較
    # ここではads決め打ちだが、リクエスト毎に内容が変わる可能性のあるpathは正規表現で除外
    if request[:method] == 'GET' && request[:path] != '/ads'
      [:production, :newdb]
    else
      [:production]
    end
  end

  # [:production, :newdb]が選ばれた際にここでdiffとったりログったり
  server.on_backends_finished do |backends, requests, responses|
    compare(responses[:production][:data], responses[:newdb][:data])
  end
end

この様な感じで、2つのバックエンドサーバのレスポンスを比較したりしています。
また、newdb-appではログレベルも変えてあり、負荷試験用にSQLログを出力させています。
compareのところで、bodyだけ取り出しレスポンスを比較したり、速度を見たりします。
その辺はお好みで色々いじれます。

もちろん、MySQLサーバのエラーログも忘れずに見ましょうね!

まとめ

MySQLのバージョンアップは色々と気を使う部分が多く、アプリケーションの開発速度が速いとさらに影響範囲を調べるのが手間になってしまいます。
しかし、Kageを使うことで、リアルタイムにクエリ状況を確認出来るため少しは手間が減るんじゃないでしょうか?
バージョンアップ以外にも、チューニングなどにも活用できます。

もちろんバージョンアップの際は
MySQL :: MySQL 5.5 Reference Manual :: 2.12.1.1 Upgrading from MySQL 5.1 to 5.5

MySQL Server 5.6 defaults changes (Supporting MySQL)
など、Changelogもちゃんと見ましょう!


明日は @kazeburo さんです!

AWS Casual Talks#1を開催しました

AWS

AWS Casual Talks#1を開催しました。
参加登録自体は15分程で枠が埋まってしまい、最終的に210人の方に登録を頂きました。
発表して頂いた方、参加頂いた方ありがとうございました!アンケートも多く集まり次回開催の参考にしようと思います。


AWS Casual Talksは、カジュアルにAWSとかその周辺の普段はあまり出てこない深い(深淵な)事を話す会を作ろうと思ったのが最初で、少し時間が空きましたが1回目を開催出来ました。
AWSの深淵な話からMBaaS・SWFまで幅広い感じで普段あまり一緒にならないテーマでカジュアルな雰囲気で終えることが出来ました。きわどい話もあったのは秘密です。
ただ、参加者管理と懇親会周りでごたついてしまい迷惑をかけてしまったので、次回は改善します。


次回は年明け速いうちにやろうかと考えています。
形式は発表 or 俺の考える〜 かなぁと。

会場だけで出したスライドにも書きましたが、Casualに初心者という意味は全くありません。

AWSさん会場提供ありがとうございました!

会場の天井が!

f:id:con_mame:20131102155505j:plain

EC2・オンプレ環境のMySQLからRDSのマイグレーションがやりやすくなった

本日
Amazon Web Services Blog: Migrate On-Premises MySQL Data to Amazon RDS (and back)
Importing Data From a MySQL Database Not Running in Amazon RDS - Amazon Relational Database Service
の発表があり、RDSに対して、オンプレミス環境・EC2上で動いているMySQLとのマイグレーションが行い易くなりました。

ただ、常にレプリケーションさせてというわけではなく、移行時に使うという用途です。

オンプレミス環境・EC2上で動いているMySQLとRDSでレプリケーションが可能になりました。
ドキュメントには環境・データサイズ毎のマイグレーションについて書かれているのでご一読下さい。

つまり
f:id:con_mame:20130906121306p:plain
このような構成が取れるようになりました。


RDS(MySQL5.6) -> EC2・オンプレ上のMySQLにもレプリケーションが可能です。
Using Replication to Export MySQL 5.6 Data - Amazon Relational Database Service
をご参照ください。手順は一般的なレプリケーションの設定と同じですが、Security Groupで接続元の開放が必要です。


簡単に試してみたので書いておきます。

こちらを使うことでDBをRDSに移行したいというときに、今までだと、サービスや書き込みを停止させ、dump -> importを行ってと時間がかかりましたが、バックアップなどからRDSを作成し、レプリケーションを追い付かせて、接続先の変更だけを行なうだけで良くなるので、サービスなどを止める時間を大幅に軽減出来ます。

制限

現在RDSでこの機能に対応しているMySQLのバージョンは

  • 5.5.33
  • 5.6.13

のみです。

他のバージョンではストアード・プロシージャーが入っていません。
現在のMySQLの最新版のみという感じです。

RDSはGTIDをONに出来ないので、GTID modeは有効に出来ません。

設定方法

通常のレプリケーションを組むのとあまり変わりは無いですが、

なのですが、RDSでレプリケーションの設定に関しては、通常のCHANGE MASTERやSTART / STOP SLAVEが使えません。
これらは用意されているストアード・プロシージャーを使用します。

 GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.0.%' IDENTIFIED BY 'slavepass';

接続元のIPアドレスは、VPC内であればRDSが所属しているサブネットのIPアドレスになります。

  • dump / impot
mysqldump -uhoge -p DB | mysql -hrds-database.xxxxxx.ap-northeast-1.rds.amazonaws.com -uhogehoge -pfugafuga -DDB

という感じで流し込めます。

もしくは一旦dumpしてなど。

サイズの大きなDBをimportする際は、一時的にRDSのパラメータグループで、innodbトランザクションやコミット周りの設定を変更しておくことでimportの時間が速くなりますが、安全ではないので、必ずもとに戻しておきます。
時間があるのであればそのままimportで問題ないです。

この時にmasterのbinlog名とポジションを控えておきます。

  • RDS側

mysql.rds_set_external_master - Amazon Relational Database Service
ここがRDS特有なのですが、CHANGE MASTERなどは権限がないためストアード・プロシージャーを使用します。

call mysql.rds_set_external_master('接続先DBのIPアドレス or FQDN',PORT,'USER','PASS','Binlog name',position,0);

最後の0はSSLを使うかどうかです、default 0は使用しない。1で使用する。

成功すると何も出てこないですが、

SHOW SLAVE STATUS;

レプリケーションの状態を確認します。

start / stop slaveは

call mysql.rds_start_replication;

を実行します

+-------------------------+
| Message                 |
+-------------------------+
| Slave running normally. |
+-------------------------+
1 row in set (1.04 sec)

このような感じでエラーがなければレプリケーションが開始されます。

stopは

call mysql.rds_stop_replication;
+---------------------------+
| Message                   |
+---------------------------+
| Slave is down or disabled |
+---------------------------+
1 row in set (1.02 sec)

となっています。


レプリケーションを解除する場合は

call mysql.rds_reset_external_master;

を実行します。
これは、内部でstop slaveとreset slave allを実行しています。

ストアード・プロシージャーの中身が気になる方は

show create procedure mysql.rds_set_external_master;

で見れます。

おまけ

現在

  • 5.5.33
  • 5.6.13

をストアード・プロシージャーが増えており

+-------+-----------------------------------+-----------+--------------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
| Db    | Name                              | Type      | Definer            | Modified            | Created             | Security_type | Comment | character_set_client | collation_connection | Database Collation |
+-------+-----------------------------------+-----------+--------------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
| mysql | rds_collect_global_status_history | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_disable_gsh_collector         | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_disable_gsh_rotation          | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_enable_gsh_collector          | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_enable_gsh_rotation           | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_external_master               | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_kill                          | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:33 | 2013-09-06 01:48:33 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_kill_query                    | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:33 | 2013-09-06 01:48:33 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_next_master_log               | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_reset_external_master         | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_rotate_general_log            | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:33 | 2013-09-06 01:48:33 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_rotate_global_status_history  | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_rotate_slow_log               | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:33 | 2013-09-06 01:48:33 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_set_configuration             | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:33 | 2013-09-06 01:48:33 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_set_external_master           | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_set_gsh_collector             | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_set_gsh_rotation              | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_show_configuration            | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:33 | 2013-09-06 01:48:33 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_skip_repl_error               | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:33 | 2013-09-06 01:48:33 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_start_replication             | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
| mysql | rds_stop_replication              | PROCEDURE | rdsadmin@localhost | 2013-09-06 01:48:39 | 2013-09-06 01:48:39 | DEFINER       |         | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
+-------+-----------------------------------+-----------+--------------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+

となっております。

対応していないバージョンのMySQLをRDSで使っている場合は、ModifyからバージョンをUpdateしたタイミングで作成されます。


レプリケーションを操作したログは

 select * from mysql.rds_history;
+---------------------+-----------------------+-------------------+---------------+--------------+-------------+--------------+------------------+----------------+------------+
| action_timestamp    | called_by_user        | action            | mysql_version | master_host  | master_port | master_user  | master_log_file  | master_log_pos | master_ssl |
+---------------------+-----------------------+-------------------+---------------+--------------+-------------+--------------+------------------+----------------+------------+
| 2013-09-06 01:49:01 | rdsadmin@localhost    | enable set master | 5.6.13        | NULL         |        NULL | rdsrepladmin | NULL             | NULL           |       NULL |
| 2013-09-06 01:58:57 | hogehoge@xxx.xxx.xxx.xxx | set master        | 5.6.13        | xxx.xxx.xxx.xxx |        3306 | repl         | mysql-bin.000001 | 1061           |          0 |
| 2013-09-06 01:59:30 | hogehoge@xxx.xxx.xxx.xxx | start slave       | 5.6.13        | NULL         |        NULL | NULL         | NULL             | NULL           |       NULL |
| 2013-09-06 01:59:55 | hogehoge@xxx.xxx.xxx.xxx | stop slave        | 5.6.13        | NULL         |        NULL | NULL         | NULL             | NULL           |       NULL |
| 2013-09-06 02:00:55 | hogehoge@xxx.xxx.xxx.xxx | start slave       | 5.6.13        | NULL         |        NULL | NULL         | NULL             | NULL           |       NULL |
+---------------------+-----------------------+-------------------+---------------+--------------+-------------+--------------+------------------+----------------+------------+

このテーブルに追加されていきます。

レプリケーションの状態は

select * from mysql.rds_replication_status;
+---------------------+-----------------------+-------------+---------------+--------------+-------------+
| action_timestamp    | called_by_user        | action      | mysql_version | master_host  | master_port |
+---------------------+-----------------------+-------------+---------------+--------------+-------------+
| 2013-09-06 04:26:32 | hogehoge@xxx.xxx.xxx.xxx | start slave | 5.6.13-log    | xxx.xxx.xxx.xxx |        3306 |
+---------------------+-----------------------+-------------+---------------+--------------+-------------+

を事項すると状態がとれます。

レプリケーションのエラーが起こった場合は、

show create procedure mysql.rds_skip_repl_error

でSET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;が実行されます。

レプリケーションのエラーは
f:id:con_mame:20130906134319p:plain
とManagement Consoleにも表示されます。

こういうのも出来ます

EC2やオンプレDB -> RDS -> ReadReplica

こちらは、上記の手順でレプリケーションを組んだ後にRRを作成するだけです。
f:id:con_mame:20130906121303p:plain

まとめ

RDSへのマイグレーションが今までよりも行いやすくなりました。サイズの大きなDBのdumpデータをS3にuploadして、S3から直接import出来ると便利だなぁと思いました。

しかし、あくまでマイグレーション用かなという感じで、Multi-AZ配置した場合にfailoverが行わた時や、Promoted Readreplicaについてはまだ検証していませんが、接続元のIPアドレスも変わりますし、レプリケーション情報も同期されていないと思うので、通常用途では検証の余地があるかと思います。
一時的に集計などで使う場合に簡単に状況に応じてスペックが変えやすいので、そういう場合は常にレプリケーションさせて置いていいかもしれません。

また、replicate-do-dbは設定出来ないので、既存のDBの一部テーブル・DBだけを移行用にレプリケーションというのが出来ないので、これが出来るようになると更に便利になるかと思います。