電子の密林を開拓する

2013年02月

今回は、(CloudWatchではなくて) ふつーの Linux 的な方法で 負荷原因となっているプロセスを特定するための方法について調べます。




・前提
複数のプログラムが動作している状況で、いずれかのプログラムがHDDを高頻度に利用し、サーバ負荷を高めている。この負荷原因となっているプログラムとプロセスを特定したい。

ここでは、「負荷試験用にEC2ラージインスタンスを用意し、sysbench を使ってソコソコ以上の HDD 負荷を発生させる」という状況を作っておきます。
今回は負荷試験が目的なので、負荷試験中でも快適な(?)操作が出来るように性能の高いEC2インスタンスにしてみました。



・EC2インスタンス作成と準備

まずは EC2インスタンスを作成します。
HDDの負荷試験を行うので、EBSタイプでなく InstanceStore (ローカルの EphemeralDisk を使用する)タイプのインスタンスを作成します。
OSは Ubuntu Server 12.04 (64bit)  を選択します。
上記の条件で検索するとAMI-ID が「ami-9763e696」のものが合致していたので、コレを使用します。
$ ec2-run-instances  \
     ami-01008700 \
     --group web  \
     --key innerkey  \
     --instance-count 1  \
     --instance-type m1.large


RESERVATION     r-9f52c89c      488224276535    web
INSTANCE        i-7b370f78      ami-01008700                    pending innerkey        0             m1.large        2013-02-26T08:32:57+0000        ap-northeast-1a aki-44992845                  monitoring-disabled                                     instance-store                                paravirtual     xen             sg-33bace32     default false

$ ec2-describe-instances i-7b370f78
RESERVATION     r-9f52c89c      488224276535    web
INSTANCE        i-7b370f78      ami-01008700    ec2-54-248-22-153.ap-northeast-1.compute.amazonaws.com        ip-10-132-148-246.ap-northeast-1.compute.internal       running innerkey      0               m1.large        2013-02-26T08:32:57+0000        ap-northeast-1a aki-44992845                  monitoring-disabled     54.248.22.153   10.132.148.246                  instance-store                                        paravirtual     xen             sg-33bace32   default false
ec2-describe-instances で確認しても BLOCKDEVICE 行が無いので EBS はアタッチされていないようですね。

今回のインスタンスは bitnami (?)というところが作成したものらしく、ログイン時のアカウントも bitnami となっています。
$ ssh \
     -i ~/.ssh/innerkey.pem \
     -l bitnami \
     ip-10-132-148-246.ap-northeast-1.compute.internal

ssh でログインできたら、sysbench をインストールしておきます。
$ sudo apt-get update
$ sudo apt-get install sysbench
最後に 接続されているディスクの状態を確認しておきます。

$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/xvda1 9.9G 1.8G 7.6G 20% /
udev 3.7G 8.0K 3.7G 1% /dev
tmpfs 1.5G 168K 1.5G 1% /run
none 5.0M 0 5.0M 0% /run/lock
none 3.7G 0 3.7G 0% /run/shm
/dev/xvdb 414G 199M 393G 1% /mnt

$ mount
/dev/xvda1 on / type ext4 (rw)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
/dev/xvdb on /mnt type ext3 (rw,_netdev)
(負荷試験に)使えそうなディスクは / と /mnt にマウントされているようですが…。
まぁ、Ephemeral Disk (ローカルHDD)であれば、中身は気にしないので コレで良いということにしておきます。

前準備はこれで終わり。



・負荷試験の実施
HDDに対する負荷試験なので、まずはHDD側の準備。
$ cd /mnt
$ sudo mkdir loadtest
$ sudo chown bitnami:bitnami loadtest
$ cd loadtest/
$ ls -lah
total 8.0K
drwxr-xr-x 2 bitnami bitnami 4.0K Feb 26 09:07 .
drwxr-xr-x 4 root    root    4.0K Feb 26 09:07 ..
次に、負荷試験を実行します。特に言及しない限り、この以降の操作は この負荷試験が実行継続している状態であることを前提としておきます。
$ sysbench \
     --max-requests=9999999 \
     --max-time=900 \
     --num-threads=2 \
     --test=fileio \
     --file-test-mode=rndrw  \
     prepare

sysbench 0.4.12:  multi-threaded system evaluation benchmark

128 files, 16384Kb each, 2048Mb total
Creating files for the test...

$ sysbench \
     --max-requests=9999999 \
     --max-time=900 \
     --num-threads=2 \
     --test=fileio \
     --file-test-mode=rndrw  \
     run
sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 2

Extra file open flags: 0
128 files, 16Mb each
2Gb total file size
Block size 16Kb
Number of random requests for random IO: 9999999
Read/Write ratio for combined random IO test: 1.50
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing random r/w test
Threads started!
以下、(負荷試験状態を継続したまま)続きます。



・よくある調べ方
初心者のサーバ運用者(自分だ!)だと、まずは以下のようなコマンドで負荷の全体像をつかみます。
top
vmstat
iostat
     ※ iostat は標準ではインストールされていないようなので、
       sudo apt-get install sysstat でインストールしておいて下さい。
sysbench で 負荷試験実行中に 上記コマンドを試してみます。

まずは topコマンド。
$ top
Tasks:  82 total,   1 running,  81 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  1.0%sy,  0.0%ni, 43.8%id, 55.2%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   7629484k total,  2892128k used,  4737356k free,    40052k buffers
Swap:        0k total,        0k used,        0k free,  2426708k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 1993 bitnami   20   0 21764 1144  808 S    2  0.0   0:06.43 sysbench
  618 root      20   0     0    0    0 S    0  0.0   0:00.99 kjournald
 2612 bitnami   20   0 17336 1244  944 R    0  0.0   0:00.03 top
    1 root      20   0 24340 2268 1360 S    0  0.0   0:01.54 init
    2 root      20   0     0    0    0 S    0  0.0   0:00.00 kthreadd
    3 root      20   0     0    0    0 S    0  0.0   0:00.01 ksoftirqd/0
    4 root      20   0     0    0    0 S    0  0.0   0:00.00 kworker/0:0
    5 root      20   0     0    0    0 S    0  0.0   0:00.02 kworker/u:0
    ~
