@ijin

[Michael H. Oshita]

#HashiConf 2015に参加してきた

Portlandで開催されたHashiConf 2015に参加してきました。

Day 1

Keynote

Founder & CEOのMitchell Hashimotoが登壇。 今までのHashiCorpプロダクトを紹介した上で、新プロダクトの紹介!

Nomad

コンテナスケジューラ。ちょうどあるサービスの一部のDocker化でスケジューリング方法を考えていたので、グッドタイミング。

Otto

開発からデプロイまで対応したmicroservicesを念頭に入れたVagrantの後継。

Operating Consul as an Early Adopter

  • 初期の頃からconsulを運用した苦労話
  • v0.2から始めた
  • consule-template
    • スケールしない。v0.6ではマシに
    • 大きいクラスタで自身をDDOSする
    • watchesを使わないでcronで-once
  • consulのDNSが不安定な時期があったので、15秒毎にzone fileを書き出し内部DNSで運用
  • その他初期バージョンで諸々不具合を発見してArmonと一緒に修正
  • ご苦労様

HashiCorp Tools in the Modern Enterprise

  • エンプラだって頑張ってDevOpsしてるもん!
  • 文字多めで眠くなっちゃった。。
  • Izanamee イザナミ?

Resillient Infrastructure with Serf

  • Pagerdutyの人
  • SerfとChefと自社ツールを組み合わせて堅牢なインフラを構築
  • Blender - a modular remote command execution framework
  • SerfX - a bare minimum ruby client for serf

Genesis: Terraforming a new Firefox crash stat infrastructure

  • Mozillaの人達による漫才ベースのプレゼン
  • Firefoxのクラッシュ統計データを受信するインフラの構築について
  • 結構笑いがとれてた

The future of management, and how we’ll get there

Puppetの作者Lukeさん。未来に観するディープで知見溢れるトーク

Day 2

Keynote

HashiCorpの哲学とAtlasの説明(2日目は新製品の発表はなし)

Dockerizing all the Things

  • Docker社内でのCIでconsul使ってるよって話
  • あまり面白くなかった
  • 20分も残して終了。。

Automate your Infrastructure

以下のツールでいろいろ自動化してるよ(フーン)

  • Terraform
  • CircleCI
  • Docker (ECS)
  • Datadog
  • Slack

Managing Applications at Scale

  • CoreOSの人
  • Nomad vs Kubernetes
  • CLI demo

Repeatable, Extensible Infra at Yelp

  • YelpのSite Reliability Engineer
  • 内部ツールで起動、puppetでプロビジョニング
  • Packerやpuppet managed VPCだったけど、今はTerraform
  • Smartstack (Service discovery)
    • Nerve
    • Synapse
    • Hacheck
    • qdisc_tools
  • Sensu
  • nsone
  • terraform community modulesをたくさん書いたよ

Virtual Machines, Containers, Lambdas? Oh my!

  • AWSの中の人(DevOps担当)
  • Microservicesについて
  • 導入の判断基準
  • VM(EC2, Packer, Terraform/Cloudformatio, Consul)
  • Container (ECS, Nomad)
  • Lambda (サーバレスアーキテクチャ。例:SquirrelBin
  • さらっと自社サービスをたっくさん紹介した後、結論はLambdaとAPI Gateway押し
  • そんなにサービスを詰めこめなくても。。

感想

Nomadの発表が一番エキサイティングだったけど、こういうカンファレンスは中の人やスピーカーや他のユーザーと直接話せるのが醍醐味。プロダクトの担当者に直接フィードバックを伝えたり、展望を聞いたりできて楽しかったです。また、会場で話した参加者も多種多様でアメリカ以外だとスペイン、オーストラリア、ニュージーランド、インド、日本等がいて、世界中から注目されている感じでした。

第一回目ということで約300人の中規模だけど、このぐらいが皆の距離感近くて良い雰囲気。

その他

  • 懇親会で飛び込みLTしたかったが会場設備が対応できなく、断念
  • Portland心地良くて過ごしやすい!
  • 記念にもらったHashiCorpとハシ(箸)をかけたジュークは誰も理解してなかった (Mitchellが言うには日本人参加者が理解してくれるから良いんだと)

さて、来週はre:Inventだ!

ISUCON5の予選に記念参加してきた

とあるエンジニアが言い放ちました。

上位に届かないチームはただの記念参加だよねー。

というわけで、今年のISUCONは見事に予選落ちしました。

お題

ISUxi」というどこか懐かしい響きの「高負荷に耐えられるSNSコミュニティサイト」

友達、記事、コメント、足あと機能が揃っており、以前より複雑度が増したなかなかの凝った作り。

起こったこと

これはESIによるpartial cachingが出来るので、Varnishでやってみよう!

と意気込んだものの、エラーが解決できず結局は間に合わずに終了ーーっ。

やりたかったこと

  • Varnish + ESI + Redis & MySQL

やれたこと

具体的な作業内容は今手元にないので、ぼんやりと。

  • MySQLのクエリー修正、パラメータ、Indexの追加
  • nginxのパラメータ追加
  • kernelのパラメータ追加
  • 一部 redis化
  • rubyプロセスの調整
  • sidekiqのワーカーで遅延書き込み

はまったとこ

今回はいろいろ初めてがあったので無駄に時間を潰した感じ。

  • systemd - 最新のUbuntu 15.04はsystemdなんですね。ずっと14.04 LTSのupstartに慣れていたので、こっちは初めて触わった。
  • apparmor - 設定ファイルをsymlinkでやろうとすると読み込まれず。。こいつのせいだと気づくのにちょっと手間取った。いらない子には怒りのapt-get purgeを。
  • mysql - なんか設定ファイルが/etc/mysql/my.cnf単体じゃなくて、symlinkされたりいろんなディレクトリに散らばってたりで若干戸惑った。後、上記のapparmor関連で設定ファイルがしばらく全然反映されずに。。
  • varnish - こちらもvclやパラメータ指定が本来/etc/default/varnishで出来るはずが、なかなか反映されずに苦労した。Varnish 4.0のパッケージはapt-getですんなり入るんだけど、起動スクリプトが/etc/init.d/varnishに設置されるのに、そちらは無視され、systemdの方が優先される模様。カスタマイズするには/lib/systemd/system/varnish.serviceをコピって編集してdaemon-reloadが必要。詳しくはこちら

終わりに

競技内容が確実に進化していて、非常ーーに楽しめました!その分、出題者の苦労が計り知れず。。こんどビールでも奢ります。今年の本戦は残念ながら行けないけど、外野として楽しくポップコーンでも食べながら観戦したい所ですね。

おまけ

現在はHashiConfに向けての飛行機の中だけど、悔しいので機内で復習しておきます!

YAPC::Asia Tokyo 2015に参加してきた

例年この時期は海外にいるので、なかなか行けなかったYAPC::Asia Tokyo 2015にやっと参加してきた。

スケジュール上、今年は参加できるぞって意気込んでいたら、まさかのSold Out…

それをtwitter上で嘆いていたら、@kenjiskywalkerさんから救いの手が!

感謝!

さて、一口コメント

Consulと自作OSSを活用した100台規模のWebサービス運用] - @fujiwara

