はてな、500 Startups Japanを通じたスタートアップ支援。サーバー監視サービス「Mackerel」で特別プラン …

投資先企業に向けて「500 Startups」では、世界中のパートナー企業と連携した関係者特典「Perks」を提供しています。「500 Startups Japan」の投資先企業は、スタートアップ支援に取り組むPerksの参加企業による「Amazon Web Service (AWS) 」や「Google Cloud Platform (GCP)」 、「Twilio」、「Wantedly」、「SmartHR」 … 続きを読む

t2.microインスタンスでWindowsは使い物になるのか?

ICDP(田舎クラウドデザインパターン)的なネタ再び。

概要

AWS EC2 t2.micro インスタンスのシステム資源は非常に乏しい。
AWS無料利用枠でウィンドウズも対象だけど、本当に使い物になるのか?

目的

t2.microインスタンスへWindows Server 2008R2をインストールしてソフトウェアを起動しようとしたところ、 Out of Memory で起動不能であった。
メモリ1GB、連続して演算できない制限付きのCPU能力で、ウィンドウズを使用するには厳しい。
動作させたいソフトウェアは必要メモリ500MBのため、なんとか使えるようにすることを目的とする。

要件

  • AMI
    Windows_Server-2008-R2_SP1-Japanese-64Bit-Base-2017.11.29 – ami-95d06bf3

  • ページファイル(スワップ)無しで使う。
    スワップが発生したら実用にならないためページファイルは無しとする。
    これはスワップ処理にはCPU時間を消費するため、CPU時間に制限があるt2系インスタンスでは動作が間欠的に停止したり、操作不能に陥ったりするからである。

現状

Windows Server 2008R2 をインストールして起動した状態はこのようになっている。
t2a.jpg

消費メモリは959MB。
メモリ1GBしか無いのに消費メモリがこの状況では無理もない。殆ど空きがない。
40MBではメモリ不足で起動不能となるのは当然であろう。

対処

タスクマネージャでメモリ使用状況を見て削減できそうなプロセスを調べる。
t2b.jpg

TrustedInstaller.exe が460MBも使用している。
これは何かと調べると、Windows Modules Installerサービスのようだ。
Windows Update関連のプログラムで、停止させると更新に失敗するが通常は問題無いので停止させてみた。

無効に設定したサービス

先の大物を含め、無効に設定したサービスは以下の通り。
ただしこれを行うとWindows Updateが失敗するので行う場合は手動で起動し対処すること。

  • Windows Modules Installer
  • Windows Update
  • WinHttp Web proxy Auto-Discovery Service

また、AWSオリジナルの制御機能を使わないのであれば以下も無効にできる。
こちらは計20MB程度の削減にしかならないのでお好みで。

  • Amazon SSM Agent
  • AWS Lite Guest Agent
  • Ec2Config

対処した結果

t2c.JPG

消費メモリが400MB程度となり、600MBの空きを確保できた。

結論

かろうじて要件を満たし動作可能な環境を構築できた。
しかし、リソースには余裕が無いためMackerel等で常時監視した方が良いと思われる。

続きを読む

CPUの脆弱性におけるEC2の保守対応(Amazon Linux、Windows)

CPUの脆弱性

年明け早々に問題になっている「CPUの脆弱性」について、AWSでの保守についてのメモです。

今回騒ぎになっているのは1月3日にProject Zeroの記事で紹介されたCPU脆弱性。

CPUの脆弱性の影響や対応方法などは、以下の記事がとてもわかりやすかったです。

上記の記事で、問題点や影響について大変わかりやすく解説されているので、この記事で脆弱性の問題は省いて、AWSのEC2における対応を書いて行きたいと思います。

EC2(Amazon Linux、Windows)の対応

Processor Speculative Execution Research Disclosureを簡単に要約すると、

KPTIのバグに対処と、CVE-2017-5754(不正なデータキャッシュ読み込み)の軽減策を改善するカーネルをリリースしました。最新のAmazon LinuxカーネルかAMIにアップデートすることによって対応されたカーネルが使えるようになります。

アップデートを推奨されているサービスは、
EC2EC2 WindowsECS Optimized AMElastic Beanstalk

また、RDSは現段階でユーザーが対応することは無いようです。

今回EC2について対応の流れを紹介していきます。

Amazon Linux

OSがAmazon Linuxの場合、最新のAMI、又はカーネルをアップデートして再起動。
現在(2018年1月11日)アップデートされるカーネルは以下になります。
Linux version 4.9.75-25.55.amzn1.x86_64
https://alas.aws.amazon.com/ALAS-2018-939.html


#対象のインスタンスにログインする
$ ssh hoge-instance

$ sudo su -

# カーネルを確認
# uname -srv
Linux 4.4.5-15.26.amzn1.x86_64 #1 SMP Wed Mar 16 17:15:34 UTC 2016
# 末尾のタイムスタンプはビルドされた日時を指している。

# カーネルをアップデートする
# yum update kernel -y
Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main/latest                                                                                                                                                               | 2.1 kB     00:00
amzn-updates/latest                                                                                                                                                            | 2.5 kB     00:00
mackerel/latest/x86_64                                                                                                                                                         | 2.5 kB     00:00
mysql-connectors-community/x86_64                                                                                                                                              | 2.5 kB     00:00
mysql-tools-community/x86_64                                                                                                                                                   | 2.5 kB     00:00
mysql56-community/x86_64                                                                                                                                                       | 2.5 kB     00:00
8 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package kernel.x86_64 0:4.9.75-25.55.amzn1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

======================================================================================================================================================================================================
 Package                                    Arch                                       Version                                                 Repository                                        Size