topコマンド 一発で 原因である sysbench を発見!!!
…と思ったら、単に CPU負荷/利用率からみて top に表示されているだけでした。
肝心の HDD への負荷によって順位が上がっているワケではないようです。
コレではちょっと使えないです(x_x;


次は vmstat 。
$ vmstat 4
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 0  2      0 4742504  35308 2426628    0    0    29   742   61   53  1  0 93  6
 0  1      0 4742336  35532 2426632    0    0     0  4728  375  214  0  1 51 48
 0  1      0 4742172  35740 2426632    0    0     1  4258  328  171  0  1 53 46
 0  2      0 4741940  35944 2426636    0    0     0  4246  328  182  0  1 53 46
IO負荷(というか IOwait ... waカラム)が高いことはスグに分かりますが…肝心の「どのブログラムが原因なのか」がサッパリ分かりません。

次は iostat を試してみます。
$ iostat
Linux 3.2.0-38-virtual (ip-10-132-148-246)      02/26/2013      _x86_64_        (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.38    0.00    0.49   14.26    0.38   84.49

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
xvdap1            4.32        30.20        80.20     128153     340388
xvdb            104.86         0.52      1981.51       2201    8409580
xvdc              0.12         0.36         0.00       1540          0
どの HDD を、どのぐらい読み書きしているのかはハッキリ分かりますが、これも原因を特定してはくれません…。
⇒ 「重いHDDドレなのか?」が分かるのは、ソレはそれで価値があるので iostat は、その点では便利でしょう!



・もっと調べる
インフラに詳しい人に教えてもらったところ、HDD/負荷を調査するのであれば 以下のようなコマンドが使えるらしいです。
lsof
iotop
dstat
ps (で stat が Dであるものを探す)
早速使ってみましょう。



・lsof コマンド
まずは lsof コマンド。どのプロセスがどのファイルを操作しているのか調べられるらしいですが…root 権限が必要らしいです。
$ sudo lsof 
COMMAND    PID       USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
init         1       root  cwd       DIR              202,1     4096          2 /
init         1       root  rtd       DIR              202,1     4096          2 /
init         1       root  txt       REG              202,1   167192      17027 /sbin/init
init         1       root  mem       REG              202,1    52120     395345 /lib/x86_64-linux-gnu/libnss_files-2.15.so
init         1       root  mem       REG              202,1    47680     395347 /lib/x86_64-linux-gnu/libnss_nis-2.15.so
~略~
全プロセスが対象になるらしく、リストが長すぎて探すのが困難です。grep してみましょう…。
$ sudo lsof \
| egrep -e '/mnt/loadtest/' -e '^COMMAND'
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sysbench 2687 bitnami 3u REG 202,16 16777216 4931586 /mnt/loadtest/test_file.0
sysbench 2687 bitnami 4u REG 202,16 16777216 4931587 /mnt/loadtest/test_file.1
sysbench 2687 bitnami 5u REG 202,16 16777216 4931588 /mnt/loadtest/test_file.2
sysbench 2687 bitnami 6u REG 202,16 16777216 4931589 /mnt/loadtest/test_file.3
sysbench 2687 bitnami 7u REG 202,16 16777216 4931590 /mnt/loadtest/test_file.4
sysbench 2687 bitnami 8u REG 202,16 16777216 4931591 /mnt/loadtest/test_file.5
sysbench 2687 bitnami 9u REG 202,16 16777216 4931592 /mnt/loadtest/test_file.6
sysbench 2687 bitnami 10u REG 202,16 16777216 4931593 /mnt/loadtest/test_file.7
sysbench 2687 bitnami 11u REG 202,16 16777216 4931594 /mnt/loadtest/test_file.8
sysbench 2687 bitnami 12u REG 202,16 16777216 4931595 /mnt/loadtest/test_file.9
~略~
大量に発見できますが…。今回は 操作対象のファイルが分かっているので lsof で特定できますが、そうできない状況の方が多いような気もします…。
結局 lsof も便利ではありますが、今回欲しかったコマンドではなさそうです。
⇒ もし対象ファイル/ディレクトリが判明しているのであれば、使えるコマンドですね。



・iotopコマンド

次は iotop コマンド。Ubuntu には標準インストールされていないようなので sudo apt-get install iotop  としてインストールしておきます。
インストールできたら使ってみましょう。root 権限が必要なので、sudo 経由で使用します。
$ sudo iotop
Total DISK READ: 0.00 B/s | Total DISK WRITE: 5.83 M/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
618 be/4 root 0.00 B/s 0.00 B/s 0.00 % 94.75 % [kjournald]
2722 be/4 bitnami 0.00 B/s 2.73 M/s 0.00 % 34.81 % sysbench --max-requests 9999999 --~ fileio --file-test-mode rndrw run
2721 be/4 bitnami 0.00 B/s 2.80 M/s 0.00 % 18.32 % sysbench --max-requests 9999999 --~ fileio --file-test-mode rndrw run
1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init
2 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kthreadd]
3 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [ksoftirqd/0]
4 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/0:0]
5 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/u:0]