mamiyaAWS CodeDeployにインスパイアされたstretcherを使ったイベントベースのdeploy周りが面白かった。s3からの取得失敗時の処理は考えてないといけない。

Conway’s Law of Distributed Work - Casey West

最近はリモートワークが殆どなので、なかなか共感できる部分が多かった。コミュニケーション大事。

大規模でも小中規模サービスでも捗る microservices な Web サービスのつくりかた - @Yappo

どのタイミングでコンポーネントの分割をするか。ちゃんと設計しようねって話

ISUCONの勝ち方 - @kazeburo

ポイントがよく纏められていて、うちらのチームでも多くを実践していた。まだ勝ててないけど。 CPUやB+ Treeの気持ちになって考える事が大事。

我々はどのように冗長化を失敗したのか - @kenjiskywalker

Networkが不安定だと、様々な冗長化に仕組みがうまく作動しない。検証はProductionと同じ環境でやりましょう。

Profiling & Optimizing in Go - Brad Fitzpatrick

Bradさんのライブコーディング。奥が深かった。

LT

どれもこれもハイレベル!

特に素晴らしかったのが、テンポの良い@yoku0825さんのMySQL 5.7の罠があなたを狙っている と超早業を披露したCONBUさんのCONBUの道具箱


いやー、非常に楽しめました。運営の皆様、ありがとうございました!!

さて、これから出国ー。

GitHubのeventをLambdaで処理してSlackへ通知

ちょっと前にGitHubのeventをAWS Lambdaで処理して、GitHubやSlackのAPIを叩く仕組みを作ったので、メモ。

材料

  • Github
  • SNS
  • KMS
  • Lambda
  • Slack

やりたいことはこんな感じ。

あるGitHubリポジトリのissuesに特定のコメントが書き込まれると、そのユーザはプロジェクトのteamに自動で追加されて、Slackへ通知が流れるというモノです。

SNS

まずは媒介となるSNSの作成。

1
2
3
4
$ aws sns create-topic --name github --region ap-northeast-1
{
    "TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:github"
}

次にSNSに対してpublishできるIAM userを作成

IAM Policy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "sns:Publish"
      ],
      "Sid": "Stmt0000000000000",
      "Resource": [
        "arn:aws:sns:ap-northeast-1:123456789012:github"
      ],
      "Effect": "Allow"
    }
  ]
}

GitHub

  • organization: my_org
  • repository: test
  • team: reader

SNS連携

Webhooks & Services からAmazonSNSと連携

AWS KEYには先ほど作成したIAMユーザのを利用。SNS topicのarnにはregionが書かれているにも関わらず、GitHubの方では明示的に指定が必要。

通知するeventの有効化

さて、GitHubではSNSの場合、hooksのjsonにある通り、push時のeventにしか対応していないので、

hooks link
1
2
3
4
"name": "amazonsns",
"events": [
  "push"
],

GitHubのWebhook APIに従ってissue_commentを追加してやります。

先ほどのSNS連携のhook idを取得するにはGET /orgs/:org/hooks

