フロムスクラッチ開発者ブログ

from scratch Engineers' Blog

大規模SaaS運用におけるAWSコスト削減7箇条

 こんにちは。フロムスクラッチのインフラチームに所属している山崎です。
今回は「大規模SaaS運用におけるAWSコスト削減」について投稿させて頂きます。

AWSのコスト管理に悩んでいる方は多いんじゃないかと思います。時間あたり費用は微々たるものですが、積もり積もると「え、こんなに使ったっけ?」ってなりますよね。

以下、私が実施してきたコスト削減の方法を大まかに挙げていきます。

 

(1)不要なサービスを停止・削除する。
簡単にAWS費用を分けると下記のようになります。

 1.サービス利用料
 2.サポート費用
 3.税金

3項目とも使用時間が長いほど請求されるので、身も蓋もない言い方をすれば、いかに使わないかがコスト削減の鍵になります。影響確認を実施して必要な手順を踏んだ後、ガンガンと停止・削除を進めていきましょう!(じゃないと、コストは下がりません)

◆AWSサポートプラン

f:id:daisuke-yamasaki:20180306181605p:plain

  

(2)本番環境と開発環境でサポートのプランを分ける(アカウントを分ける)
(1)で示したサポート費用はプランが4つに別れ、それぞれでサービス・費用が異なります。環境に合わせた適切なプランを選択しましょう。

https://aws.amazon.com/jp/premiumsupport/signup/

例えば、本番環境は「ビジネス」か「エンタープライズ」プランのアカウント、開発環境は「開発者」プランのアカウントに分けるだけでコストを削減できます。

◆アカウント作成

f:id:daisuke-yamasaki:20180306181738p:plain

  

(3)RIを利用する。
RI(reserved instance)を利用することで、通常のオンデマンド費用を割引額で利用することができます。RIは、EC2,RDS,Redshift,DynamoDB,Elasticacheの各種サービスで適用することが可能です。割引額は、EC2でだいたい20%~50%です。ただし、1年または3年の長期契約となるので、サービスや財務の見通しを考えて購入しましょう。AWSは変化が早く年単位で新世代のインスタンスがリリースされることがあるので、期間1年のRIを支払い方法「一部前払い」で購入することをオススメします。「一部前払い」も「全前払い」もあまり割引率が変わりませんので、キャッシュアウトが少なくてすむ「一部前払い」のほうが良いでしょう。

 

購入後のRI数の確認についてですが、RIとオンデマンドインスタンス数がリアルタイムで分かるように監視ツールを整えれば、現状確認をスムーズに行うことができます。

最後になりますが、EC2のRIは「統合」「分割」ができます。例えば、同時購入した「m4.xlarge」が2つあれば、「m4.2xlarge」に「統合」でき、その逆に「m4.2xlarge」を2つの「m4.xlarge」に分割できます。この機能を利用できる機会ができたら、コスト削減に利用しましょう。

◆EC2 リザーブドインスタンス

f:id:daisuke-yamasaki:20180306181901p:plain

  

(4)夜間・休日はサーバを止める。
主に開発環境の話になりますが、使わない時間帯のサーバを自動で止め、コストを削減しましょう。

  

(5)過剰な冗長設定を外す。
RDSの「マルチAZ」が本当に必要か、リードレプリカの数やELBに繋がったEC2の数は妥当か検討しましょう。「マルチAZ」だと「シングルAZ」の2倍の費用を払う必要があります。サービスローンチ当初はインシデントを防ぐため「マルチAZ」を選びがちですが、必要ないと判断できたら「シングルAZ」にしましょう。

 

 (6)定期的に性能を見直す。
リソース状態を見て、サーバの性能が過剰になっていないか検討しましょう。(インシデントを防ぐため、その逆も実施しましょう)EC2の性能は高すぎないか、数を集約できないか、Redshiftのノード数は適切か、などです。ただし、性能を落とすことはサービス影響のリスクがあるので慎重に実施しましょう。

 

 (7)不要なAMIやスナップショットは定期的に削除する。
地味ですが、不要なバックアップ類は管理されないと増え続けます。1ヶ月に1回など定期的な削除機会を作り、定期削除を実施しましょう。

 

以上、AWSインフラのコスト削減方法について記載しました。ご覧頂きありがとうございました。

Apache ZooKeeperの内部解析してみる vol.2 ~ZooKeeper操作編~

こんにちは、fukuです。