ズバリ判明!
恐ろしい!!!
もう、他のコマンド要らないかも…(^^;



・dstatコマンド
dstat コマンドはUbuntu標準ではインストールされていないので sudo apt-get install dstat としてインストールしておきます。
インストールできたら、dstat を実行してみます。

dstat

何も考えずにdstatを実行したら、ものすごくカラフルな結果になりました。
色を抑制したい場合は --nocolor オプションが使えるようです。

man dstat として中を読んでみると、--top-* 系オプションで一番コストがかかっているモノをいろいろ検索できるようです。
今回は IO 処理 なので、--top-io で調べてみます。
$ dstat --nocolor --time --top-io
----system---- ----most-expensive----
time | i/o process
26-02 10:57:14| 3173k 2363k
26-02 10:57:15|sysbench 7680k 5120k
26-02 10:57:16|sysbench 6720k 4480k
26-02 10:57:17|sysbench 3840k 2560k
26-02 10:57:18|sysbench 10M 7040k
26-02 10:57:19|sysbench 7680k 5120k
26-02 10:57:20|sysbench 8640k 5760k
26-02 10:57:21|sysbench 8656k 5760k
26-02 10:57:22|sysbench 4800k 3200k
26-02 10:57:23|sysbench 8624k 5776k
26-02 10:57:24|sysbench 7696k 5104k
こちらも、そのままズバリ sysbench が発見されていますね。「一番重いプロセス」を見つけるには最適なコマンドかもしれません。
他のオプションも付与してみると、もっと楽しく(?)なります。
$ dstat --nocolor --time --top-io --disk
----system---- ----most-expensive---- -dsk/total-
time | i/o process | read writ
26-02 11:00:57| 3902k 2842k| 15k 3041k
26-02 11:00:58|sysbench 8640k 5776k| 0 5676k
26-02 11:00:59|sysbench 6720k 4480k| 0 5228k
26-02 11:01:00|sysbench 8640k 5760k| 0 5840k
26-02 11:01:01|sysbench 6736k 4464k| 0 5056k
26-02 11:01:02|sysbench 6720k 4480k| 0 4760k
26-02 11:01:03|sysbench 7664k 5136k| 0 5412k
26-02 11:01:04|sysbench 8640k 5760k| 0 6128k
26-02 11:01:05|sysbench 8640k 5760k| 0 5964k
ディスクIOの数値も表示されるようになりました。
dstat も、かなり使えるコマンドですね。



・ps で stat = D のものを探す
ps コマンドの表示結果から、STAT 列が D であるものダケを探せば、HDDに負荷をかけているプロセスの正体が判明するそうです。stat の意味を man ps で調べると…
PROCESS STATE CODES
       Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display to
       describe the state of a process:
       D    uninterruptible sleep (usually IO)
       R    running or runnable (on run queue)
       S    interruptible sleep (waiting for an event to complete)
       T    stopped, either by a job control signal or because it is being traced.
       W    paging (not valid since the 2.6.xx kernel)
       X    dead (should never be seen)
       Z    defunct ("zombie") process, terminated but not reaped by its parent.
       .....
…ということなので、まぁ、そんなもんなのでしょう。

まずは ps auxwww として、プロセス一覧を表示してみます。
$ ps auxwww | head
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 24340 2268 ? Ss 08:35 0:01 /sbin/init
root 2 0.0 0.0 0 0 ? S 08:35 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 08:35 0:00 [ksoftirqd/0]
root 4 0.0 0.0 0 0 ? S 08:35 0:00 [kworker/0:0]
root 5 0.0 0.0 0 0 ? S 08:35 0:00 [kworker/u:0]
root 6 0.0 0.0 0 0 ? S 08:35 0:00 [migration/0]
root 7 0.0 0.0 0 0 ? S 08:35 0:00 [watchdog/0]
STAT が D であるものだけを見つけるのは、目視でも grep でも困難に思えます。

ps の --format オプションを使用して出力の順序を変更し、先頭に stat が来るようにします。その上で、grep ^D で絞り込んでみます。
$ ps ax --format 'stat %cpu %mem user cmd' \
     | grep '^D'

D     0.1  0.0 root     [kjournald]
期待とは違う結果になりましたね…。

sysbenchの状態がどのようになっているのか……sysbenchダケを探してみます。
$ ps ax --format 'stat %cpu %mem user cmd' \
     | grep 'sysbench'

Sl+   2.3  0.0 bitnami  sysbench --max-requests 9999999 --max-time 900 --num-threads 2 --test fileio --file-test-mode rndrw run
S+    0.0  0.0 bitnami  grep --color=auto sysbench
sysbench の stat は D ではなく Sl+ となっていますね…。+ は「foregroud process」という意味らしいので、Slに意味があるんだけれど…「長時間のevent待ち」 って...。
⇒ 他の環境で、HDDのアクセス負荷が問題になっていた時には この stat=D を探す方法で発見できたのですが…。

原因は何なのか? あるいは調べ方が悪いのか...?
  1. HDDが遅くて待たされているわけではないため、stat=Dとはならない。
  2. sysbenchの使用しているAPIは stat=D ではなく、stat=Sl を発生させる。
  3. AWSのEphemeralDiskは(ドライバか何かの都合で) stat=D とはならない。 
妄想だけはいくらでもできますが、真実は不明…。今度 調べるときに sysbench 以外を使ってみようかな…。
⇒ sysbench のスレッド数を2倍にしても stat=D は発生しなかったので、(1)は違う気がしています。


・まとめ
HDD負荷が疑われる場合、以下のように問題を絞り込めるでしょう。
  1. top、vmstat、iostat などで 負荷の傾向と量を把握する
  2. iotop、dstat --top-io コマンドで、負荷原因となったプロセスを特定する
  3. ファイル/ディレクトリが特定できているなら lsof で問題プロセスを特定する
  4. root が取れないのであれば、ps コマンド等でガンバる


・後始末
作成したラージインスタンスは、時間当たりの利用料が高いので、作業が終わったらサッサと STOP、TERMINATE しておきましょう。

インスタンスを消去しないのであれば、sysbench を停止した後、以下のコマンドで sysbench ファイルの後始末をしておいてください。
$ sysbench \
     --max-requests=9999999 \
     --max-time=900 \
     --num-threads=2 \
     --test=fileio \
     --file-test-mode=rndrw  \
     cleanup


sysbench 0.4.12:  multi-threaded system evaluation benchmark
Removing test files..



今回はここまで。

今回は CloudWatch の Alarm を CLI 経由で設定します。


・負荷をかける対象のEC2インスタンスを作成する
GUIでCloudWatchのAlarmを設定した記事でやったように、sysbench というコマンドで負荷をかけてみます。
AmazonLinux では sysbench が yum でインストールできるパッケージに含まれていないので、負荷対象として 新規に Ubuntu を OS とする EC2を起動します。
$ ec2-run-instances  \
     ami-20ad1221 \
     --group web  \
     --key innerkey  \
     --instance-count 1  \
     --instance-type t1.micro  \
     --instance-initiated-shutdown-behavior stop

RESERVATION     r-15841f16      488224276535    web
INSTANCE        i-55b38d56      ami-20ad1221                    pending innerkey        0             t1.micro        2013-02-25T07:43:21+0000        ap-northeast-1a aki-ec5df7ed                  monitoring-disabled                                     ebs                                   paravirtual     xen             sg-33bace32     default false
セキュリティグループや鍵ペアについては適切なものを指定ください。

次に、作成した 負荷対象となるEC2インスタンスにsshログインして、負荷試験ツール(sysbench)をインストールします。まずは ssh ログイン。
$ ec2-describe-instances i-55b38d56 \
     | grep '^INSTANCE'  \
     | cut --fields=5

ip-10-132-166-244.ap-northeast-1.compute.internal

$ ssh \
     -i ~/.ssh/innerkey.pem \
     -l ubuntu \
     ip-10-132-166-244.ap-northeast-1.compute.internal

続いて、EC2インスタンス上での設定。
まずは前準備の呪文として、以下の二つを実行しておきます(後者は、まぁ、無くてもOKかも)。
$ sudo apt-get update
$ sudo apt-get upgrade
次は、sysbench をインストールします。
$ sudo apt-cache search sysbench
sysbench - Cross-platform and multi-threaded benchmark tool

$ sudo apt-get install sysbench

Ubuntu 側の設定はコレで終わりなので、一旦ログアウトしておきます。
$ exit



・S
NSの設定

Alarmを利用するには通知先となるSNSが必要になります。
そのため、先に server-alarm という名前のSNSトピックを作成し、メールアドレスを登録しておきます。
手順は以前の記事を参考にしてください。
$ sns-create-topic server-alarm
arn:aws:sns:ap-northeast-1:488224276535:server-alarm

$ sns-subscribe \
     arn:aws:sns:ap-northeast-1:488224276535:server-alarm \
     --protocol email  \
     --endpoint  exploreaws@example.com

Subscription request received.

※ここでメール受信

$ sns-confirm-subscription \
     arn:aws:sns:ap-northeast-1:488224276535:server-alarm \
     --token ~メールで送られてきたTOEKN識別子~

arn:aws:sns:ap-northeast-1:488224276535:server-alarm:59bb374a-186b-40e9-8d6c-09d43d716058
念のため、sns-publish コマンドで通知が届くことを確認しておいてください。
⇒ Alarm設定後に通知が届かない場合、SNS側の設定ミスなのか、Alarm側の設定ミスなのか判断できなくなるので。
$ sns-publish \
     arn:aws:sns:ap-northeast-1:488224276535:server-alarm \
     --message 'This is sample publishing.'

13dc2c0b-069c-5820-8e6e-65965c13ae80



・Alarmの設定
(AmazonLinuxの場合) /opt/aws/bin/ にインストールされている alarm に関連しそうな mon-* 系コマンドは以下の通り。
$ ls -1 /opt/aws/bin/mon* \
     | grep -i alarm

/opt/aws/bin/mon-delete-alarms
/opt/aws/bin/mon-describe-alarm-history
/opt/aws/bin/mon-describe-alarms
/opt/aws/bin/mon-describe-alarms-for-metric
/opt/aws/bin/mon-disable-alarm-actions
/opt/aws/bin/mon-enable-alarm-actions
/opt/aws/bin/mon-put-metric-alarm
/opt/aws/bin/mon-set-alarm-state
Alarmの作成と削除は、それぞれ mon-put-metric-alarm と mon-delete-alarms が対応するようです。

まずはAlarmの作成から。

mon-put-metric-alarm で、良く使いそうなパラメータを並べてみます。
mon-put-metric-alarm

  ALARM_NAME
  --alarm-description 'COMMENT'
  --alarm-actions SNS_TOPIC_NAME,...

  --namespace  CLOUDWATCH_NAMESPACE
  --metric-name  CLOUDWATCH_METRIC
  --statistic  CLOUDWATCH_STATISTIC
  --dimensions CLOUDWATCH_DIMENSION
  --period  CLOUDWATCH_PERIOD_IN_SECOND
  --unit CLOUDWATCH_UNIT

  --threshold  VALUE_TO_COMPARE
  --evaluation-periods  NUMBER_OF_PERIODS
  --comparison-operator  (
         GreaterThanOrEqualToThreshold
       | GreaterThanThreshold,
       | LessThanThreshold
       | LessThanOrEqualToThreshold
       )
ものすごく大量にあってゲンナリしますが…。2つにグループ分けすると、以下のような感じになります。
  • 上段 - Alarmに関する名前、通知先SNSトピックの指定
  • 中段 - 監視対象となる CloudWatch の指定
  • 下段 - 条件と閾値(この値になったらAlarm作動するぜ…というモノ)

Alarm に関する名前は、EC2インスタンス自身の CPU負荷に対するAlarmを作成するので、それらしいモノにしておきます。


  cpu-overload
  --alarm-description 'CPU utlization overload'
  --alarm-actions server-alarm


CloudWatch の設定は、前回の記事で試したので特に困ることは無いですね…。以下のような感じになります。


  --namespace  AWS/EC2
  --metric-name  CPUUtilization
  --statistic  Average
  --period  300

  --unit Percent


EC2インスタンス、300秒(5分)間、CPU使用率…の平均値を監視対象とします。

どのEC2インスタンスで負荷が発生してもAlarmを出したいので、dimensions は指定しません。

period を指定させる意味が良く分かりませんが、とりあえず(CloudWatchデフォルトの)300としておきます。


最後の条件と閾値は…


  --threshold  50
  --evaluation-periods  2
  --comparison-operator  GreaterThanOrEqualToThreshold


…という設定で、「監視対象の値が 50%以上の2回以上続いたら」という条件設定にします。

ではコマンドを実行してみましょう。
$ mon-put-metric-alarm  \
     cpu-overload  \
     --alarm-description 'CPU utlization overload'  \
     --alarm-actions arn:aws:sns:ap-northeast-1:488224276535:server-alarm  \
     --namespace  AWS/EC2  \
     --metric-name  CPUUtilization  \
     --statistic  Average  \
     --period  300  \
     --unit Percent  \
     --threshold  50  \
     --evaluation-periods  2  \
     --comparison-operator  GreaterThanOrEqualToThreshold
OK-Created Alarm
先ほどのコマンド一覧にあった mon-describe-alarms で結果を確認してみます。
$ mon-describe-alarms
cpu-overload  INSUFFICIENT_DATA  arn:aws:sns:ap-nor...276535:server-alarm  AWS/EC2  CPUUtilization  300  Average  2  GreaterThanOrEqualToThreshold  50.0
それらしいものが設定されているように見えますね…。
しかし、状態(?)が INSUFFICIENT_DATA になっています。これって異常???
https://forums.aws.amazon.com/message.jspa?messageID=253009

Ensure any dimensions you specify are applicable to the metric (e.g. CPUUtilization for EC2 instances is measured against the InstanceId and AutoscalingGroup dimensions for the AWS/EC2 namespace, whereas CPUUtilization for RDS is measured against the dimensions DatabaseClass, DBInstanceIdentifier and EngineName for the AWS/RDS namespace).
上記の公式フォーラムの回答によると、CPUUtilization は Instance-ID か AutoScalingGroup を dimension として必要とするみたいですね…。どのインスタンスのCPU 負荷でも良いからアラーム対象とする…という設定にはできないみたいです…(x_x;

Alarm を再設定します。再設定(update)も 同じ mon-put-metric-alarm コマンドを使用するようです。
$ mon-put-metric-alarm  \
     cpu-overload  \
     --alarm-description 'CPU utlization overload'  \
     --alarm-actions arn:aws:sns:ap-northeast-1:488224276535:server-alarm  \
     --namespace  AWS/EC2  \
     --metric-name  CPUUtilization  \
     --dimensions 'InstanceId=i-55b38d56' \
     --statistic  Average  \
     --period  300  \
     --unit Percent  \
     --threshold  50  \
     --evaluation-periods  2  \
     --comparison-operator  GreaterThanOrEqualToThreshold

OK-Created Alarm

$ mon-describe-alarms
cpu-overload  OK  arn:aws:sns:ap-nor...276535:server-alarm  AWS/EC2  CPUUtilization  300  Average  2  GreaterThanOrEqualToThreshold  50.0
今度はバッチリ設定されているようですね。




・負荷試験の実行

負荷試験は、Ubuntu側で直接実行します。sshでログインして、そこから作業しましょう。
先に設定した mon-put-metric-alarm では「5分単位の計測で2回の高負荷」時に警告が飛ぶようにしたので、比較的な長い時間負荷試験を実行する必要があります。
ここでは、900秒(15分)実行しておくことにします。

$ ssh \
     -i ~/.ssh/innerkey.pem \
     -l ubuntu \
     ip-10-132-166-244.ap-northeast-1.compute.internal



$ sysbench \
     --max-requests=9999999 \
     --max-time=900 \
     --test=cpu run


sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Doing CPU performance benchmark

Threads started!

Time limit exceeded, exiting...
Done.

Maximum prime number checked in CPU test: 10000


Test execution summary:
    total time:                          900.0490s
    total number of events:              203125
    total time taken by event execution: 899.3371
    per-request statistics:
         min:                                  1.78ms
         avg:                                  4.43ms
         max:                                229.57ms
         approx.  95 percentile:               2.11ms

Threads fairness:
    events (avg/stddev):           203125.0000/0.00
    execution time (avg/stddev):   899.3371/0.00



負荷試験対象である Ubuntu にはEC2コマンドをインストールしていないので、AmazonLinuxなインスタンスから CPUUtlization (CPU負荷)を確認してみます。
$ mon-get-stats  \
     CPUUtilization \
     --namespace AWS/EC2 \
     --statistics Maximum \
     --dimensions 'InstanceId=i-55b38d56'
2013-02-25 09:40:00  1.67   Percent
2013-02-25 09:45:00  1.67   Percent
2013-02-25 09:50:00  1.69   Percent
2013-02-25 09:55:00  1.64   Percent
2013-02-25 10:00:00  1.67   Percent
2013-02-25 10:05:00  1.75   Percent
2013-02-25 10:10:00  100.0  Percent
2013-02-25 10:15:00  100.0  Percent
2013-02-25 10:20:00  100.0  Percent
2013-02-25 10:25:00  100.0  Percent
2013-02-25 10:30:00  100.0  Percent

$ mon-describe-alarms
cpu-overload  OK  arn:aws:sns:ap-nor...276535:server-alarm  AWS/EC2  CPUUtilization  300  Average  2  GreaterThanOrEqualToThreshold  50.0

$ mon-describe-alarm-history cpuoverload
cpu-overload  2013-02-25T10:35:36.223Z  StateUpdate          Alarm updated from ALARM to OK
cpu-overload  2013-02-25T10:25:36.253Z  Action               Successfully executed action arn:aws:sns:ap-northeast-1:488224276535:server-alarm
cpu-overload  2013-02-25T10:25:36.230Z  StateUpdate          Alarm updated from OK to ALARM
cpu-overload  2013-02-25T09:46:47.720Z  StateUpdate          Alarm updated from INSUFFICIENT_DATA to OK
cpu-overload  2013-02-25T09:46:47.136Z  ConfigurationUpdate  Alarm "cpu-overload" updated
cpu-overload  2013-02-25T09:33:04.279Z  ConfigurationUpdate  Alarm "cpu-overload" created

Alarmに設定されたアクションが実行されたことになっています。

exploreaws@example.com にも、「ALARM: "cpu-overload" in APAC - Tokyo」という件名のメールが届いていました。

You are receiving this email because your Amazon CloudWatch Alarm "cpu-overload" in the APAC - Tokyo region has entered the ALARM state, because "Threshold Crossed: 2 datapoints were greater than or equal to the threshold (50.0). The most recent datapoints: [100.0, 100.0]." at "Monday 25 February, 2013 10:25:36 UTC".

View this alarm in the AWS Management Console:
https://console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#s=Alarms&alarm=cpu-overload

Alarm Details:
- Name:                       cpu-overload
- Description:                CPU utlization overload
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 2 datapoints were greater than or equal to the threshold (50.0). The most recent datapoints: [100.0, 100.0].
- Timestamp:                  Monday 25 February, 2013 10:25:36 UTC
- AWS Account:                488224276535

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

Monitored Metric:
- MetricNamespace:            AWS/EC2
- MetricName:                 CPUUtilization
- Dimensions:                 [InstanceId = i-55b38d56]
- Period:                     300 seconds
- Statistic:                  Average
- Unit:                       Percent

State Change Actions:
- OK: 
- ALARM: [arn:aws:sns:ap-northeast-1:488224276535:server-alarm]
- INSUFFICIENT_DATA: 

これでAlarmの設定が正しく機能していることが確認できました。

ちなみに、今回は「ALARMになった時」のActionだけ設定しましたが、実運用では「OKになった時」も設定しておくのが良いでしょう。負荷状態から自動的に復帰した場合、それも知りたいでしょうから…。

しかしAlarmの文面が変更できないのは、微妙に使いにくいですね…。



・後始末
mon-delete-alarm でAlarm設定を削除します。
$ mon-delete-alarms cpu-overload
    Are you sure you want to delete these Alarms? [Ny]y
OK-Deleted alarms
プロンプトがメンドくさければ、--force オプションで抑制できます。

Alarm の通知先であった、SNS も削除します。
$ sns-list-topics
arn:aws:sns:ap-northeast-1:488224276535:server-alarm

$ sns-delete-topic \
     arn:aws:sns:ap-northeast-1:488224276535:server-alarm
    Are you sure you want to delete this topic? [Ny]y
Topic deleted.
要らなくなった EC2 インスタンス (Ubuntu)も削除しておいてください。
$ ec2-stop-instances i-55b38d56
INSTANCE        i-55b38d56      running stopping

$ ec2-terminate-instances i-55b38d56
INSTANCE        i-55b38d56      stopped terminated

これで後始末も終了。




今回はここまで。


今回は CloudWatch というか、mon-*系の監視コマンドを使ってみます。



・タグからEC2インスタンスを探す
MasterController という名前の AmazonLinux な EC2 で CloudWatch を試してみます。
MasterController というNameタグを持つインスタンスを探して、そのInstance-ID を入手します。
$ ec2-describe-instances \
     | grep -e '^TAG' \
     | grep 'MasterController' \
     | cut --fields=3
i-0f1b440c
あるいは --filter オプションを使用して以下のようにもできます。
$ ec2-describe-instances \
     --filter 'tag:Name=MasterController' \
   | grep '^INSTANCE' \
   | cut --fields=2
i-0f1b440c
書く手間は、あまり変わりませんね…。
いずれにせよ、コマンドじゃなくてAPIで探した方が良いような気がするけど…。とりあえず、今はコレでガマンしておきます。



・EC2インスタンス用のメトリックス
次に、mon-list-metrics を使って、先に入手した Instance-ID に紐づく Metrics のリストを
入手します。
⇒ mon-list-metrics コマンドだけを使っても一覧を入手できますが、既に削除済みのインスタンスに対するmetricsも表示されたりしてメンドクサイので、Instence-ID で検索したいのです。
$ mon-list-metrics \
     | egrep 'i-0f1b440c' \
     | grep -v '^"'
CPUUtilization                 AWS/EC2  {InstanceId=i-0f1b440c}
DiskReadBytes                  AWS/EC2  {InstanceId=i-0f1b440c}
DiskReadOps                    AWS/EC2  {InstanceId=i-0f1b440c}
DiskWriteBytes                 AWS/EC2  {InstanceId=i-0f1b440c}
DiskWriteOps                   AWS/EC2  {InstanceId=i-0f1b440c}
NetworkIn                      AWS/EC2  {InstanceId=i-0f1b440c}
NetworkOut                     AWS/EC2  {InstanceId=i-0f1b440c}
StatusCheckFailed              AWS/EC2  {InstanceId=i-0f1b440c}
StatusCheckFailed_Instance AWS/EC2  {InstanceId=i-0f1b440c}
StatusCheckFailed_System       AWS/EC2  {InstanceId=i-0f1b440c}

MasterController というタグが付けられたEC2インスタンスには、これだけのMetricsがあるらしいです。

しかし、もっとカンタンな方法を発見。

$ mon-list-metrics \
--dimensions "InstanceId=i-0f1b440c" \
     | egrep -v '^"'

CPUUtilization                 AWS/EC2  {InstanceId=i-0f1b440c}
DiskReadBytes                  AWS/EC2  {InstanceId=i-0f1b440c}
DiskReadOps                    AWS/EC2  {InstanceId=i-0f1b440c}
DiskWriteBytes                 AWS/EC2  {InstanceId=i-0f1b440c}
DiskWriteOps                   AWS/EC2  {InstanceId=i-0f1b440c}
NetworkIn                      AWS/EC2  {InstanceId=i-0f1b440c}
NetworkOut                     AWS/EC2  {InstanceId=i-0f1b440c}
StatusCheckFailed              AWS/EC2  {InstanceId=i-0f1b440c}
StatusCheckFailed_Instance AWS/EC2  {InstanceId=i-0f1b440c}
StatusCheckFailed_System AWS/EC2  {InstanceId=i-0f1b440c}
--dimensions オプションを使えば、簡単に Instance-ID で絞り込みできました!

で、肝心の Metrics そのものですが……。
MasterController は AmazonLinux なマイクロインスタンスなので、ローカルディスクは使用していないです(マイクロインスタンスではEBSが使用される)。つまり、Disk* 系の Metrics には あまり意味が無いというコトですね。


・EC2インスタンスの監視結果を得る
Metrics の一覧が手に入ったので、次は mon-get-stats コマンドで CloudWatch から監視結果の値を入手します。指定するパラメータは以下のようにします。
Metric     = CPUUtilization 
Statistics = Average
NameSpace = AWS/EC2
mon-get-stats --help で確認すると、Statistics には「Average, Sum, SampleCount, Maximum, Minimum」のいずれかが指定できるようです。
$ mon-get-stats \
     CPUUtilization \
     --statistics Average \
     --namespace AWS/EC2
あれ??? パラメータは足りているはずなのに、何も表示されませんね???
(このコマンド指定で何かが表示される場合もありますが、今回は表示されませんでした…。結果が表示されたり、されなかったりする理由は不明。)

気を取り直して、先ほど mon-list-metrics で指定した dimensions を設定してみます。
$ mon-get-stats \
     CPUUtilization \
     --statistics Average \
     --namespace AWS/EC2 \
     --dimensions "InstanceId=i-0f1b440c"

2013-02-17 17:13:00  23.830000000000002   Percent
2013-02-17 17:18:00  0.33399999999999996  Percent
2013-02-17 17:23:00  26.666000000000004   Percent
2013-02-17 17:28:00  0.0                  Percent
2013-02-17 17:33:00  0.0                  Percent
2013-02-17 17:38:00  1.6440000000000001   Percent
2013-02-17 17:43:00  47.18                Percent
2013-02-17 17:48:00  9.622                Percent
2013-02-17 17:53:00  18.887999999999998   Percent
2013-02-17 17:58:00  35.922000000000004   Percent
2013-02-17 18:03:00  12.334               Percent
--dimensions オプションに Instance-ID を指定したら 結果が表示されるようになりましたね。Dimensions は必須オプションではないのに……指定が必要な理由が分からないです。

他の値、ヘルスチェックの結果も見てみましょう。
$ mon-get-stats \
     StatusCheckFailed \
     --statistics Sum \
     --namespace AWS/EC2 \
     --dimensions "InstanceId=i-0f1b440c"

2013-02-17 18:25:00  0.0  Count
2013-02-17 18:30:00  0.0  Count
2013-02-17 18:35:00  0.0  Count
2013-02-17 18:40:00  0.0  Count
2013-02-17 18:45:00  0.0  Count
2013-02-17 18:50:00  0.0  Count
2013-02-17 18:55:00  0.0  Count
2013-02-17 19:00:00  0.0  Count
2013-02-17 19:05:00  0.0  Count
2013-02-17 19:10:00  0.0  Count
2013-02-17 19:15:00  0.0  Count
2013-02-17 19:20:00  0.0  Count
特にヘルスチェックに失敗するような処理もさせていないので、カウントはゼロになっていますね。



・EBSの Volume-ID を得る
MasterController(i-0f1b440c)にアタッチされた EBS の状態を確認してみましょう。
ec2-describe-volumes に --filter オプションを使って、EBS のボリュームIDを探してみます。
$ ec2-describe-volumes \
     --filter 'attachment.instance-id=i-0f1b440c' \
   | grep '^VOLUME' \
   | cut --fields=2


vol-6057ec42



・EBSに対するメトリックスを得る
では、EBS Volume(vol-6057ec42) に対する Metrics のリストを確認します。
$ mon-list-metrics \
     --namespace AWS/EBS \
     --dimensions='VolumeId=vol-6057ec42' \
   | grep -v '^"'
VolumeIdleTime           AWS/EBS  {VolumeId=vol-6057ec42}
VolumeQueueLength        AWS/EBS  {VolumeId=vol-6057ec42}
VolumeReadBytes          AWS/EBS  {VolumeId=vol-6057ec42}
VolumeReadOps            AWS/EBS  {VolumeId=vol-6057ec42}
VolumeTotalReadTime      AWS/EBS  {VolumeId=vol-6057ec42}
VolumeTotalWriteTime AWS/EBS  {VolumeId=vol-6057ec42}
VolumeWriteBytes         AWS/EBS  {VolumeId=vol-6057ec42}
VolumeWriteOps AWS/EBS  {VolumeId=vol-6057ec42}
AWS Management Console でも見たことがあるような監視項目が表示されています。




・EBSの監視結果を得る
まずは、VolumeQueueLength を見てみます。
$ mon-get-stats \
     VolumeQueueLength \
     --statistics Maximum \
     --namespace AWS/EBS \
     --dimensions "VolumeId=vol-6057ec42"
2013-02-17 19:01:00  3.06666666666667E-4  Count
2013-02-17 19:06:00  9.73333333333333E-4  Count
2013-02-17 19:11:00  2.4E-4               Count
2013-02-17 19:16:00  4.13333333333333E-4  Count
2013-02-17 19:21:00  2.13333333333333E-4  Count
2013-02-17 19:26:00  5.2E-4               Count
2013-02-17 19:31:00  2.66666666666667E-4  Count
2013-02-17 19:36:00  1.46666666666667E-4  Count
2013-02-17 19:41:00  1.46666666666667E-4  Count
2013-02-17 19:46:00  0.0                  Count
2013-02-17 19:51:00  0.0                  Count
2013-02-17 19:56:00  0.00133333333333333  Count
浮動小数点が E 表記になっているので、ものすごく見づらいです…。これをふつうの表記に変更する方法が分からない…。

VolumeQueueLength の意味は「The average number of read and write operations waiting to be completed during the period」(単位時間内に、READ/WRITE処理が待たされた回数の平均)ということらしいです。平均ってオカシイような気がするのですが…(単に「回数」じゃなくて??? ↑のコマンド実行結果にも Count [回数]って書いてあるし…)
あと、単位時間(the period)って どれぐらいなのでしょう? …と思いましたが、記録されている時間が 5分毎なので、恐らく 単位時間も5分なのでしょう。EC2の標準状態(無料)の監視間隔と同じですね。

他の値も見ておきます。
$ mon-get-stats \
     VolumeTotalWriteTime \
     --statistics Sum \
     --namespace AWS/EBS \
     --dimensions "VolumeId=vol-6057ec42"

2013-02-17 19:36:00  0.044  Seconds
2013-02-17 19:41:00  0.044  Seconds
2013-02-17 19:56:00  0.26   Seconds
2013-02-17 20:01:00  0.124  Seconds
2013-02-17 20:06:00  0.196  Seconds
2013-02-17 20:11:00  0.088  Seconds
2013-02-17 20:16:00  0.028  Seconds
2013-02-17 20:21:00  0.032  Seconds
2013-02-17 20:26:00  0.072  Seconds
VolumeTotalWriteTimeは「書き込みに処理かかった時間(=待たされた時間)」ということらしいです。これと VolumeTotalReadTime の値が高い値になったら、EBSの処理が遅延しているということになりますね…たぶん。
⇒ 実際に負荷試験するなり、実運用しているEBSから値を取得するなりしないと、ホントのところは分かりませんが…。




・まとめ???
mon-* 系コマンド(というか CloudWatch)には、Namespace / Metrics / Statistics / Dimensions / Unit / Period という値が登場しますが…。ここまでコマンドを使ってみた結果、以下のような感じになっているものと思われます。


Namespaceデータ取得元の大雑把な分類 (AWS/EC2、AWS/EBS など)
Metricsデータの種類 (CPU使用率、失敗回数、遅延時間など)
Dimensionsデータ取得元の詳細な分類(Volume-ID、Instance-ID など)
Statisticsデータの統計方法(平均、合計、最大、最小、記録回数など)
Unit データの単位 (~秒、~バイト、~ビット、~パーセント、~回、~バイト/秒 など)
Periodデータを取得/統計する単位時間 (標準の無料利用状態だと5分単位)

標準で用意されたデータを参照して利用するだけでは、単なる簡単で便利な自動監視機構にしか見えませんが…。
カスタムメトリックス(mon-put-data とか?)とアラームを使いこなせれば、もっと高度に使えそうな気がします…。
⇒ そもそも AutoScaling の基礎になっているので、そのとおりなのですが…(^^;



今回はここまで……。

SNS(Simple Notification Service)をコマンドラインから設定します。
sns*系のコマンドライン版プログラムをインストールしていない場合は、以前の記事を参考にインストールしておいてください。


・SNS登録の手順/概要
SNSに登場するオブジェクトは3つ。
トピック           - 通知先ごとのグループ
サブスクリプション - 通知先、あるいはメッセージの購読者
メッセージ - 送信されるテキスト、あるいはデータ
SNSでは、まず 通知先ごとのグループとなるトピックを作成し、そこに購読者である通知先を登録(サブスクリプト)します。トピックへの通知先登録時には確認(confirmation)が必要になります。
その後、メッセージをトピックに対して送信すると、各登録者(通知先)にメッセージが送信されます。



・SNS系コマンドの使い方
sns*系コマンドの一覧は、http://docs.aws.amazon.com/sns/latest/cli/command-reference.htmlか、あるいは sns-cmd コマンドで入手できます。

$ sns-cmd
Command Name                       Description
------------                       -----------
help
sns-add-permission                 Add a permission to a topic.
sns-confirm-subscription           Confirm a Subscription.
sns-create-topic                   Create a topic.
sns-delete-topic                   Delete a topic.
sns-get-subscription-attributes    Get subscription attributes.
sns-get-topic-attributes           Get topic attributes.
sns-list-subscriptions             List all subscriptions.
sns-list-subscriptions-by-topic    List subscriptions by topic.
sns-list-topics                    Lists all topics.
sns-publish                        Publish a message to a topic.
sns-remove-permission              Remove permission from a topic.
sns-set-subscription-attributes    Set subscription attributes.
sns-set-topic-attributes           Set topic attributes.
sns-subscribe                      Subscribe to a topic.
sns-unsubscribe                    Unsubscribe from a topic.
version                            Prints the version of the CLI tool and the API.

    For help on a specific command, type '<commandname> --help'

コマンド一覧を見る限り、流れとしては以下のようになると思われます。
sns-create-topic                - トピックの作成
sns-list-topics - トピック一覧の表示

sns-subscribe - トピックの通知先追加を要求
sns-confirm-subscription - トピックへの通知先追加を承認
sns-list-subscriptions - 通知先一覧の表示
sns-list-subscriptions-by-topic - トピックごとの通知先一覧の表示

sns-publish - 通知の送信

sns-unsubscribe - 通知先の削除

sns-delete-topic - トピックの削除
それでは、その手順でやってみましょう。




・トピック作成
sns-create-topic コマンドでトピック名を指定するだけで作成されるらしい。
$ sns-create-topic sample_topic
arn:aws:sns:us-east-1:488224276535:sample_topic
あれ???
us-east-1 って???
環境変数の EC2_URL と EC2_REGION を指定しているハズですが、効果が無いようですね...。

sns-create-topic に --help オプションを与えて説明を見てみると… AWS_REGION と AWS_SNS_URL という環境変数が参照されるようです。メンドクサイので設定しておきましょう。ここでは、既に EC2_URL と EC2_REGION の環境変数が設定してあるので、それを利用して再設定します。マトメるとこんな感じ。
export EC2_REGION='ap-northeast-1'
export EC2_URL=ec2.${EC2_REGION}.amazonaws.com

export AWS_REGION=${EC2_REGION}
export AWS_SNS_URL=http://sns.${AWS_REGION}.amazonaws.com
バッチファイルや .bash_profile / .login にも追記しておくと良いでしょう。
⇒ AWS_SNS_URL は先頭に http:// が無いと正しく認識されないようです。EC2_URL側は 無くてもOKなのに...。

間違って作成したトピックは、↑の環境変数を設定する前に、以下のように削除しておきます。
$ sns-delete-topic \
     --force \
     --topic-arn arn:aws:sns:us-east-1:488224276535:sample_topic

Topic deleted.

$ sns-list-topics
No topics found.
で、トピックの再作成は以下のような感じ。というか、さっきと同じコマンドです。
$ sns-create-topic sample_topic
arn:aws:sns:ap-northeast-1:488224276535:sample_topic

$ sns-list-topics
arn:aws:sns:ap-northeast-1:488224276535:sample_topic
期待通りに Tokyo Region (ap-northeast-1)になってますね。



・サブスクライブ(送信先の登録)
送信先を登録するには sns-subscribe コマンドを使用します。
パラメータには TOPIC_ARN (トピックID)、--protocol オプションで http/https/email/email-json/sqs のいずれか、--endpoint オプションで URL/メールアドレス/SQS_ARN を指定します。
ここでは、「メールを送信する」という設定で登録することにします。
$ sns-subscribe \
     arn:aws:sns:ap-northeast-1:488224276535:sample_topic \
     --protocol email \
     --endpoint 'exploreaws@example.com'

Subscription request received.
sns-subscription コマンドだけでは、登録は完了しません。
sns-subscriptionが 正しく受け付けられると、指定したメールアドレスにメールが届きます。
送信主は no-reply@sns.amazonaws.com で、タイトルが「AWS Notification - Subscription Confirmation」となっているハズです。
メールには URL (リンク)が含まれていますが、ここではクリックはしないでください。
メールに含まれているURLは、以下のようになっています。
https://sns.ap-northeast-1.amazonaws.com/confirmation.html
     ?TopicArn=arn:aws:sns:ap-northeast-1:488224276535:sample_topic
     &Token=~長い文字列~
     &Endpoint=exploreaws@example.com
Token パラメータである ~長い文字列~ の部分がサブスクライブ用トークンなので、コピーしておきます。TopicArn は、先ほど作成したトピックのIDですね。

sns-confirm-subscription  コマンドを使った サブスクライブの確認(confirmation)には、先ほどコピーした サブスクライブ用トークンと TOPIC_ARN が必要です。以下のようにして sns-confirm-subscription コマンドを呼び出します。
$ sns-confirm-subscription \
     arn:aws:sns:ap-northeast-1:488224276535:sample_topic \
     --token サブスクライブ用トークン

arn:aws:sns:ap-northeast-1:488224276535:sample_topic:e39a9b52-d792-481d-a5a6-8e8763951e99
sns-confirm-subscription のレスポンスとして、サブスクリプションARN(Subscription ARN)が表示が表示されます。

登録がホントに完了しているかどうか sns-list-subscriptions と sns-list-subscriptions-by-topic  コマンドで確認してみます。
$ sns-list-subscriptions
arn:aws:sns:ap-northeast-1:488224276535:sample_topic:e39a9b52-d792-481d-a5a6-8e8763951e99  email  exploreaws@example.com


$ sns-list-subscriptions-by-topic \
     arn:aws:sns:ap-northeast-1:488224276535:sample_topic

arn:aws:sns:ap-northeast-1:488224276535:sample_topic:e39a9b52-d792-481d-a5a6-8e8763951e99  email  exploreaws@example.com
登録が1コしかないので良く分かりませんが、一応登録できているのでしょう…。
email の前に表示されているのが、Subscription ARN でしょうね。



・メッセージ送信
sns-publish コマンドで送信します。
本文は --message オプションで指定します。
プロトコルが email-json の場合は --message-structure で指定するらしいです。
更にプロトコルが email の場合、--subject でタイトルを指定できます。
$ sns-publish \
     arn:aws:sns:ap-northeast-1:488224276535:sample_topic \
     --message 'Message body.'

a225674d-2aa5-540c-9db3-2ed850443eee
レスポンスで表示される文字列は message-ID らしいです。
指定されたメールアドレス(ここでは exploreaws@example.com)に…
タイトル「AWS Notification Message」
本文「Message body.」+ 登録解除用URL等
…というメールが届きました。

今度は、タイトルを指定して送信してみましょう。ついでに複数行の送信が出来るかも試してみます。
$ sns-publish \
     arn:aws:sns:ap-northeast-1:488224276535:sample_topic \
     --message 'Message body.
<改行キー>
     Second line.' \
     --subject 'email title'

f9e9c50b-b1d3-50c2-9ab6-8c9ecad42662
この送信方法だと、
タイトル「email title
本文「Message body.
   Second line.」+ 登録解除用URL等
…というメールが届きました。バッチリですね。



・サブスクライブ解除(送信先の登録解除)
サブスクライブ解除には sns-unsubscribe コマンドを使用します。
sns-confirm-subscription あるいは sns-list-subscription コマンドなどで得られる Subscription ARN がパラメータとして必要になります。
$ sns-list-subscriptions
arn:aws:sns:ap-northeast-1:488224276535:sample_topic:e39a9b52-d792-481d-a5a6-8e8763951e99  email  exploreaws@example.com

$ sns-unsubscribe  \
     arn:aws:sns:ap-northeast-1:488224276535:sample_topic:e39a9b52-d792-481d-a5a6-8e8763951e99
Unsubscribed.

$ sns-list-subscriptions
No subscriptions found.
これで、サブスクリプション登録が消えました。



・トピックの削除

最後に残ったトピック「sample_topic」を削除します。
sns-list-topics で TopicARN を取得し、sns-delete-topic に渡すことで削除できます。
ホントに削除してよいかどうか確認するプロンプトが出るので「y」と答えれば、削除が完了します。
$ sns-list-topics
arn:aws:sns:ap-northeast-1:488224276535:sample_topic

$ sns-delete-topic \
     arn:aws:sns:ap-northeast-1:488224276535:sample_topic

    Are you sure you want to delete this topic? [Ny] y
Topic deleted.

$ sns-list-topics
No topics found
確認プロンプトを出したくない場合は --force オプションを使用してください。


これでトピックもバッチリ消えました!



今回はここまで。

CloudWatch を使いたい……のですが、以前 GUI 版で試した限りでは、先に SNS (Simple Notification Service)の設定が必要になります。
しかし、ザッと見てみた限りでは Amazon Linux でも sns-* 系のコマンドはインストールされていないように見えます…。



・SNS用コマンドラインツールの入手/ダウンロード
http://docs.aws.amazon.com/sns/latest/cli/welcome.html
上記 Amazon 公式マニュアル (API Version 2010-03-31 のモノ)を読むと、sns-* 系のコマンドは 別途インストールする必要があるようです。そもそもSNS用のコマンドラインツール自体、「コミュニティが制作したモノ」であって公式ツールではないとのこと…。

SNS用のコマンドラインツールは、以下のURLから入手できます。
⇒ http://sns-public-resources.s3.amazonaws.com/SimpleNotificationServiceCli-2010-03-31.zip

Amazon Linux に ssh し、そこから wget で取得してみます。
$ wget 'http://sns-public-resources.s3.amazonaws.com/SimpleNotificationServiceCli-2010-03-31.zip'

--2013-02-12 10:32:32--  http://sns-public-resources.s3.amazonaws.com/SimpleNotificationServiceCli-2010-03-31.zip
Resolving sns-public-resources.s3.amazonaws.com... 207.171.189.81
Connecting to sns-public-resources.s3.amazonaws.com|207.171.189.81|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6537754 (6.2M) [application/zip]
Saving to: “SimpleNotificationServiceCli-2010-03-31.zip”

100%[====================================================>] 6,537,754   1.38M/s   in 8.7s

2013-02-12 10:32:42 (736 KB/s) - “SimpleNotificationServiceCli-2010-03-31.zip” saved [6537754/6537754]

特に問題なくダウンロード成功しました。



・SNSコマンドラインツールのインストールと環境設定

ダウンロードした 付似せファイルをunzipコマンドで展開します。
$ unzip SimpleNotificationServiceCli-2010-03-31.zip
Archive:  SimpleNotificationServiceCli-2010-03-31.zip
   creating: SimpleNotificationServiceCli-1.0.3.3/
  inflating: SimpleNotificationServiceCli-1.0.3.3/README.TXT
 ~
unzipで展開したディレクトリを見てみると…
$ cd SimpleNotificationServiceCli-1.0.3.3/
$ ls -1
bin
credential-file-path.template
lib
license.txt
notice.txt
README.TXT
RELEASENOTES.TXT
THIRDPARTYLICENSE.TXT
README.TXTというのがあるので、コレの中身を確認します。期待通り、インストール手順が書かれていました。
Installation:
-------------
1. Ensure that JAVA version 1.6 or higher is installed on your system: (java -version)
2. Unzip the deployment zip file
3. Set the following environment variables:
3.1 AWS_SNS_HOME - The directory where the deployment files were copied to
        check with:
           Unix: ls ${AWS_SNS_HOME}/bin should list sns-cmd...)
           Windows: dir "%AWS_SNS_HOME%\bin" should list sns-cmd ...)
3.2 JAVA_HOME - Java Installation home directory
4. Add ${AWS_SNS_HOME}/bin (in Windows: "%AWS_SNS_HOME%\bin") to your path

READMEによると JavaVM1.6以上 が必要らしいので JVM のバージョンを調べてみます。
$ java -version
java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.5) (amazon-53.1.11.5.47.amzn1-i386)
OpenJDK Client VM (build 20.0-b12, mixed mode)
え゛ー。Amazon Linux ってOpenJDK がインストールされているんですね…。まぁ、互換性が問題になるようなものはインストールしていないのでコレで良いというコトにしておきます。
で、肝心のJava のバージョンは 1.6 以上なのでOK。