======================================================================================================================================================================================================
Installing:
 kernel                                     x86_64                                     4.9.75-25.55.amzn1                                      amzn-updates                                      18 M

Transaction Summary
======================================================================================================================================================================================================
Install  1 Package

Total download size: 18 M
Installed size: 72 M
Downloading packages:
kernel-4.9.75-25.55.amzn1.x86_64.rpm                                                                                                                                           |  18 MB     00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : kernel-4.9.75-25.55.amzn1.x86_64                                                                                                                                                   1/1

  Verifying  : kernel-4.9.75-25.55.amzn1.x86_64                                                                                                                                                   1/1

Installed:
  kernel.x86_64 0:4.9.75-25.55.amzn1

Complete!

カーネルをアップデート後、awsのコンソール画面より再起動。
(再起動しないとカーネルが更新されない)

# 再起動後
# uname -srv
Linux 4.9.75-25.55.amzn1.x86_64 #1 SMP Fri Jan 5 23:50:27 UTC 2018

脆弱性対応されたカーネル(Linux version 4.9.75-25.55.amzn1.x86_64)になっていることを確認。
このバージョンがビルドされた日も1月5日と最新ですね。

補足:使用しているAMIのバージョンが古い場合は、最新のAMIにアップデートする必要があります。

問題の脆弱性に対応できているか確認する

Linuxが脆弱性「Spectre」「Meltdown」に対応済みか調べる方法の記事を参考に、アップデートされたカーネル(Linux version 4.9.75-25.55.amzn1.x86_64)で検査しまします。

Spectre and Meltdown mitigation detection tool v0.24

Checking for vulnerabilities against live running kernel Linux 4.9.75-25.55.amzn1.x86_64 #1 SMP Fri Jan 5 23:50:27 UTC 2018 x86_64

CVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'
* Checking count of LFENCE opcodes in kernel:  NO  (only 35 opcodes found, should be >= 70)
> STATUS:  VULNERABLE  (heuristic to be improved when official patches become available)

CVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'
* Mitigation 1
*   Hardware (CPU microcode) support for mitigation:  YES 
*   Kernel support for IBRS:  NO 
*   IBRS enabled for Kernel space:  NO 
*   IBRS enabled for User space:  NO 
* Mitigation 2
*   Kernel compiled with retpoline option:  NO 
*   Kernel compiled with a retpoline-aware compiler:  NO 
> STATUS:  VULNERABLE  (IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability)

CVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3'
* Kernel supports Page Table Isolation (PTI):  YES 
* PTI enabled and active:  YES 
> STATUS:  NOT VULNERABLE  (PTI mitigates the vulnerability)

A false sense of security is worse than no security at all, see --disclaimer

AWSのProcessor Speculative Execution Research Disclosureに書いてあるように
確かにKPTIのバグ(Variant 3)は対処されていますが、CVE-2017-5754(不正なデータキャッシュ読み込み)の軽減策を改善するだけで、根本的に解決はできていないようです。

Windows 8.1 又は Windows Server 2012 R2

OSがWindows 8.1 又は Windows Server 2012 R2の場合
KB4056898のセキュリティプログラムをインストールします。

手順は対象のwindowsインスタンスからMicrosoft®Update カタログにアクセスし、対象のセキュリティプルグラムをインストール、再起動すれば完了です。

確認は、「コントロールパネル」 > 「システムとセキュリティ」 > 「Windows Update」 >「更新の履歴」
のタブを開き

Windows 用セキュリティ更新プログラム (KB4056898) インストール状態: 成功しました

となっていれば、対応完了です。

補足:更新プログラムしばらく更新していないマシンは、インストールに失敗する場合があるので、「コントロールパネル」 > 「システムとセキュリティ」 > 「Windows Update」 > 「更新プログラムを確認」 を開いて、プログラムを最新のものに更新して再起動してから、上記のセキュリティプログラムをインストールしましょう。

終わりに

今回の対応をとして完全に脆弱性が解決しているわけではないので、継続的にAmazon Linux AMI Security Centerをチェックして、(RSS feed有り)最新のカーネルにアップデートし続けた方が良さそうです。

今回のCPUの脆弱性で多くのマシンを保守していると脆弱性の対応がとても大変だなと痛感しました。エンジニアとして、できるだけ自分達で保守するものが少なくなるように努めて行きたいなと思います。

続きを読む

python + AWS Lambda でのmackerelの退役を自動化|GCREST_engineerのブログ

ジークレストでは、AWSを利用してアプリを開発しております。 今回は、AWSのAutoScalingで追加したインスタンスが不要になった際に. 監視対象からホストを退役させることを自動で行う方法をご紹介します。 監視対象の退役処理が自動化されることで. 誤検知や監視にかかるコストの無駄が増えないようしようという工夫です。 続きを読む

【AWS+Rails5+mackerel】AMIを使って複製したサーバがmackerelのダッシュボードに表示されない時の対処方法

やりたいこと

  • ALBに紐づけているWEB-APPサーバ1号機のAMIを取得して、2号機を立てたい

    • 1号機はmackerelエージェントをインストール済み
  • 2号機にもmackerelエージェントをインストールしたい

環境

  • AWS
  • Ubuntu 16.04
  • Rails5.1
  • Nginx
  • Unicorn

発生した事象

AMIから複製したサーバ2号機に、mackerelエージェントをインストールしてもダッシュボードに表示されない。
公式ページの手順に従い、以下のコマンドを実施。

wget -q -O - https://mackerel.io/file/script/setup-all-apt-v2.sh | MACKEREL_APIKEY='YOUR_APIKEY' sh

詳細

サーバ2号機のmackerelエージェントの起動ログを確認。