1
2
export HOOK_ID=$(curl -H 'Uer-Agent: ijin' -X GET -s -H "Authorization: token xxxxxxxxxx" \
https://api.github.com/repos/my_org/test/hooks | jq '.[].id')

編集するにはPATCH /orgs/:org/hooks/:id

1
2
curl -H 'Uer-Agent: ijin' -X PATCH -s -H "Authorization: token xxxxxxxxxx" \
https://api.github.com/repos/my_org/test/hooks/$HOOK_ID -d '{"add_events": ["issue_comment"]}' | jq .

Web UIからは分からないので、ついでにreader teamのIDも取得しておく

1
2
curl -H 'Uer-Agent: ijin' -X GET -s -H "Authorization: token xxxxxxxxxx" \
https://api.github.com/orgs/my_org/teams | jq '.[] | select(.name=="reader")'

(※)User-Agentは必須

これで、誰かがコメントをした時にもSNSが飛びます。

KMS

lambdaでは以下の認証情報を使うので、予めKMSで暗号化しておく。

  • GitHub token
  • Slack webhook

rubyで暗号化する場合

1
2
3
4
require 'aws-sdk'
require 'base64'
kms = Aws::KMS::Client.new(region: 'us-east-1')
Base64.encode64 kms.encrypt(key_id: "alias/ijin", plaintext: 'my plain text code').ciphertext_blob

javascriptの場合

1
2
3
4
5
6
7
var aws = require('aws-sdk');
var kms = new aws.KMS({ region: 'us-east-1' });
var text = 'my plain text code';
kms.encrypt({KeyId: 'alias/ijin', Plaintext: text}, function(err, data) {
  if (err) console.log(err, err.stack);
  else console.log(data.CiphertextBlob.toString('base64'));
});

こうしておくと、SCMに入れても安心。

また、KMSキーの実行権限もlambdaのroleに紐づけておく。

Lambda

Lambda function作成時にはSNSをevent sourceとして指定。

(※) KMSは現在us-eastにしかないので、そこ以外のregionでlambdaを実行する場合は、timeoutは若干長めに指定して置くと良さげ

コードはこんな感じ。

  1. GitHubからSNS hookを受け取って
  2. コメントした内容がjoinの場合
  3. KMSによってGitHubのtokenを復号化し
  4. そのユーザをteamへ追加する
  5. その後、別lambda functionでslackへ通知する

nodeのlibraryを使うともっとスッキリ書けたけど、1 function 1 fileで纏めたかったのでやや冗長なコードになっちゃいました。。

実行

GitHubでコメント

Lambda発動

1
2
3
4
5
6
7
8
9
10
11
2015-08-11T15:42:53.108Z   a09e3c80-403f-1e15-bbb5-55b693433c0e    user: ijin2
2015-08-11T15:42:53.108Z  a09e3c80-403f-1e15-bbb5-55b693433c0e    comment: join
2015-08-11T15:42:55.417Z  a09e3c80-403f-1e15-bbb5-55b693433c0e    status code: 200
2015-08-11T15:42:55.418Z  a09e3c80-403f-1e15-bbb5-55b693433c0e    response:
{
    "state": "pending",
    "url": "https://api.github.com/teams/1234567/memberships/ijin2"
}
2015-08-11T15:42:55.418Z  a09e3c80-403f-1e15-bbb5-55b693433c0e    Added to the team
END RequestId: a09e3c80-403f-1e15-bbb5-55b693433c0e
REPORT RequestId: a09e3c80-403f-1e15-bbb5-55b693433c0e Duration: 5211.48 ms Billed Duration: 5300 ms Memory Size: 128 MB  Max Memory Used: 14 MB   
1
2
3
4
5
6
7
8
9
10
11
2015-08-11T15:42:56.058Z   a25c66fc-403f-11e5-b291-25d4ee441689    Received event:
{
    "username": "ijin2",
    "icon_url": "https://avatars.githubusercontent.com/u/12809425?v=3",
    "text": "Added to the team"
}
2015-08-11T15:42:58.310Z  a25c66fc-403f-1e15-b291-25d4ee441689    200
2015-08-11T15:42:58.311Z  a25c66fc-403f-1e15-b291-25d4ee441689    ok
2015-08-11T15:42:58.311Z  a25c66fc-403f-1e15-b291-25d4ee441689    Successfully posted to Slack!
END RequestId: a25c66fc-403f-11e5-b291-25d4ee441689
REPORT RequestId: a25c66fc-403f-1e15-b291-25d4ee441689 Duration: 2268.06 ms Billed Duration: 2300 ms Memory Size: 128 MB  Max Memory Used: 14 MB   

teamへの追加(招待)

Slackへ通知

結論

簡単にできますね。実はこんな風に作っちゃった2週間後ぐらいにAWSの人も似たようなブログを書いていた事を発見しましたが。まあ、こっちはKMSとSlack使ってるので。。

後、KMSのアイコンが欲しい!

Data PipelineによるDynamoDBのexport

ちょっとハマったのでメモ。

DynamoDBにはRDSみたいなスナップショットによるバックアップ機能がなく、データを一括でexportするにはフルスキャンしかありません。 AWSではData Pipelineによるs3へのexportテンプレートがあって、それを使うとEMRクラスタが立ち上がりHive経由で大量の処理をして、s3へ書き出してくれます。

1000万件程度の小さな件数だとデフォルトのテンプレートがそのまま使えるけど、1億件近くになると失敗したりタイムアウトしたりするので、パラメータの調整が必要になってきます。

前提

  • 約1億件
  • 20GB
  • Provisioned Throughput (reads): 1000
  • Read Throughput Percent: 1.0
  • 2時間以内のexport

エラー

具体的には以下のようなエラーに遭遇しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: Hive Runtime Error
 while processing row {"item":{"id_list":"{\"l\":[{\"n\":\"958\"},
{\"n\":\"704\"},{\"n\":\"847\"},{\"n\":\"232\"},{\"n\":\"72\"}]}",
"code":"{\"s\":\"adarea9\"}","user_area":"{\"s\":\"91657-adarea9\"}",
"user":"{\"s\":\"91657\"}","app_code":"{\"s\":\"xxx\"}","last_seen_at":
"{\"s\":\"2010-06-23 22:57:49 +0000\"}","target_id":"{\"n\":\"395\"}",
"count":"{\"n\":\"44\"}","promo_id":"{\"n\":\"125\"}"}} at 
org.apache.hadoop.hive.ql.exec.MapOperator.process(MapOperator.java:550) at 
org.apache.hadoop.hive.ql.exec.mr.ExecMapper.map(ExecMapper.java:177) 
... 8 more Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: 
java.io.IOException: All datanodes 10.160.102.191:9200 are bad. Aborting... at 
org.apache.hadoop.hive.ql.exec.FileSinkOperator.processOp(FileSinkOperator.java:651) at 
org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:793) at org.apach
1
2
3
4
5
6
7
8
9
10
11
12
2015-06-29 13:33:31,610 Stage-1 map = 100%, reduce = 0% MapReduce Total cumulative 
CPU time: 14 minutes 19 seconds 0 msec Ended Job = job_1435578726935_0002 with 
errors Error during job, obtaining debugging information... 
Examining task ID: task_1435578726935_0002_m_000008 (and more) from job job_1435578726935_0002 
Examining task ID: task_1435578726935_0002_m_000000 (and more) from job job_1435578726935_0002 
Examining task ID: task_1435578726935_0002_m_000000 (and more) from job job_1435578726935_0002 
Task with the most failures(4): 
----- Task ID: task_1435578726935_0002_m_000003 URL: http://ip-10-160-25-23.ap-northeast-1.compute.
internal:9026/taskdetails.jsp?jobid=job_1435578726935_0002&tipid=task_1435578726935_0002_m_000003
----- Diagnostic Messages for this Task: Error: GC overhead limit exceeded FAILED: 
Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask 
MapReduce Jobs Launched: Job 0: Map: 10 Cumulative CPU: 859.0 sec HDFS Read: 0 HDFS Write: 0 FAIL Total MapRed
1
2
3
4
5
6
7
8
9
10
11
12
2015-06-30 02:32:17,929 Stage-1 map = 100%, reduce = 0%, Cumulative CPU 1605.94 sec 
MapReduce Total cumulative CPU time: 26 minutes 45 seconds 940 msec Ended Job = 
job_1435627213542_0001 with errors Error during job, obtaining debugging information... 
Examining task ID: task_1435627213542_0001_m_000004 (and more) from job job_1435627213542_0001 
Examining task ID: task_1435627213542_0001_m_000004 (and more) from job job_1435627213542_0001 
Examining task ID: task_1435627213542_0001_m_000004 (and more) from job job_1435627213542_0001 
Task with the most failures(4): ----- Task ID: task_1435627213542_0001_m_000000 URL: 
http://ip-10-150-205-59.ap-northeast-1.compute.internal:9026/taskdetails.jsp?
jobid=job_1435627213542_0001&tipid=task_1435627213542_0001_m_000000 ----- 
Diagnostic Messages for this Task: AttemptID:attempt_1435627213542_0001_m_000000_3 
Timed out after 600 secs FAILED: Execution Error, return code 2 from 
org.apache.hadoop.hive.ql.exec.mr.MapRedTask MapReduce Jobs Launched: Job 0: Map: 10 Cu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Error: java.lang.RuntimeException: Hive Runtime Error while closing operators at 
org.apache.hadoop.hive.ql.exec.mr.ExecMapper.close(ExecMapper.java:260) at 
org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:81) at 
org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:432) at 
org.apache.hadoop.mapred.MapTask.run(MapTask.java:343) at 
org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:175) at 
java.security.AccessController.doPrivileged(Native Method) at 
javax.security.auth.Subject.doAs(Subject.java:415) at 
org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1548) at 
org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:170) 
Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: 
java.io.IOException: All datanodes 10.186.28.181:9200 are bad. 
Aborting... at org.apache.hadoop.hive.ql.exec.FileSinkOperator$FSPaths.closeWriters(FileSinkOperator.java:168) at 
org.apache.hadoop.hive.ql.exec.FileSinkOperator.closeOp(FileSinkOperator.java:882) at org.apache.hadoop.

Hive Runtime ErrorやGCエラー等が出てますね。

原因