次は、Java用の環境変数。
$ export  | grep JAVA
declare -x JAVA_HOME="/usr/lib/jvm/jre"
JAVA_HOME 環境変数も期待通り設定されています。



次はファイルの配備場所です。
AmazonLinux では /opt/aws/ の下に AWS用コマンドラインツールがインストールされているので、それに倣って 同じような場所にインストールしてみます。
まず、展開したパッケージファイル群の所有者をrootに変更の上、/opt/aws/others/ へ移動します。
$ sudo chown -R root:root SimpleNotificationServiceCli-1.0.3.3/
$ sudo chmod -R u=rwx,og=rx SimpleNotificationServiceCli-1.0.3.3/

$ sudo mkdir /opt/aws/others
$ sudo chmod u=rwx,og=rx  /opt/aws/others
$ sudo mv SimpleNotificationServiceCli-1.0.3.3  /opt/aws/others/
別バージョンをインストールする際にカンタンに切り替えられるよう、symbolic link を作成します。
$ cd /opt/aws/others
$ sudo ln -s SimpleNotificationServiceCli-1.0.3.3/  sns
/opt/aws/others/sns/bin/ ディレクトリにある sns-* に該当するファイルの symbolic link を /opt/aws/bin/ の下に作成します。
$ cd /opt/aws/bin/
$ ls -1 /opt/aws/others/sns/bin/sns-* \
     | grep -v '.*\.cmd$' \
     | sed -e 's!^.*/!!' \
     | xargs -i sudo ln -s /opt/aws/others/sns/bin/{}  {}