$ sudo journalctl -u mackerel-agent.service

以下のエラーが発生しており、mackerelエージェントが起動していない。

Dec 26 15:02:29 ip-10-100-4-182 systemd[1]: Starting mackerel.io agent...
Dec 26 15:02:29 ip-10-100-4-182 systemd[1]: Started mackerel.io agent.
Dec 26 15:02:29 ip-10-100-4-182 mackerel-agent[31438]: 2017/12/26 15:02:29 INFO <main> Starting mackerel-agent version:0.48.2, rev:549962c, apibase:https://api.mackerelio.com
Dec 26 15:02:29 ip-10-100-4-182 mackerel-agent[31438]: command.Prepare failed: failed to prepare host: custom identifiers mismatch: this host = "hogehoge.ec2.amazonaws.com", the host whose id is "hogehoge" on mackerel.io =
Dec 26 15:02:29 ip-10-100-4-182 mackerel-agent[31438]: exit status 1
Dec 26 15:02:29 ip-10-100-4-182 systemd[1]: mackerel-agent.service: Main process exited, code=exited, status=1/FAILURE
Dec 26 15:02:29 ip-10-100-4-182 systemd[1]: mackerel-agent.service: Unit entered failed state.
Dec 26 15:02:29 ip-10-100-4-182 systemd[1]: mackerel-agent.service: Failed with result 'exit-code'.

原因

AMIを使用して複製したため。

公式ページFAQにも記載があった。
FAQ・エージェントが起動しない

Docker ImageやAMIなどによりOSイメージ化した際に/var/lib/mackerel-agent/idもコピーしている場合、このファイルを削除する必要があります。
mackerel-agentは初回起動時にサーバーが発行したIDを/var/lib/mackerel-agent/idに保存します。以後はこのファイルに記載されたIDによりホストの識別を行います。
そのため、/var/lib/mackerel-agent/idがコピーされると実際は複数のホストがMackerel上では同一のホストと認識され、メトリックの投稿や監視が正しく動作しなくなります。

対策

  • サーバ2号機の/var/lib/mackerel-agent/idを削除する。
$ sudo rm /var/lib/mackerel-agent/id
  • 設定確認
$ sudo mackerel-agent configtest
sudo: unable to resolve host ip-10-xxx-xxx-xxx
/etc/mackerel-agent/mackerel-agent.conf Syntax OK
  • mackerelエージェント再起動
$ sudo service mackerel-agent restart

確認

mackerelダッシュボードに表示されれば成功です。
AMIでEC2を複製する際にはご注意ください。

続きを読む

GoでZabbixを爆速にしたかった

はじめに

こんにちは。
CYBIRDエンジニア Advent Calender 2017の22日目は@gucchonさんのゲーム開発をWebViewからUnityに乗り換えて、苦労したこと、良かったことでした。

本日の記事のあらすじ・動機

  • タイトルからもお察しかと思いますが, 失敗談になります。
  • 弊社ではサーバの監視にZabbixを使用しております。(一部はmackerelを使用させていただいております。)
  • Zabbixを容易に拡張する手段として”UserParameter”と”外部スクリプト”が存在します。
    • しかし, これらはメトリクスの取得の度にプロセスをforkするので負荷がかかります。
    • 外部スクリプトの過度の使用によってパフォーマンスが劣化することはZabbixのドキュメントに明記されております。
    • 弊社(のAWSを使用した案件)では外部スクリプトに頼った監視になっており, 監視サーバのインスタンスタイプが本番環境のWebサーバのインスタンスタイプを超えているケースがあったりします。
  • Zabbixサーバの負荷をなんとか抑えたいということが今回の動機になります。
  • Zabbixモジュールを使用することで, ネイティブ実装と同じパフォーマンスを得ることができる。
    • PHPのCGIモードとmoduleモードでパフォーマンスが異なる理由と同じになります。
    • UserParameter・外部スクリプトを使用するときのようなオーバーヘッド(fork)が削減されます。
    • ネイティブ実装と同じパフォーマンスを得ることができる。
    • Zabbixサーバのインスタンスタイプを落とすことが出来るかもしれない。
    • しかしZabbixモジュールを実装するためには基本的にはCで実装する必要があります。
  • そこでGolangで気軽にZabbixモジュールを作成して使用してみました。
    • しかし後述する, “ZabbixとGoランタイムの相容れないアーキテクチャ”によって失敗するという話になります…
  • 着想・実装にあたっては, @ike_daiさんの記事Golangを使ってZabbixを拡張大いに参考にさせていただいております。

実際にやってみた結果…

実装

  • 変数等のネーミングセンスがない件については, ご容赦ください。

    • AWSのCredentialを.envファイルから読み込んでおります。
    • github.com/cavaliercoder/g2zを使用させていただいております。
    • 既に作者様が行ったパフォーマンスのテストの結果がperformance.mdに記載されております。
mod_zabbix_go.go
package main

import (
    "C"
    "errors"
    "log"
    "strings"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/ec2"
    "github.com/joho/godotenv"
    g2z "gopkg.in/cavaliercoder/g2z.v3"
)

// main ... 共有ライブラリなので通常は実行されない
func main() {
    panic("THIS_SHOULD_NEVER_HAPPEN")
}

// env_load ... pathに存在する.envを読み込み環境変数にマッピング
func env_load(path string) {
    err := godotenv.Load(path)
    if err != nil {
        log.Fatalf("Error loading .env file in %v.n", path)
    }
}

// init ... 共有ライブラリ読み込み時に実行される
func init() {
    env_load("/etc/zabbix/aws.env") // AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYの値を参照
    g2z.RegisterStringItem("go.echo", "Hello World", Echo)
    g2z.RegisterStringItem("go.ec2_name2id", "error", Ec2Name2Id)
}