通常のexportテンプレートではEMRはなんとm1.mediumのcore taskが一台のみ起動して処理が走ります。 各種ヒープサイズの設定(YARN_RESOURCEMANAGER_HEAPSIZE 等)はinstance typeによって決まっており、この件数とデータサイズではHEAPSIZEが不足し、GCエラー等が発生してOut of Memory状態になって処理が落ちるようです。 そこで、メモリをもっと搭載している大きめのインスタンスでHEAPSIZEを確保してあげる必要があります。

解決策

こんな感じ。

parameter default value new value
core & master instance type m1.medium m3.xlarge
core instance count 1 2
AMI version 3.3.2 3.8.0

m3.xlargeにした事で処理が落ちる事なくスムーズに実行されるようになりました。core countを増やしたのは、exportテンプレートのデフォルト設定だとcountが1なので、mapperが不足し、DynamoDBで設定したthroughput (1000)をフルに使い切る事ができなく、デフォルトのタイムアウト時間(2時間)に達して処理自体がキャンセルされてしまうからです。EMR側のスループットも上げる為に必要な変更でした。また、HadoopのAMI versionも古い3.3.2から最新の3.8.0にしてあります。

これらによって、export処理がだいたい1時間ちょいで完了します。

その時の試行錯誤がこれ。

計算

provisioned throughputに対するバックアップ時間の目安を計算するには以下の通り。

20GBのデータ、1億件のレコード、1000 throughputとして、

平均item size = 20*1024*1024*1024/100000000 =~ 215 byte

4KB以下なので4KB blockのreadとなります。 Hive Queryのread処理はeventually consistentになるので、1 IOPSに対して8KBのデータが読み込めます。 そうすると

DynamoDB scan時間 = (20*1024*1024*1024)/(1000*8*1024*60) = 43.7分

実際にはEMRクラスタのオーバーヘッドが20分弱程度あるので、これに若干加算します。

図にするとこんな風になります。

バックアップのタイミングでDynamoDBのthroughputをガツンと上げれば、件数によっては短時間で済む場合もあるので、参考にでも!

(※ Production Trafficに影響がないように、Read Throughput Percentは適切に設定する必要があります)

EC2 Auto Recoveryの注意点

先日、EC2のAuto Recoveryでちょっとハマったのでメモ。

CloudwatchのStatusCheckFailed_Systemアラームを設定すると、インスタンスを自動的に復旧してくれるEC2 Auto Recoveryという機能があり、使うためには条件がいくつかあります。

  • 特定のリージョン
  • C3, C4, M3, R3, T2 instances
  • VPC
  • 共有tenancy
  • EBSストレージのみのサーバ

Recover Your Instance

しかし、上記を満たしているのに、特定のAMIをCLI経由で起動するとEC2 Auto Recoveryを設定できなくなります。

(AWSコンソールでラジオボタンが押せない。CLIで設定しても効かない)

原因はAMIにephemeral disk等のblock device mappingが設定されていて、T2やC4等のEBS onlyなinstance typeで起動しているにも関わらず、AWS側がephemeral diskが付与されていると認識してしまう所にあります。なお、AWSコンソールからの起動だとこの現象は発生しません。

AMIでblock device mappingが埋め込まれている

aws ec2 describe-images --image-ids ami-e74b60e6 --region ap-northeast-1

本来はEBS onlyなinstance typeだとblock device mappingの設定如何に関わらず、付与自体が不可能なので、全く関係ないはずです。

解決方法は現時点(2015/5/1)では3通り

  • extraなmappingが設定されていないAMIを使う(Amazon Linux等)
  • AWSコンソールから起動する
  • 明示的に--block-device-mappingsパラメータでNoDeviceと指定 aws ec2 run-instances --image-id ami-e74b60e6 --instance-type t2.small --subnet-id subnet-xxxxxxxx --block-device-mappings "[{\"DeviceName\": \"/dev/sdb\", \"NoDevice\": \"\"}, {\"DeviceName\": \"/dev/sdc\", \"NoDevice\": \"\"}]"

これは明らかにAWS側のバグなので早く治って欲しいものですね。

Auto Scalingによる自動復旧(AWS Lambda+SNS編)

先週のAWS Summit San Fransiscoにて、ついにLambdaがSNSに対応しました。 様々なサービスが発表された中、個人的にはこれが一番のヒットです!というのも、この機能によってAWS間のサービスがより連携しやすくなり、新しいリアクティブなアーキテクチャをどんどん実現できそうだからです。

というわけで、少し試してみました。

お題は去年12月に試したAutoScaling + Lambda。(当時はLambdaはまだこの機能がなかったのでSNS→SQSにてイベントをプロセスする仕組みを作りました。)

SNS連携によって前回のこれが

こうなります。(Lambdaのアイコンが出たので差し替えてます)

うーん、シンプル!

設定

前回とほぼ同様。

SNS作成

1
2
3
4
$ aws sns create-topic --name instance-alert --region ap-northeast-1
{
    "TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:instance-alert"
}

LambdaとSNS連携できるようにポリシーを付与

1
2
3
4
5
6
$ aws lambda add-permission --function-name makeASUnhealty --statement-id sns-instance-alert \
--action "lambda:invokeFunction" --principal sns.amazonaws.com \
--source-arn arn:aws:sns:ap-northeast-1:123456789012:instance-alert --region us-west-2                                                                                                                                                                                                  
{
    "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:sns:ap-northeast-1:123456789012:instance-alert\"}},\"Resource\":\"arn:aws:lambda:us-west-2:123456789012:function:makeASUnhealty\",\"Action\":[\"lambda:invokeFunction\"],\"Principal\":{\"Service\":\"sns.amazonaws.com\"},\"Sid\":\"sns-instance-alert\",\"Effect\":\"Allow\"}"
}

Subscribe

1
2
3
4
5
$ aws sns subscribe --topic-arn arn:aws:sns:ap-northeast-1:123456789012:instance- --protocol lambda \
--notification-endpoint arn:aws:lambda:us-west-2:123456789012:function:makeASUnhealty --region ap-northeast-1
{
    "SubscriptionArn": "arn:aws:sns:ap-northeast-1:123456789012:as-test:4b22eec6-aeb5-4421-7a2f-99ca33a4b8ab"
}

aws cliはのヘルプにはまだSNSをLambdaへsubscribeするやり方は書いてませんが、上記のようにやればできます。 Thanks Eric!

EC2 Status Check

1
2
3
4
5
6
7
$ export INSTANCE=i-xxxxxxxx
$ aws cloudwatch put-metric-alarm --alarm-name StatusCheckFailed-Alarm-for-$INSTANCE \
--alarm-description "Instance $INSTANCE has failed" --metric-name StatusCheckFailed \
--namespace AWS/EC2 --statistic Maximum --dimensions Name=InstanceId,Value=$INSTANCE \
--period 60 --unit Count --evaluation-periods 2 --threshold 1 --comparison-operator \
  GreaterThanOrEqualToThreshold --alarm-actions arn:aws:sns:ap-northeast-1:560336700862:instance-alert \