前回に引き続きApache ZooKeeperについて書いていきます。前回ではZooKeeperの概要の説明を行いました。ZooKeeperではznodeから構成されるデータノードを管理しており、クラアントはAPIを通じてデータノードの操作を行うことができます。 今回は実際にZooKeeperを操作することでZooKeeperのAPIなどについての理解を深めていきましょう。

インストール

ZooKeeperのダウンロードページApache ZooKeeper - Releasesからダウンロードを行います。今回はZooKeeperのバージョン3.5.3-beta(何事も先取って検証)を対象とし、macOS Sierra(バージョン10.12.6)のOS環境上で検証を行いました。 ダウンロードしたzookeeper-3.5.3-beta.tar.gzファイルを任意のディレクトリに置き、以下のコマンド群を実行することで、ZooKeeperの起動の準備をします。

$ tar zxvf zookeeper-3.5.3-beta.tar.gz
$ cd zookeeper-3.5.3-beta.tar.gz
$ cp conf/zoo_sample.cfg conf/zoo.cfg

上記のコマンドを実行でZooKeeperが起動できるようになったので、以下のコマンドからスタンドアローンモードでZooKeeperをバックグラウンド(デフォルトポート2181)で起動することができます。

$ bin/zkServer.sh start

またサブコマンドを変更することでフォアグラウンドで実行することも可能です。

$ bin/zkServer.sh start-foreground

サーバを停止する時は、以下のコマンドを実行してください。

$ bin/zkServer.sh stop

ZooKeeperの利用

サーバを立ち上げた状態で、ZooKeeperのディレクトリにおいて以下のコマンドを実行することで、クライアントを起動することができます。

$ ./bin/zkCli.sh

無事に接続が確立すると、クライアントコマンドの待ち受け状態になります。ここでhelpを入力して、コマンド一覧を表示してみましょう(実際にはhelpというコマンドは存在せず、存在しないコマンドを入力することで以下のようなUSAGE情報が表示されます)。

[zk: localhost:2181(CONNECTED) 0] help
ZooKeeper -server host:port cmd args
    addauth scheme auth
    close 
    config [-c] [-w] [-s]
    connect host:port
    create [-s] [-e] [-c] [-t ttl] path [data] [acl]
    delete [-v version] path
    deleteall path
    delquota [-n|-b] path
    get [-s] [-w] path
    getAcl [-s] path
    history 
    listquota path
    ls [-s] [-w] [-R] path
    ls2 path [watch]
    printwatches on|off
    quit 
    reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
    redo cmdno
    removewatches path [-c|-d|-a] [-l]
    rmr path
    set [-s] [-v version] path data
    setAcl [-s] [-v version] path acl
    setquota -n|-b val path
    stat [-w] path
    sync path
Command not found: Command not found help

今回はいくつかのコマンドを実際に実行することで、ZeeKeeperで行えることをみていきましょう。

データツリーの操作

まずlsコマンドを使ってZooKeeperのデータノードを覗いてみましょう。

[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]

上記から、データノードのルートノードには[zookeeper]のznodeがあることがわかります。[zookeeper]ノードはZooKeeperのシステム情報を管理するためのノードとなります。

それでは次にcreateコマンドからznodeを作成してみましょう。

[zk: localhost:2181(CONNECTED) 2] create /clients ""
Created /clients
[zk: localhost:2181(CONNECTED) 3] ls /              
[zookeeper, clients]

このようにcreateコマンドの第1引数にznodeの名前、第2引数でznodeに格納するデータを指定することで、znodeが作成されます。 ちなみに今回のcreateコマンドでできたznodeはPERSISTENTノードとなります。

getコマンドではznodeの情報を参照することができます。

[zk: localhost:2181(CONNECTED) 4] get /clients