// Echo ... 引数の値を全て連結して返す
func Echo(req *g2z.AgentRequest) (string, error) {
    return strings.Join(req.Params, " "), nil
}

// Ec2Name2Id ... EC2インスタンスのタグ名からインスタンスIDを取得
func Ec2Name2Id(req *g2z.AgentRequest) (string, error) {
    if len(req.Params) != 1 {
        return "", errors.New("can use only 1 argument(s).")
    }

    sess, err := session.NewSession(&aws.Config{
        Credentials: credentials.NewEnvCredentials(),
    })
    if err != nil {
        return "error", err
    }

    svc := ec2.New(
        sess,
        aws.NewConfig().
            WithRegion("ap-northeast-1").
                WithLogLevel(
                    aws.LogDebugWithRequestRetries |
                    aws.LogDebugWithRequestErrors  |
                    aws.LogDebugWithHTTPBody,
                ),
    )

    params := &ec2.DescribeInstancesInput{
        Filters: []*ec2.Filter{
            &ec2.Filter{
                Name: aws.String("tag:Name"),
                Values: []*string{
                    aws.String(req.Params[0]),
                },
            },
        },
    }

    res, err2 := svc.DescribeInstances(params)
    if err2 != nil {
        return "error", err2
    }

    for _, r := range res.Reservations {
        for _, i := range r.Instances {
            return *i.InstanceId, nil
        }
    }
    return "empty", nil
}

ビルド環境

  • AWSのCodeBuildを使用してビルドしております。CircleCI?知らない子ですね…

    • Dockerイメージはgolang:1.9.2を使用してビルドしております。
buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - wget https://github.com/Masterminds/glide/releases/download/v0.13.1/glide-v0.13.1-linux-amd64.tar.gz
      - tar xvf glide-v0.13.1-linux-amd64.tar.gz
      - install -o root -g root -m 0755 linux-amd64/glide /usr/local/bin/glide
  pre_build:
    commands:
      - /usr/local/bin/glide install
  build:
    commands:
      - GOOS=linux GOARCH=amd64 go build -buildmode=c-shared -o mod_zabbix_go.so main.go

artifacts:
  files:
    - 'mod_zabbix_go.so'
  discard-paths: no

環境設定

  • Moduleを読み込むよう設定を記述し, Zabbix Agentを起動・再起動します。
/etc/zabbix/zabbix_agentd.conf
+ LoadModulePath=/var/lib/zabbixsrv/modules
+ LoadModule=mod_zabbix_go.so
systemctl restart zabbix-agent.service

動作確認

  • 実際に確認してみますと, リクエストを飛ばすところでハングっているようです…
$ zabbix_get -s localhost -k 'go.echo[hello, ntrv]'
hello ntrv # OK!!
$ zabbix_get -s localhost -k 'go.ec2_name2id[ntrv-test]'

zabbix_get [24960]: Timeout while executing operation # i-xxxxxxと返ってくることを期待していた...

失敗した原因について

  • マルチスレッドのgoランタイムでプロセスを安全にフォークすることは不可能

    • 一般的にシングルスレッドのプログラムがマルチスレッドとなる共有ライブラリをdlopen()で呼び出した段階でforkすることが出来ない。
    • https://github.com/golang/go/issues/15538
  • 共有ライブラリをロードしたプロセスがfork()を呼び出した後, 子プロセスでGo codeを使用できない。
    • エージェントがforkする際, Copy-on-WriteでメモリマッピングをコピーするがGoランタイムスレッドをコピーしてくれない。

      • 結果, g2zで記述した関数が呼び出されると, 子プロセスに存在しないスレッドを使用しようとしてデッドロックに陥る?
    • 詳しい方, 教えて頂けるとありがたいです…

References

Zabbix負荷問題を軽減する上で考えうる別の解決方法

  • 失敗してしまったので
  1. Zabbixをやめる
  2. EC2のCloudWatchメトリクスを取得する場合には, 外部スクリプトではなくUserParameterを使用する。
    • Zabbixサーバに負荷が集中するのを防ぐため。
    • RDS等ZabbixAgentが使用出来ない場合に外部スクリプトを使用する。
  3. Zabbix Senderを使用する。
    • 別途エージェントを用意してそこでメトリクスを収集し, ZabbixサーバのZabbix Trapperに投下する。
    • 弊社ですとHTTPステータスコードやアクセス数を, Webサーバ上のtd-agentからZabbix Trapperに送っております。

最後に

今回はZabbixを爆速化しようとして失敗してしまったことをまとめました。
GoでZabbix Sender専用のエージェントを用意して, エージェント上でAWS APIの結果を収集しZabbixサーバに送ってもよさそうですね。
時間があるときに試してみようかと思います。

また今回の経験を通して, Goのことというよりはマルチスレッドプログラミングが分かっていなかったということを痛感いたしました。Golangの文法が簡単だからと言ってなめておりました。
そのあたりの知識を身に着けなければなと考えております。

CYBIRDエンジニア Advent Calendar 2017の24日目は@koki_yamadaさんの”Unityのコード編集にVimを使ってみた”です!
私の冬休みの宿題はneobundle.vim/neocomplete.vimdein.vim/deoplete.nvimに置き換えることなので参考にしようかと思います。
どうぞお楽しみに!

続きを読む

Auroraの拡張性, 可用性について

RDS for MySQLからAuroraに移行した際に調査した拡張性, 可用性の面で優れている点をまとめました。

既存システムの課題