--region ap-northeast-1

Lambda Function

自動復旧

通信を遮断し、Status Check Failを発動させる

1
2
$ date; sudo ifdown eth0
Fri Apr 17 03:08:39 UTC 2015

EC2 Status Check。2分でfail検知

1
2
3
4
5
6
7
Fri Apr 17 12:10:25 JST 2015
ok
DETAILS reachability    passed

Fri Apr 17 12:10:31 JST 2015
impaired
DETAILS 2015-04-17T03:10:00.000Z        reachability    failed

SNS通知。さらに2分ちょい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Alarm Details:
- Name:                       StatusCheckFailed-Alarm-for-i-xxxxxxxx
- Description:                Instance i-xxxxxxxx has failed
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 2 datapoints were greater than or equal to the threshold (1.0). The most recent datapoints: [1.0, 1.0].
- Timestamp:                  Friday 17 April, 2015 03:13:09 UTC
- AWS Account:                123456789012

Threshold:
- The alarm is in the ALARM state when the metric is GreaterThanOrEqualToThreshold 1.0 for 60 seconds.

Monitored Metric:
- MetricNamespace:            AWS/EC2
- MetricName:                 StatusCheckFailed
- Dimensions:                 [InstanceId = i-xxxxxxxx]
- Period:                     60 seconds
- Statistic:                  Maximum
- Unit:                       Count

Lambdaログ

1
2
3
4
2015-04-17T03:13:14.504Z  ac9ed52f-e4af-1e14-b826-ee9008a99db9   Received event:..
2015-04-17T03:13:14.504Z  ace9d52f-e4af-1e14-b826-ee9008a99db9    Changing instance health for: i-xxxxxxxx
2015-04-17T03:13:15.682Z  ace9d25f-e4af-1e14-b826-ee9008a99db9    { ResponseMetadata: { RequestId: 'b0194dfb-e4af-1e14-895f-abdf96b0b593' } }
2015-04-17T03:13:15.684Z  ace9d25f-e4af-1e14-b826-ee9008a99db9    result: ""

タイムスタンプによるとSNS発砲されてたからLambda発火まで5秒!

Auto ScalingのHealth Status

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Fri Apr 17 12:13:10 JST 2015
as-sg   ap-northeast-1a HEALTHY i-ce02563d      as-lc   InService

Fri Apr 17 12:13:15 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   InService

Fri Apr 17 12:13:20 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   InService

Fri Apr 17 12:13:26 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   InService

Fri Apr 17 12:13:31 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   InService

Fri Apr 17 12:13:37 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   Terminating

Fri Apr 17 12:13:43 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   Terminating

Fri Apr 17 12:13:49 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   Terminating

Fri Apr 17 12:13:54 JST 2015
as-sg   ap-northeast-1a UNHEALTHY       i-ce02563d      as-lc   Terminating

Fri Apr 17 12:13:59 JST 2015

Fri Apr 17 12:14:05 JST 2015
as-sg   ap-northeast-1a HEALTHY i-525601a1      as-lc   Pending

Fri Apr 17 12:14:10 JST 2015
as-sg   ap-northeast-1a HEALTHY i-525601a1      as-lc   Pending

Fri Apr 17 12:14:16 JST 2015
as-sg   ap-northeast-1a HEALTHY i-525601a1      as-lc   Pending

Fri Apr 17 12:14:21 JST 2015
as-sg   ap-northeast-1a HEALTHY i-525601a1      as-lc   Pending

Fri Apr 17 12:14:26 JST 2015
as-sg   ap-northeast-1a HEALTHY i-525601a1      as-lc   Pending

Fri Apr 17 12:14:32 JST 2015
as-sg   ap-northeast-1a HEALTHY i-525601a1      as-lc   Pending

Fri Apr 17 12:14:37 JST 2015
as-sg   ap-northeast-1a HEALTHY i-525601a1      as-lc   InService

ちゃんとTerminateされてリプレースされてますね。

AutoScalingの通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Service: AWS Auto Scaling
Time: 2015-04-17T03:13:59.367Z
RequestId: efa97137-fa15-4aa4-9c8c-5241961a2d0e
Event: autoscaling:EC2_INSTANCE_TERMINATE
AccountId: 123456789012
AutoScalingGroupName: as-sg
AutoScalingGroupARN: arn:aws:autoscaling:ap-northeast-1:123456789012:autoScalingGroup:c395c157-3a7e-4d56-287b-5ad9b26eb464:autoScalingGroupName/as-sg
ActivityId: efa97137-fa15-4aa4-9c8c-5241961a2d0e
Description: Terminating EC2 instance: i-xxxxxxxx
Cause: At 2015-04-17T03:13:36Z an instance was taken out of service in response to a user health-check.
StartTime: 2015-04-17T03:13:36.342Z
EndTime: 2015-04-17T03:13:59.367Z
StatusCode: InProgress
StatusMessage:
Progress: 50
EC2InstanceId: i-xxxxxxxx
Details: {"Availability Zone":"ap-northeast-1a","Subnet ID":"subnet-bbbbbbbb"}

通常はCausean instance was taken out of service in response to a EC2 health check indicating it has been terminated or stopped.となるのがan instance was taken out of service in response to a user health-check.となっているのでAutoScalingのEC2 Health Checkより前にアクションが起こされた事が分かります。

障害発生からInstanceがリプレースされてInServiceになるAuto Healingのトータル時間は6分ちょいになりました。 EC2 Auto Recoveryを使えば済む場合もありますが、あちらはAWS側の障害に起因するStatusCheckFailed_SystemのみでStatusCheckFailed_Instanceはトリガー対象じゃないのと、特定のインスタンスタイプやVPC等若干制限があります。

終わりに

ちなみに今回はinstanceやSNSは東京リージョン(ap-northeast-1)、Lambdaはオレゴンリージョン(us-west-2)というリージョンを跨いだ連携も可能という事が分かりました。まだ東京に来てないけど、既にproduction readyなのでもう普通に使っていけます。

いやー。SNS連携によって夢は広がりますねぇ。

サバフェス!2015に参加してきた

サバフェス!2015 Springに参加してきました。 やった内容を少々。

前回と同じくチーム@ijinとして1人で参戦して、順位は「4位」。

スコアは44988.867 TpmCでした。

お題

Mysql on ioDriveでtpcc-mysqlベンチマークのtransaction throughput競争。

第1陣と第2陣に分かれていて、今回は後者での参戦。

はじめに

競技期間は5日間あったものの、第1陣で結構な地雷があったのと、Fusion-IO(現SanDisk)のioDriveとtpcc-mysqlは2年前に触ったので最初はあんまりやる気が起きなくて困ってました。後は前回と違って施せる施策がかなり限定されるというので、正直5日間は長過ぎるのではないかという印象でした。(結果的に第1陣のトラブルとかを鑑みると長さ的には良かったのかも知れないけど)