ここまででファイル配備は完了。

次は…sns-* コマンド用の環境変数 AWS_SNS_HOME を設定します。
に PATH を通す必要があるので、以下のように設定します。
export AWS_SNS_HOME=/opt/aws/others/sns
環境変数PATHに、sns-* コマンドのディレクトリも登録する必要がありますが……、先にsymbolic link を /opt/aws/bin/ に作成しておいたので問題ナシです。


他に AWS_CREDENTIAL_FILE も必要なので、設定していないようなら追記しておきます。アクセスキー等は以前の方法で入手したものでOK。
$ export AWS_CREDENTIAL_FILE=~/.aws/aws-accesskey.ini

$ cat ~/.aws/aws-accesskey.ini
AWSAccessKeyId=アクセスキー
AWSSecretKey=シークレットアクセスキー
ここでは、export 設定をマトメてバッチファイルに記載しておきます。
メンドクサければ .bash_profile や .login 等に記載してもよいかもしれません。



・SNSコマンドラインツールの動作確認
環境変数が設定出来たら早速実行してみます。
⇒ ここでは、EC2_URL、EC2_REGION、AWS_CREDENTIAL_FILE、AWS_ACCESS_KEY、AWS_SECRET_KEY が正しく設定されている環境で動作確認しています。
$ sns-version
Amazon SimpleNotificationServiceCli CLI version w.x.y.z (API 2010-03-31)

$ sns-list-topics
No topics found.
バージョン表記が w.x.y.z とかなっていてチョット変ですが……バッチリ動作するようになりました!!!



これで、sns-* 系のコマンドが利用できるようになりました☆

このページのトップヘ