システムの構成はRDS for MySQL Master, Slave 複数台という構成だった。
RDSのスレーブへのコネクションをアプリケーション層で分散していたが, ヘルスチェックし障害が起きていないhealthyなslaveに接続するというチェックができていなかった。

=> 複数Slaveの構成にも関わらず死んでいるSlaveにも接続してしまう つらみ

この課題を解決することをきっかけにより可用性, 拡張性のあるDBの構成を考えるきっかけに。

最初はHAProxyを使用してヘルスチェック, ロードバランシングをしようとしていたがHAProxy自体の冗長化等のコストがあり他の実現方法を調査し, Auroraのリーダーエンドポイントで課題を解決できる
& 可用性, 拡張性の向上が見込めたAuroraへの移行を決めた。

Aurora

可用性, 拡張性にフォーカスして注目すべきところをまとめていきます。

image.png

MySQL/PostgreSQL 互換のリレーショナルデータベースエンジンでパフォーマンス, 可用性、信頼性がRDS for mysqlよりも高いAWSのマネージドデータベースサービス。

Amazon Aurora インスタンスを作成すると、DB クラスターが作成される。
DB クラスターは、1 つ以上のインスタンスと、これらのインスタンスのデータを管理する 1 つのクラスターボリュームで構成されWriter(Master)とReader(Slave)で立ち上がる。
Aurora クラスターボリュームは、複数のアベイラビリティーゾーンにまたがる仮想データベースストレージボリューム。各アベイラビリティーゾーンにはクラスターデータのコピーが格納される。
SSDベースのディスクで10GBから64TBまでダウンタイム無しで自動で拡張される。

インスタンス

プライマリインスタンス

読み取りと書き込みの操作をサポートし、クラスターボリュームに対するすべてのデータ変更を実行する。各 Aurora DB クラスターには 1 つのプライマリインスタンスがある。

Aurora レプリカ

読み取りのみをサポートする。各Aurora DB クラスターは、プライマリインスタンスに加えて最大15 台のレプリカを立ち上げれる。複数のAuroraレプリカはコネクションを分散し、別のアベイラビリティーゾーンにAuroraレプリカを立ち上げることで可用性を上げることができる。

プライマリインスタンスがフェイルオーバーした場合、Aurora レプリカが自動的にプライマリインスタンスに昇格される。尚どのレプリカを指定するかは各レプリカに優先度を設定することができ, 優先度が高いインスタンスからプライマリインスタンスに昇格される。

Auroraには プライマリインスタンス, Aurora レプリカそれぞれを指定するエンドポイントが用意されている。

エンドポイント

クラスターエンドポイント

プライマリインスタンスを指定するエンドポイント。
Read, Writeの両方を実行できる。
インスタンス毎に一意のエンドポイントがあるが, クラスターエンドポイントを利用するとプライマリインスタンスに障害が起きた場合に新しいプライマリインスタンスを参照するようになる。

読み込みエンドポイント

Aurora DB クラスターには読み込みエンドポイントがあり、これを使用して DB クラスターの Aurora レプリカの 1 つに接続できる。DB クラスターの読み込みエンドポイントは、DB クラスター内で使用できる Aurora レプリカ間で接続を負荷分散する。

Aurora DB クラスターで利用できる Aurora レプリカの 1 つに接続する、その DB クラスターのエンドポイント。

明示的にヘルスチェックしているとは言っていない(?)ので注意 :no_good:

インスタンスエンドポイント

プライマリインスタンス, Auroraレプリカのすべての特定のインスタンスに直接接続するためのエンドポイントが用意されている。

Auto Scaling

指定したメトリクスの変更に応じて Aurora レプリカを自動的に追加または削除できるようになった。
CPU 平均使用率や平均アクティブ接続数などの Aurora レプリカの定義済みメトリクスに、必要な値を指定できる。
そのため無駄なコストがかからないようにスケールインすることもできる。

Zero Downtime Patching

私達の、新しいゼロダウンタイムパッチ機能により、Auroraインスタンスへのパッチ適用をダウンタイム無しで、可用性にも影響を及ぼさずオンラインで実行出来るようになりました。この機能は、現在の最新バージョン(1.10)が適用されたAuroraインスタンスで、ベストエフォートで機能します。シングルノードクラスタとマルチノードクラスタのWriterインスタンス双方で機能しますが、バイナリログが有効になっている場合は無効になります。

Multi-Master

つい先日のReinventで発表されたMulti-Master。
クラスタを構成するすべてのノードに対して読み書きが可能になる。

監視項目

Auroraで取れるメトリクス,結構RDSと比較すると監視項目細かく設定できそう。

Mackerelで以下のメトリクスでAuroraの監視している。

Mackerelで監視する項目

  • Queries 1秒あたりに実行されたクエリの平均回数
  • SelectThroughput (per second) 1秒あたりのSELECTの平均回数
  • DMLThroughput (per second) 1秒あたりのINSERT,UPDATE,DELETEの平均回数
  • SelectLatency SELECTクエリのレイテンシー(ミリ秒)
  • DMLLatency INSERT,UPDATE,DELETEのレイテンシー(ミリ秒)
  • Buffer cache hit ratio バッファキャッシュ(バッファプール)のヒット率
  • Deadlocks デッドロック数
  • Blocked Transactions ブロックされているトランザクション数

Migrate back to MySQL

ないとは思うがAuroraに移行し問題がありRDS for MySQLに戻さなければ行けない場合の手順。

https://stackoverflow.com/questions/32794809/is-it-possible-to-migrate-back-from-amazon-aurora-to-native-mysql-in-amazon-rds

Amazon’s Aurora is MySQL wire compatible so you can always use tools such as mysqldump to get your data back out into a form that you could use to import back into a regular MySQL instance running in RDS, an EC2 instance or anywhere else for that matter.