という事で初日はログインとベンチで基準値を取るだけして終了。

その後、最近のMySQLやioDrive周りの情報収集を軽ーくして数日が経過。。

そして最終日の夜中になって、なんとか本腰を入れてチューニング開始。まあ、やりだしたら楽しいんですけどね。

マシンスペック

  • CentOS 6.4
  • Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz x 32
  • 32GB RAM
  • 40G HDD
  • 320GB ioDrive

制限

innodb_doublewrite = 1
innodb_flush_log_at_trx_commit = 1

その他レギューレーションはこちら

方針

今までのtwitterのタイムラインからして、どうもベンチをウェブ画面から要求しても並列実行の数とキューイング、及び非常に長い実行時間からして1時間に一回実行できるかどうかも怪しかったのでローカルでこまめに回す方向に。

本番データはtpccの1000 warehouse(70GB+)、16GB Buffer Pool、900sの実行時間だったのでそれを250 warehouse, 4GB Buffer Poolと縮小し120sと短めに設定。こうすることによってローカルでのデータコピー時間やベンチ実行時感が短縮され、時間がない中での細かいパラメータのチューニングに専念できる。Buffer Poolはどうせ一番効くと分かりきってるので、あえて後回し。DBは6年前(MySQL 5.0時代)から手に滲んで愛用しているPercona Serverの5.6版を選択。

スコアの推移はこんな感じ。データセットが小さい分、スコアは大きめ。

終盤になってやっと本番に近いデータセットや実行時感で細かいチューニング。

最終的にローカルでのベストスコアは53420.332 TpmCでした。

設定ファイル

効果があったもの

細かいおまじないレベルでのパラメータも他にいくつあったけど、割と効いたのをピックアップ。また、既に設定されていたパラメータは除外(innodb_io_capacity等)

mysql

datadir=/fioa/mysql
tmpdir=/fioa/tmp
sync_binlog=0
innodb_buffer_pool_size = 28150M
innodb_buffer_pool_instances=16
innodb_log_file_size=4G
innodb_log_files_in_group=3
innodb_log_group_home_dir=/var/log/mysql
innodb_log_buffer_size=64M
innodb_data_file_path=ibdata1:76M;../../var/log/mysql/ibdata2:500M:autoextend
innodb_checksum_algorithm=0
innodb_max_dirty_pages_pct=90
innodb_lru_scan_depth=2000
numa_interleave=1
flush_caches
malloc-lib=/usr/lib64/libjemalloc.so.1

etc

vm.swappiness=1
mount option (noatime,nodiratime,  max_batch_time=0,nobarrier,discard)
cache warmup

基本的にはioDriveにIOをなるべく発生させない、もしくは遅延させる関連のパラメータが効いた感じ。この辺は割と正統なチューニング方法。一つ、若干工夫したのは、doublewrite buffer fileの指定方法。シーケンシャルなIOが発生するログ周りの処理はHDDに逃がした方がioDrive/SSD的には負荷低減になるけど、Percona 5.5まではinnodb_doublewrite_fileというパラメータでいつも指定していたのが、5.6ではなんと未実装!なのでベンチマーク前にコピーされるibdata1の予めのサイズを計っておいて、以降の書き込みをHDD側へ逃がすようにinnodb_data_file_pathで調整。

他はNUMAによるメモリの偏り調整とmallocライブラリを使う指定。この辺もPerconaやMariaDB専用オプション。

後は一応初動のスコアをちょっとだけ稼ぐためにmysqlのstartup script内にてテーブルをcount(*)してindexをbuffer poolに乗せたぐらい。

効果が微妙だったもの

mysql

innodb_flush_method=ALL_O_DIRECT
innodb_support_xa=0
innodb_thread_concurrency=N
innodb_flush_neighbors=0
query_cache_size=0
large-pages

etc

echo 'noop' > /sys/block/fioa/queue/scheduler
echo 4096 > /sys/block/fioa/queue/nr_requests
echo 2 > /sys/block/fioa/queue/rq_affinity
renice -n19 -p `ps auxf | grep mackerel | grep -v grep | awk ‘{print $2}’`

large-pagesでページサイズを大きく設定すればメモリ効率は向上するはずが、少なくともベンチマークにおいては効果なし。また、スケジューラをnoopやdeadlineと変えたり、nr_requestsやrq_affinityを調整してみたけど、デフォルトのOS bypass設定と比べてあまり変化なし。

試したかったもの

  • ioDrvieのblock sizeのリサイズ
  • C0 state(CPUのC stateを制御して変動させずにioDriveの処理向上の期待)
  • numa_node_forced_local(IO処理をメモリに一番近接しているCPUで行う)
  • IRQ pinning(ioDriveのIRQを固定)
  • network tuning

この中で最後やることリストに乗っけていながらやらなかったネットワーク周りのチューニング。多分、これが敗因。(1位のチームzzz(@ttkzwさん)はローカルベンチマークで51000ぐらいだったので)もっとリモートからベンチが実行される事に意識を向ければ良かったのかもしれないですね。とはいえ、最後はキュー待ちが8チームだったり、結果が不具合で見れなかったりと、バダバタしてたのでそっちに気を取られたのもまた事実。まあ、半日ちょいのチューニングにしてはそこそこ行った感じでしょうか。

終わりに

最初は運営側が「目下実装中です!」といいながら#トラしゅをしているような感じでちょっと不安でしたが、最後は(第2陣という事もあり)それなりに楽しめました。ベンチマーク時間の短縮と並列実行数がもうちょっと増やせたらよかったですかね。運営側の皆様、大変お疲れさまでした!

おまけ

賞品として3DマッサージピローとSSDを頂きました!

個人敵には飛び込みLTした人がもらったDroneの方が良さそうだったけど、ピローは家族に好評でした。

ISUCON4の本戦の思い出

ISUCON4の本戦の直後にそのままAWS re:Inventへ行ったきりエントリを書いてなかったので思い出だけでも年内に書いておく。

内容のエントリはたくさんあるので、詳しい内容なそちらに任せます。

結果は予選よりちょい上の15位。まあ、中間層は結構団子状態だったので誤差の範囲とも言えますが。。

Cache-Control

結局はCache-Controlヘッダーに気づくかどうかという点にかかっていて、達成したのは2チームのみ。優勝チームのモリスさんが「頭から煙が出る程考えて」やっと直前に答えにたどり着いた事を考えると、ベンチマークツールの挙動が若干不思議な実装になっていたとはいえ、思慮深さが足りなかったと反省。

冒険しすぎた