ここでは、出力としてcreate`コマンドで指定したデータ(今回は空文字列)が出力されます。

続いてsetコマンドで、znodeのデータを変更してみましょう。

[zk: localhost:2181(CONNECTED) 5] set /clients "hogehoge"
[zk: localhost:2181(CONNECTED) 6] get /clients           
hogehoge

上位のようにznodeに格納されているデータが空文字列から"hogehoge"に変わっていることがわかります。znodeのデータセットで注意しなければならないことは、データが置き換わるということです。そのためデータを追記したりすることはできません。

クライアントのセッションを終了するにはquitコマンドを実行します。

[zk: localhost:2181(CONNECTED) 7] quit
Quitting...
2017-12-30 20:32:17,295 [myid:] - INFO  [main:ZooKeeper@687] - Session: 0x160a6c05dcf0004 closed
2017-12-30 20:32:17,298 [myid:] - INFO  [main-EventThread:ClientCnxn$EventThread@520] - EventThread shut down for session: 0x160a6c05dcf0004

znodeのモード

ここでは前回記事で紹介したznodeのいろいろなモードを試していきたいと思います。createコマンドにはモードを指定するオプションが存在しており、オプションを指定する事によって、いろいろなモードのznodeを作成することができます。

PERSISTENT

PERSISTENTモードのznodeは、先ほどのようにcreateのオプションなしで作成することができます。

[zk: localhost:2181(CONNECTED) 0] create /clients/c1 "PERSISTENT"
Created /clients/c1

PERSISTENTモードではznodeが永続化されるので、セッションを終了してから、再度セッションを開始してもznodeがそのまま存在することが確認できます。

PERSISTENTモードのznodeを削除するにはdeleteコマンドによって、明示的に削除を行う必要があります。

[zk: localhost:2181(CONNECTED) 1] delete /clients/c1
[zk: localhost:2181(CONNECTED) 2] ls /clients
[]

EPHEMERAL

EPHEMERALモードではznodeの作成を行なったセッションが切断されると、znodeは自動的に削除されます。createコマンドで-eオプションの指定でEPHEMERALモードのznodeを作成することができます。ここではクライアントを2つ立ち上げてEPHEMERALモードのznodeをみていきます。

#  クライアント1
[zk: localhost:2181(CONNECTED) 0] create -e /clients/ephemeral-client "EPHEMERAL"
Created /clients/ephemeral-client

#  クライアント2
[zk: localhost:2181(CONNECTED) 0] ls /clients
[ephemeral-client]

#  クライアント1
[zk: localhost:2181(CONNECTED) 1] quit
Quitting...
2017-12-30 20:47:29,178 [myid:] - INFO  [main:ZooKeeper@687] - Session: 0x160a6c05dcf0006 closed
2017-12-30 20:47:29,180 [myid:] - INFO  [main-EventThread:ClientCnxn$EventThread@520] - EventThread shut down for session: 0x160a6c05dcf0006

# クライアント2
[zk: localhost:2181(CONNECTED) 1] ls /clients
[]

上記のようにクライアント1でEPHEMERALモードのznodeを作成すると、クライアント2でも作成したznodeの確認が行えます。次にクライアントのセッションを終了して、クライアント2でznodeの確認を行うとEPHEMERALモードのznodeのノードが削除されていることがわかります。

CONTAINER

CONTAINERモードのznodeは自身の子ノードが削除されると自動的にznodeが削除されます。createコマンドの-cオプションによって、CONTAINERモードを指定することができます。

[zk: localhost:2181(CONNECTED) 0] create -c /container ""
Created /container
[zk: localhost:2181(CONNECTED) 1] create  /container/child ""
Created /container/child
[zk: localhost:2181(CONNECTED) 2] delete /container/child 
[zk: localhost:2181(CONNECTED) 3] ls /
[clients, container, zookeeper]

<しばらくした後>

[zk: localhost:2181(CONNECTED) 4] ls /
[clients, zookeeper]

上記のようにCONTAINERモードのznode(/container)を作成して、子ノードを作成・削除します。その後にCONTAINERモードのznodeはすぐには削除されませんが、一定時間ののちにZooKeeperによって自動的に削除されます。

PERSISTENT_TTL

PERSISTENT_TTLモードがznodeの生存時間を指定することができ、指定時間後にZooKeeperによって自動的に削除されます。createコマンドの-tオプションによってPERSISTENT_TTLモードを指定することができます。

[zk: localhost:2181(CONNECTED) 0] create -t 600 /ttl_node ""
[zk: localhost:2181(CONNECTED) 1] ls /
[clients, ttl_node, zookeeper]

<しばらくした後(600ms以上)>

[zk: localhost:2181(CONNECTED) 2] ls /
[clients, zookeeper]

生存時間は-tオプションの後ろにミリ秒単位で指定します(上記は600ms)。作成直後はznodeが存在していることが確認できますが、600ms後しばらくしてから、確認するとznodeが削除されていることが確認できます。

ここで注意しなければいけないのは、ちょうど600ms後に削除されるのではなく、ZooKeeperの定期的にTTLモード(CONTAINERモードも同様)の削除を行うタイミングで削除が行われるという点です。そのため600ms後に初めてのZooKeeperの削除サイクルのタイミングが来た時に削除されます。デフォルトではZooKeeperの削除サイクルの時間間隔は2000msとなります。

長くなってしまったので、今回はこの辺で....

おわりに

今回は実際にZooKeeperをスタンドアローンモードで起動して、CLIからデータツリーに対するさまざまな操作を行いました。 次回はソースコードからデータツリーがどのように管理されているのかをみていこうと思います。

ではでは...

運用中のRedshiftを旧世代から最新世代に移行する方法

はじめまして。

フロムスクラッチでエンジニアをしている山崎と申します。
普段はAWSを用いたインフラの運用・構築、およびコスト管理を担当しています。

今後私からは、AWSを用いたインフラに関わる「技術」「コスト管理」について、他社の方もご興味ありそうなトピックを共有させて頂ければ幸いです。

 

さて1回目のテーマは、「運用中のRedshiftを旧世代から最新世代に移行する方法」です。

2017年10月にアナウンスがあり、Redshiftにて第二世代のdc2を冠した性能を選ぶことができるようになりました。

 

Amazon Redshiftに新世代のDC2ノードが追加 – 価格はそのままで最大2倍の性能向上

https://aws.amazon.com/jp/blogs/news/amazon-redshift-dc2/

 

価格はそのままで性能が向上するなら、そりゃdc1からdc2に移行したくなるのは当然ですね。問題は”どうやってサービス影響が最も小さくなるように移行するか”ということになります。

 

移行方法のアイディアは2つあります。

 

(1)dc1のRedshiftクラスタをリサイズしてdc2にする。

(2)dc1のRedshiftクラスタの更新を止め、スナップショットを取得して復元。その後名前を入れ替える。

 

具体的に中身を見ていきます。

(1)について

こちらはシンプルですね。以下の通り、クラスタの性能をdc2にそのまま変えるだけです。

 

Redshiftダッシュボード>クラスター>対象クラスタを選択>クラスター>サイズ変更>ノードの種類をdc2にする>サイズ変更 

f:id:daisuke-yamasaki:20180301170946p:plain

f:id:daisuke-yamasaki:20180301172324p:plain

 

ただし、リサイズ中はクラスタが”Read-Only”になるので注意しましょう。で、問題はリサイズにどのくらいの時間がかかるか。2017年11月に検証した時の情報ですが、非常に時間がかかりました。具体的には、約430GBのデータがあり3ノードで運用しているクラスタのdc1→dc2のリサイズに392分の時間がかかりました。とてもじゃないですが、この間”Read-Only”にしておけません。



(2)について

こちらは若干作業に手間がかかりますが、作業時間が読めるのでお勧めします。作業時間は約1時間、うちクラスタへの接続断時間は約2分程度でした。
ただし、クラスタのエンドポイントは移行前後で同じですが、クラスタのIPアドレスは変わると推測されるので、クラスタのIPアドレスを指定して接続するシステムの場合は作業前に充分な検討をしてください。

 

1.移行対象クラスタ(名前=クラスター識別子をAとする)への更新を止める。

 

2.クラスタ(A)のスナップショットを取得する。スナップショット識別子は分かり易い名前にしましょう。

f:id:daisuke-yamasaki:20180301172422p:plain

f:id:daisuke-yamasaki:20180301172425p:plain

 

3.2で取得したスナップショットを、「ノードタイプ:dc2、クラスター識別子:スナップショット取得元と別名(Bとする)、その他の設定:同じ」で復元する。

f:id:daisuke-yamasaki:20180301172630p:plain

f:id:daisuke-yamasaki:20180301172723p:plain

 

4.Aのクラスター識別子をCにする。

f:id:daisuke-yamasaki:20180301172901p:plain

f:id:daisuke-yamasaki:20180301172904p:plain

 

5.Bのクラスター識別子をAにする。

 

6.Aへのアプリからの接続がOKであることを確認する。

 

7.Cを削除する。

f:id:daisuke-yamasaki:20180301173037p:plain

 

8.Aへの更新を開始する。




以上、「運用中のRedshiftを旧世代から最新世代に移行する方法」について書いてきました。本内容はあくまで弊社で試した内容になりますので、実施する際は必ず事前検証をお願い致します。ご覧頂きありがとうございました。