Since posting this answer Amazon has also released the Database Migration Service which can be used to do zero downtime migrations between MySQL -> Aurora MySQL (Aurora also now supports PostgreSQL) and back. It also supports heterogeneous migrations such as from Oracle to Aurora MySQL or a number of other sources and targets.

普通にmysqldump を使ってRDSにデータを移行する。
または, Database Migration Serviceを使用するしかないようだ。

まとめ

Auroraに移行したことで可用性が確実に上がったしパフォーマンス的にネックとなる部分も今は出てきていないので移行は成功だったのではないかと思う。
そしてこれからもAuroraの拡張性, 可用性の部分の改善となるリリースが行われるのではないか。
内部がきになる方はこの記事がとてもわかりやすかったので参考にしていただければ => https://qiita.com/kumagi/items/67f9ac0fb4e6f70c056d

続きを読む

ビットバンクの主軸事業【仮想通貨取引所 bitbank】

同社のサービスのインフラ部分に携わっていただきます。 ・AWSを用いたサーバレスアーキテクチャ ・Dockerによる仮想化とDevOps ・Mackerelと連携した監視 ・ブロックチェーンとの連携による仮想通貨管理. 雇用形態. 正社員(中途). 配属部署. 開発部. 応募資格. 【必須要件】 ・AWSを用いた開発経験・コミュニケーション … 続きを読む

中途入社のAWSエンジニアが、稼働中サービスの運用状況をキャッチアップするために意識すること

Classiアドベントカレンダー11日目です。
今回は、AWSエンジニアが稼働中のAWSの管理アカウントを渡されて、ビクビクしながらキャッチアップを行っていったときのメモになります。

1.TL;DR

AWSアカウントのログイン前に準備できることもあるし、AWSアカウントにログインしてわかることもあるし、サーバーにログインしてわかることもある。それぞれのレイヤーでどういったことを確認するかを意識しながらキャッチアップを進めていきましょう。

2.AWSアカウントログイン前の事前準備

pre_aws.png

サービスが稼働しているのであれば、AWSアカウントにログインせずとも、たくさんの情報をキャッチアップすることができます。1日目から何らかの大きなアウトプットを出さないと解雇するような会社は、(おそらく)存在しない筈です。まずは落ち着きましょう^^;

2-1.ドキュメント読み込み

サービスのインフラにAWSが使われることが多くなったからといって、入社前に経験したAWS運用フローがそのまま活かせる訳ではありません。まずは、前任者や運用中のドキュメント管理ツールの中から、今までどのような運用を行っていたかを確認します。
ドキュメントを見たときに意識する観点としては、

  • フロー型:時間による鮮度の劣化があるドキュメント
  • ストック型:システム仕様など、メンテナンスが求められるドキュメント

どちらの情報であるかを意識して読むことが重要です。
フロー型の情報は、障害などで一時的な対応用にメモっていることもあり、運用の中で解決済みのことがあります。そのため、ストック型のドキュメントを中心に見ることが素早いキャッチアップになると思います。
とはいえ、ドキュメントの全てがメンテナンスされている会社というのは稀だと思いますので、各種ドキュメントを見ながら、仮説程度に自分なりのシステム構成図などを書いてみましょう。
要件定義書や各種構成図の変更履歴、課題管理表、リスクコントロール表といったドキュメント類があるのであれば、目を通しておきましょう。

2-2.運用フローを観察する

サービス側のドキュメントについては、まだ文書化されてることが多いですが、運用系ツールに関しては、ドキュメント化されていないことがあります。今の開発スタイルであれば、何らかのチャットツール(Slack,ChatWork,HipChat)上で、

  • デプロイ
  • 各種の通知
  • 運用Bot

の運用といったことが行われていると思います。また、チャットだけでなく、メールでの運用フローも存在しているかもしれません。
こうした運用系ツールの存在は、今後自分がリファクタするときに、「必須要件ではないが、重宝している」ということで、「リファクタ後にも、あの機能を実装して欲しい」といった声が社内から上がると思います。
そのため、このような運用フローがどこで実装されているかを見極めることが重要になってきます。

2-3.インフラ部分のコード読み

「俺はフルスタックエンジニアだ!」という強い意思がある方は、この時点で稼働中のアプリ側のコードまで読み込んでいただければよいですが、まずは入社前に期待されたであろう、インフラまわりのコード化部分を把握しておきましょう。どのみち、いずれはメンテナンスを任されたり、質問されることが増えてきますので、自分のメンテナンスする部分を優先的に確認しておきましょう。
実サーバーの運用はAWSに任せているので、ここで意識しておくことは、

  • Infrastructure Orchestration Tools:Terraform, CloudFormationなど
  • Server Configuration Tools:Chef,Ansible,Itamaeなど

あたりのコードがgithubなどに保存されているからといって、メンテナンスされていない可能性もあります。
コードの設計方針などを確認するのは当然必要なのですが、コードの変更履歴が年単位で放置されていないかどうかも見ておきましょう。特に、AWS関連のコードについては、担当する人がアプリ側よりも少ないので、構築当初のコードのままなのか、運用されているコードなのかはPRなどで確認しておいた方がよいです。

3.AWSのアカウント内を調査する

aws_kansatsu.png

実際にAWSアカウントにログインしたり、APIで各種設定を確認していきます。Web系サービスであれば、TCP/IPモデルやC/Sモデルを意識しながら、下層レイヤー回りから調査していき、ネットワークがどうせ設定されているかを確認していきます。
おそらく、ここで多くの疑問(場合によっては、絶望)が生まれる段階です。「あれ?ドキュメントにこう記述されているけど、設定上は違うような…」という沼にハマることがあるでしょう。負けないでください、一人で抱え込まずに闇を共有できる仲間を見つけましょう。