今回はrubyとGoのハイブリッド構成でもろもろチューニング。が、しばらくして帯域が頭打ちに。。 また、その間にメンバーの一人の@fruweUndertowというjavaのフレームワークでチャレンジしてもらうものの(事前の技術検証では結構期待できそうだった)、実装完走にはいたらず。この辺は冒険し過ぎたかな。。振り返ってみれば、結局2位のチームがブレークスルーをしたのを見て、全作業を一旦ストップしてでも皆で考えなおす行動を取れば良かったのかもしれないですね。ただ、当時は予選でのベンチマークツールがいささか不安定だった事と運営側もリアルタイムでバグフィックスをしてたという事情もあり、きっとバグか何かだろうとあまり気にしてなかったのも確か。

最後に

とまあ、不完全燃焼だったけど、なんだかんだで面白かったです。運営&参加者の皆様お疲れ様でした。来年またあるか分からないけど、楽しみにしています。

Auto Scalingによる自動復旧(AWS Lambda編)

ちょうど1年程前に「非ELBなAutoscalingによる自動復旧」の再検証をしました。前回も復旧までのタイムラグが20分だったので、この1年で変わったかまた検証してみました。

(*) このエントリはAWS Advent Calendar 2014の5日目分です。

設定

前回とほぼ一種ですが、今回はついでにEC2 Status AlarmをCloudwatch経由でSNSでアラートを飛ばします。

SNS作成 & Subscribe(送られてくる確認メールは手動で承認)

1
2
3
4
5
6
7
8
9
$ aws sns create-topic --name instance-alert
{
    "TopicArn": "arn:aws:sns:us-west-2:123456789012:instance-alert"
}

$ aws sns subscribe --topic-arn arn:aws:sns:us-west-2:123456789012:instance-alert --protocol email --notification-endpoint user@example.com                               
{
    "SubscriptionArn": "pending confirmation"
}

EC2 Status Alarm登録

1
2
3
4
5
6
export INSTANCE=i-xxxxxxxx
aws cloudwatch put-metric-alarm --alarm-name StatusCheckFailed-Alarm-for-$INSTANCE \
--alarm-description "Instance $INSTANCE has failed" --metric-name StatusCheckFailed \
--namespace AWS/EC2 --statistic Maximum --dimensions Name=InstanceId,Value=$INSTANCE \
--period 60 --unit Count --evaluation-periods 2 --threshold 1 --comparison-operator \
  GreaterThanOrEqualToThreshold --alarm-actions arn:aws:sns:us-west-2:123456789012:instance-alert

自動復旧

通信を遮断し、Status Check Failを発動させる

1
2
ubuntu@ip-172-31-19-185:~$ date; sudo ifdown eth0
Fri Dec  5 13:02:39 UTC 2014

EC2のStatus Check。前回同様、3分ぐらいでfail検知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Fri Dec  5 22:05:22 JST 2014
ok
DETAILS reachability    passed

Fri Dec  5 22:05:28 JST 2014
ok
DETAILS reachability    passed

Fri Dec  5 22:05:34 JST 2014
impaired
DETAILS 2014-12-05T13:05:00.000Z        reachability    failed

Fri Dec  5 22:05:40 JST 2014
impaired
DETAILS 2014-12-05T13:05:00.000Z        reachability    failed

SNS通知。飛ぶまで2分弱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Alarm Details:
- Name:                       StatusCheckFailed-Alarm-for-i-xxxxxxxx
- Description:                Instance i-xxxxxxxx has failed
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 2 datapoints were greater than or equal to the threshold (1.0). The most recent datapoints: [1.0, 1.0].
- Timestamp:                  Friday 05 December, 2014 13:07:19 UTC


- AWS Account:                123456789012

Threshold:
- The alarm is in the ALARM state when the metric is GreaterThanOrEqualToThreshold 1.0 for 60 seconds.

Monitored Metric:
- MetricNamespace:            AWS/EC2
- MetricName:                 StatusCheckFailed
- Dimensions:                 [InstanceId = i-xxxxxxxx]
- Period:                     60 seconds
- Statistic:                  Maximum
- Unit:                       Count

AutoscalingのHealth Status

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Fri Dec  5 22:11:08 JST 2014
aws-advent2014-sg       us-west-2a      HEALTHY i-xxxxxxxx      aws-advent2014-lc       InService

Fri Dec  5 22:11:14 JST 2014
aws-advent2014-sg       us-west-2a      HEALTHY i-xxxxxxxx      aws-advent2014-lc       InService

Fri Dec  5 22:11:20 JST 2014
aws-advent2014-sg       us-west-2a      UNHEALTHY       i-xxxxxxxx      aws-advent2014-lc       InService

Fri Dec  5 22:11:26 JST 2014
aws-advent2014-sg       us-west-2a      UNHEALTHY       i-xxxxxxxx      aws-advent2014-lc       InService

Fri Dec  5 22:11:32 JST 2014
aws-advent2014-sg       us-west-2a      UNHEALTHY       i-xxxxxxxx      aws-advent2014-lc       Terminating

お、4分ぐらいでAuto ScalingがUnhealthyと認識。

何回か繰り返したところ、トータルで障害から復旧までの時間が10分を切りました!

なんと1年前と比べて時間が半分に短縮されてますねぇ。

Lambda

さて。改善されたものの、Auto ScalingがEC2 status checkの状態を検知するまでタイムラグがまだあるので、もうちょっと短縮したいですよね。できればSNSが発行されたタイミングで。

そこで、AWSの新サービス「Lambda」を使ってイベント通知できたら良いかも!!。。と思ったものの、残念ながらLambdaはまだSNSには対応してません。

なので、ひとまずSQSをSNSにsubscribeして、messageが届いたらLambda functionへ渡してinvokeへしてくれるsqs-to-lambdaを使ってAuto ScalingのHealthStatusを直接API経由でLambdaが叩く仕組みを試しました。 図にするとこんな感じですね。

ELB付けた方が楽な気もするけど、まあ集約できるのと検証も兼ねて。。

設定

SQSの作成

1
2
3
4
$ aws sqs create-queue --queue-name instance-failed
{
    "QueueUrl": "https://us-west-2.queue.amazonaws.com/123456789012/instance-failed"
}

SQSをSNSへsubscribe

1
2
3
4
$ aws sqs add-permission --queue-url https://us-west-2.queue.amazonaws.com/123456789012/instance-failed \
 --label SQSDefaultPolicy --aws-account-ids  --actions SendMessage
$ aws sqs set-queue-attributes --queue-url https://us-west-2.queue.amazonaws.com/123456789012/instance-failed  \
 --attributes '{"Policy": "{\"Version\":\"2008-10-17\",\"Id\":\"arn:aws:sqs:us-west-2:123456789012:instance-failed/SQSDefaultPolicy\",\"Statement\":[{\"Sid\":\"Sid1417796380309\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":\"SQS:SendMessage\",\"Resource\":\"arn:aws:sqs:us-west-2:123456789012:instance-failed\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"arn:aws:sns:us-west-2:123456789012:instance-alert\"}}}]}"}'

Lambda function