3-1.外部システム連携の確認

関連するAWSサービス

VPC関連のサービスを中心に、自AWSアカウント以外の連携がないかの確認を行います。

関連しやすいAWSサービス例)

  • DirectConnect
  • NAT Gateway
  • Peering Connection
  • Customer Gateways
  • Virtual Private Gateways
  • VPN Connections
  • NetWorkACL
  • SecurityGroup
  • EIP

などに、何らかのインスタンスが稼働していて、productionやhonbanなどの文言がついたものがあれば、それはドキュメント上には存在しないが、サービス上何らかの理由で稼働しているものである可能性があります。
自社のサービスがAWSアカウント内だけで完結しているのであればよいのですが、誤ってここのインスタンスなどを削除すると、場合によってはシステム復旧できないぐらいの痛手になるので、慎重に確認していきましょう。
特に、SecurityGroupは、最近でこそInboundルールにDescriptionをつけられるようになりましたが、数年運用されているシステムには、何で利用しているIPアドレスなのかがわからないことがあるので、設定確認中に不明なIPアドレスを見つけたら社内で有識者に聞いてみましょう。

3-2.システム導線の確認

関連するAWSサービス

インスタンス障害があるとユーザー影響がありそうな、システム導線を追っていきます。

関連しやすいAWSサービス例)

  • ELB(CLB,ALB,NLB)
  • CloudFront
  • EC2
  • ElasticCache(redis,memcached)
  • RDS(Aurora,MySQL,PostgreSQL,SQLServer)
  • ElasticSearch
  • DynamoDB
  • S3

各種のインスタンスサイズが適切かを確認するのはもちろんですが、DB関連についてはバックアップ関連の設定がちゃんと行われているかどうかも確認しておきましょう。バックアップウィンドウの世代数やメンテナンスウィンドウの時間が営業時間内になっているとかは、結構ありがちな設定漏れケースになります。パラメータストアの設定については、本番で稼働している設定が正義なので、設計と違う場合は、社内で経緯を追ってみましょう。

3-3.運用導線の確認

関連するAWSサービス

直接のユーザー影響はないものの、バッチ系およびログインやログ連携など、システム運用で必要な運用導線を追っていきます。

関連しやすいAWSサービス例)

  • EC2
  • Lambda
  • ElasticSearch(& kibana)
  • IAM
  • CloudTrail
  • AWS Config
  • CloudWatch Logs
  • S3
  • Glacier

24224というポート開放を見れば、そのシステムはfluentd関連のフローがあるのはほぼ確定なので、ログの発生から可視化ツールおよびバックアップのフローまで追っていきましょう。また、バッチ系のEC2に関しては、最近のAWSだと、FargateやECS、Lambdaなどで定期バッチを行うことも可能なので、単一障害点をなくすことができないか、今後の計画のために、バッチ系が整理されているドキュメントなどを探してみましょう。

4.サーバー内の設定を確認する

server_chosa.png

最近だと、Server Configuration Toolsが大分普及していたり、コンテナ系の運用が発達してきているので、このあたりのキャッチアップ期間が少なくなるのかなと思います。とはいえ、SSH接続を頻繁に行うサーバーや起動時間が長いサーバーだと、コードの設定と異なる部分が出てきていることがあるかもしれません。
OSの設定やミドルウェアのバージョンなど、SSH接続すると確認した方がよいところは多々ありますが、Server Configuration Toolsの設定と異なっていたり、運用中のアラート設定などで差異がでやすそうな部分を以下に記載します。

4-1.各種メトリクス確認

メモリやプロセスの状況は、通常CloudWatchだけではわからないので、MackerelやZABBIXなどの監視ツールエージェントを入れているのであれば、各サーバーのメトリクスを確認しておきましょう。

4-2.稼働プロセスの確認

pstreeなどで、稼働しているプロセスを確認します。SSH接続が禁止されているのであれば、AWSのSSMエージェントなりで確認できないかを検討してみましょう。設計上のソフトウェアスタックに存在しないプロセスが常駐している場合は、何のエージェントが動いているかを追っておきましょう。

4-3.不要なファイルが出力されていないかの確認

ログレベルがデバッグのままだったり、ログファイルのローテートがなされていない場合があり、アラートは上がっていないけど、サーバー内のリソースを侵食しているときがあります。また、生成されるログファイルが小さすぎると、ディスクに余裕がありそうに見えても、inodeが先に枯渇するときもあります。lsofdf -iなどを可視化するなどして、サーバー内のディスク状況を確認しておきましょう。

4-4.同期処理と非同期処理のプロセス確認

同期処理のプロセスは意識しやすいので、監視対象に入っている可能性が高いです。ただ、非同期系プロセス(Rubyだとsidekiq,Pythonだとcelery,PHPだとphp-resqueなど)が監視対象に入っていないこともあるので、どのサーバーで非同期処理が行われているかを把握しておきましょう。

5.まとめ

AWSや他のパブリッククラウドが全盛になった今でも、3層アーキテクチャのシステム構成やOSI7階層などのレイヤーを意識しながらキャッチアップを行うと、システムを俯瞰しながらキャッチアップを進めることができるのではないかなと思います。とはいえ、前任者がコード化しきれなかった部分もある筈なので、そこは社内で過去経緯を知っている人に笑顔で質問をしてみましょう。技術が発達しても、人に蓄積されるノウハウはまだまだ多いので…
AWSエンジニアが転職する際などのご参考になれば。

続きを読む

システム障害解析におけるログのあれこれ