node.js製のsqs-to-lambda。long pollingしつつ、messageを取得後にLambda functionをinvokeしてくれる。12/5現在ではEscape characterがAWS/JDKやCLIから送信できないという大きな問題がある為、upstreamを少し改修

1
2
3
4
5
6
sudo apt-get install nodejs npm
sudo ln -s /usr/bin/nodejs /usr/local/bin/node
git@github.com:ijin/sqs-to-lambda.git
cd sqs-to-lambda
npm install
./index.js --queueUrl https://sqs.us-west-2.amazonaws.com/123456789012/instance-failed --functionName myFunction --region us-west-2  

Lambdaによる復旧

通信を遮断し、Status Check Failを発動させる

1
2
ubuntu@ip-172-31-21-180:~$ date; sudo ifdown eth0
Fri Dec  5 19:37:32 UTC 2014

EC2のStatus Check。約3分ぐらいでfail検知

1
2
3
4
5
6
7
8
9
10
11
Sat Dec  6 04:40:09 JST 2014
ok
DETAILS reachability    passed

Sat Dec  6 04:40:16 JST 2014
impaired
DETAILS 2014-12-05T19:40:00.000Z        reachability    failed

Sat Dec  6 04:40:22 JST 2014
impaired
DETAILS 2014-12-05T19:40:00.000Z        reachability    failed

SNS通知。飛ぶまで2分弱

1
2
3
4
5
6
7
Alarm Details:
- Name:                       StatusCheckFailed-Alarm-for-i-yyyyyyyy
- Description:                Instance i-yyyyyyyy has failed
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 2 datapoints were greater than or equal to the threshold (1.0). The most recent datapoints: [1.0, 1.0].
- Timestamp:                  Friday 05 December, 2014 19:42:33 UTC
- AWS Account:                123456789012 

そしてLambda発動!

1
2
3
4
5
6
7
START RequestId: e64849be-7cb6-12e4-9951-11b87edac46e
2014-12-05T19:42:36.728Z        e64849be-7cb6-12e4-9951-11b87edac46e    Received event:
2014-12-05T19:42:36.728Z        e64849be-7cb6-12e4-9951-11b87edac46e    { Type: 'Notification', MessageId: '2d85a5d8-c596-5f83-94a9-e924c97fd676', TopicArn: 'arn:aws:sns:us-west-2:123456789012:instance-alert', Subject: 'Status Check Alarm: !!StatusCheckFailed-Alarm-for-i-yyyyyyyy!! in US-West-2', Message: '{!!AlarmName!!:!!StatusCheckFailed-Alarm-for-i-yyyyyyyy!!,!!AlarmDescription!!:!!Instance i-yyyyyyyy has failed!!,!!AWSAccountId!!:!!123456789012!!,!!NewStateValue!!:!!ALARM!!,!!NewStateReason!!:!!Threshold Crossed: 2 datapoints were greater than or equal to the threshold (1.0). The most recent datapoints: [1.0, 1.0].!!,!!StateChangeTime!!:!!2014-12-05T19:42:33.757+0000!!,!!Region!!:!!US-West-2!!,!!OldStateValue!!:!!OK!!,!!Trigger!!:{!!MetricName!!:!!StatusCheckFailed!!,!!Namespace!!:!!AWS/EC2!!,!!Statistic!!:!!MAXIMUM!!,!!Unit!!:!!Count!!,!!Dimensions!!:[{!!name!!:!!InstanceId!!,!!value!!:!!i-yyyyyyyy!!}],!!Period!!:60,!!EvaluationPeriods!!:2,!!ComparisonOperator!!:!!GreaterThanOrEqualToThreshold!!,!!Threshold!!:1.0}}', Timestamp: '2014-12-05T19:42:33.841Z', SignatureVersion: '1', Signature: '1IYhSVfZmNxWWzoc539jBDN2HCo0Y5k/dUhWbaAEZSt/tkISjFkNTb9VsVwNAfZDOaLneO/sE2PwfUc/3aU9eedlAassxHOXAB6h844NVKxJzR5Xwg4dUx0mIb+fk9pMy/elcwk13GbDxLJ1cCTef7Bu7zyJU3TAF626YfAVhI9QdEo4o44g/y2osEXb+CuvFc5ICYpIWAad7gM5YPYxCU6tJ/CEtWGzaPz+O5Vk4NLm2/AizZ6LKA8/zqhQkqwnUwhzQDwuDGbJ2DXtTJwAO2r4M+zU8RwOxwPgEdgxA270xrmB6AlWV0mhsQIqqJVxo5Xm2v7y3iNUjKfov5DCZm==', SigningCertURL: 'https://sns.us-west-2.amazonaws.com/SimpleNotificationService-ad6697a11189d5c6f9eccf214ff9e123.pem', UnsubscribeURL: 'https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:123456789012:instance-alert:2d85a5d8-faea-5f83-baa1-9fecd7a5e71b' }
2014-12-05T19:42:36.728Z        e64849be-7cb6-12e4-9951-11b87edac46e    Changing instance health for: i-yyyyyyyy
014-12-05T19:42:36.831Z e64849be-7cb6-12e4-9951-11b87edac46e    { ResponseMetadata: { RequestId: 'dd605f39-7cb6-12e4-a2c2-d57010899d82' } }
END RequestId: e64849be-7cb6-12e4-9951-11b87edac46e
REPORT RequestId: e64849be-7cb6-12e4-9951-11b87edac46e  Duration: 175.86 ms     Billed Duration: 200 ms Memory Size: 128 MB     Max Memory Used: 18 MB

AutoscalingのHealth Status

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Sat Dec  6 04:42:18 JST 2014
aws-advent2014-sg       us-west-2a      HEALTHY i-yyyyyyyy      aws-advent2014-lc       InService

Sat Dec  6 04:42:24 JST 2014
aws-advent2014-sg       us-west-2a      HEALTHY i-yyyyyyyy      aws-advent2014-lc       InService

Sat Dec  6 04:42:30 JST 2014
aws-advent2014-sg       us-west-2a      UNHEALTHY       i-yyyyyyyy      aws-advent2014-lc       InService

Sat Dec  6 04:42:35 JST 2014
aws-advent2014-sg       us-west-2a      UNHEALTHY       i-yyyyyyyy      aws-advent2014-lc       InService

Sat Dec  6 04:42:42 JST 2014
aws-advent2014-sg       us-west-2a      UNHEALTHY       i-yyyyyyyy      aws-advent2014-lc       InService

jSat Dec  6 04:42:48 JST 2014
aws-advent2014-sg       us-west-2a      UNHEALTHY       i-yyyyyyyy      aws-advent2014-lc       Terminating

おお。さらに短く5分ぐらいに短縮!!

終わりに

Lambdaと組み合わせる事によってSNS通知によるELBを使わないレスポンシブなAuto Scalingの自動復旧が実現できました。

折角のサーバいらずのLambdaの良さが全く活かされてないけど。。早くSNSにも対応して欲しいものです。