この記事は Akatsuki Advent Calendar 2017 の 8 日目の記事です。
7日目: バイナリのビルド作業はそろそろボタンをポチるだけにしようぜ

背景

システムを運用していると、日々アプリケーション・ミドルウェア・インフラのログが蓄積されていきます。これらのログはシステムの障害対応・解析のための貴重な情報源となりますし、そうであることが期待されます。
しかし、これらのログの取り扱いを誤ると誤った障害解析結果を導き出してしまったり、解析にいたずらに時間がかかったり、障害を特定することができなかったりといったことが起こります。
今回はこれらのログを扱う上で注意すべき点とその改善案を紹介をしたいと思います。

前提

私はソーシャルゲームのインフラとサーバサイドアプリケーションを担当しており、下記のサービス・ソフトウェアを利用しています。

  • AWS

    • ELB (Classic)
    • EC2 (AmazonLinux)
    • RDS (MySQL)
    • CloudWatch
  • nginx
  • Ruby on Rails (unicorn)
  • 他 BigQuery, ElasticSearch, Re:dash, Kibana, Mackerel 等

そのタイムスタンプ、いつのもの?

通常、ログデータにはタイムスタンプが付けられていますが、このタイムスタンプは一体「いつ」の時刻を記録したものなのでしょうか。

ほとんどの場合、対象ソフトウェアが処理を開始した時間が記録されるのですが、実は例外もあります。
私の所属しているプロジェクトで使っているソフトウェアの中では nginx がこれに該当します。
nginx では「処理が完了した時刻 (= レスポンスを返した時刻)」が記録されます。

システムが正常に稼働している限りこれらの違いを気にすることは少ないと思いますが、障害解析時はその限りではありません。
各アプリケーション・ミドルウェア・インフラのログを少なくとも秒単位であわせ解析する必要があるため、各タイムスタンプが「いつ」の時刻を記録したものなのか把握していないと、誤った障害解析結果を導きかねません。
特にタイムアウト処理が絡んだ場合、レスポンスを返した時刻はリクエストを受けた時刻と大きな差が発生します。

何気なく記録されているログのタイムスタンプにも罠があります。ご注意ください。

必要な情報出してる?

前項で「nginx のタイムスタンプはレスポンスを返した時刻」と説明しましたが、ではいったいどうやって「処理を開始した時刻(= リクエストを受けた時刻)」を出力するのでしょうか。
実は nginx のデフォルトの設定ではこれができません。

nginx で「リクエストを受けた時刻」を記録する方法はいくつかあるようなのですが、最も簡単なのは「レスポンスを返すまでにかかった時間」を一緒に記録することです。ログの解析時にそれらの値を使って「リクエストを受けた時刻」を求めることができます。ログ解析時に前処理は必要になりますが、それを低コストで行える環境もあわせて用意しておくとよいです(後述)

(※ 最も良いのはもちろん予めログにリクエストを受けた時刻を記録することですが、ログ収集時に計算させる方法も可能です)

死ぬ前の情報は残した?

エラー時の情報は貴重です。この情報の有無で障害解析のスピードと精度は数倍変わってくるでしょう。しかし、中にはエラー時の情報を残さずに死んでしまうソフトウェアもあります。私のプロジェクトで利用しているもの中では unicorn がこれに該当します。

unicorn はリクエストを処理する worker プロセスと、workerプロセスを管理する masater プロセスから構成されます。
unicorn はタイムアウトの設定を持ち、worker プロセスの処理がこのタイムアウト内に完了しない場合、master プロセスは workerプロセスに対して即座に SIGKILL を送りつけます。その結果、「タイムアウト内に完了しなかった処理」がログに記録されないという事態が発生します。

これに対する改善策はいくつかあります。

  1. より上位にあるソフトウェアで記録を残す

    • 具体的には ELB や nginx でログを残す。当該リクエストを処理したホストの情報、エラーコード、エンドポイント等を記録する。
  2. SIGKILL の代わりにトラップ可能な SIGINT 等を利用し、そこで Rails.logger.flush させる
  3. Rails の ActionController の around_action で “ソフトな” タイムアウトを設定する
around_action :global_timeout

def global_timeout
  Timeout.timeout(TIMEOUT_SEC) do
    yield
  end
end

私の所属するプロジェクトで実際に適用されているのはまだ1のみですが、2,3の手法も評価していく予定です。

ログデータ膨大すぎるんだけど…

正確な障害解析には普段から多くの情報を取得しておく必要がありますが、その結果、解析に時間がかかったり、そもそも普通のマシンでは処理ができなかったりといったことが発生します。
私の所属するプロジェクトでは、ログをBigQueryとElasticSearchに格納し、Re:dashやKibanaで可視化できる仕組みを構築しています。

普段はマクロなインフラメトリクス(や、売上情報等)を表示するために使っていますが、障害解析時はクエリを書くことで簡単に情報を絞り込んだり、可視化することができ、便利です。nginxのタイムスタンプ問題もクエリを書くことで簡単に解決できます。

(※ すべてBigQuery+Re:dash に統一化したいなぁ)

さいごに

障害解析は「より少ない情報、より少ない時間で原因を特定する」エクストリームスポーツではありませんし、そうあってはなりません。
エンジニアにエスパーの力を求めるのは間違っています。
また、「システムの癖を知った、長年の経験のあるエンジニアにしかできない作業」であってもなりません。

障害解析のために十分な情報を集めることや、スピーディに解析できる環境を用意することは言うほど簡単ではありませんし、コストもかかりますが、安定したサービスを提供するには必要不可欠なものです。

堅牢なシステムの構築は1日にして成らず、頑張っていきましょう。

続きを読む