トレタ開発者ブログ

飲食店向け予約/顧客台帳サービス「トレタ」、モバイルオーダー「トレタO/X」などを運営するトレタの開発メンバーによるブログです。

Rubyを2.0から2.3にバージョンアップした効果とか

インフラをチョメチョメしている佐野です。今日はRubyを現最新バージョンの2.3.1にアップデートしたのでその効果について書きます(2.0、とっくにEOLですしね...)。gemのバージョンアップはserizawaニキがやってくれました。結論から言いますと、

  • CPU使用率が劇的に下がり、メモリ使用率が少し上がった。
  • サーバ台数削減できる。

です。

CPU

f:id:hiroakis:20160907163559p:plain

9/6の昼過ぎくらいに2.3に切り替えたのですがそれ以降、CPUが下がっていることがわかります。

メモリ

メモリについては使用率が上がっています。

  • 2.3

f:id:hiroakis:20160907163610p:plain

  • 2.0

f:id:hiroakis:20160907163625p:plain

何が使っているのかというと、Ruby2.3なプロセスのメモリ使用量が全体的に増えました。次のtopコマンドは左ペインが2.3、右ペインが2.0なのですが、rubyないしbundleとなっているものがunicorn, sidekiqになります。これら全般的に2.3の方がメモリ使用量が多いです。 ちょっと気にしていたら、TLにてhttps://github.com/ko1/nakayoshi_forkなるものがあると教えていただいたのですが、まだ試していません。

f:id:hiroakis:20160907163546p:plain

性能

簡易的に測定しました。ヘルスチェックパス(DBアクセスあり)に10000発のHTTP GETを投げてみた際の処理時間です(3回ほど試行)。2.3選手の方が3回ともかなり早い結果となりました。

  • 2.3
counts: 10000 total time: 120.01s
counts: 10000 total time: 128.66s
counts: 10000 total time: 120.59s
  • 2.0
counts: 10000 total time: 207.34s
counts: 10000 total time: 199.82s
counts: 10000 total time: 230.72s

なのでバージョンageていったらいいと思います。簡単ですが以上です。

おわり

Excelなテスト仕様書をMarkdown/GitHub/CircleCIに移行した話

こんにちは、QAエンジニアの井上恵一です。好きな飲み物は一番搾りと韃靼そば茶です。

初回からニッチなネタではありますが、昨年入社した直後に行った、 iPad アプリのテスト仕様書の管理方法を見直したときの話を紹介しようと思います。

見直しのきっかけ

トレタは飲食店向けの予約/顧客台帳アプリです。だれでもかんたんに使いこなせるシンプルさを追求してはいますが、製品の進化に伴ってそのテストケース数はすでに数千という単位にまで膨れあがっています。

製品の品質を安定させるためには、テストの内容自体をブラッシュアップすることが重要なのは言うまでもありません。ただ、安定した製品を永続的に提供していくためには、それに加えて、膨大なテストケースを効率よくメンテナンスし続けるためのプロセス作りも欠かせません。

入社のタイミングでトレタのテスト設計を担当することになったので、テストケースの管理方法についてもいちから見直すことにしました。

当時の問題点

当時、トレタのテスト仕様書は Excel で管理されていました。 Excel は閲覧性が高くテスト仕様書の管理ツールとしても一般的ですが、テストケース管理という意味では不便を感じることがあります。たとえば、こんなところです。

  • そもそも手元に Office が無いとテストケースの閲覧・メンテナンスができない
  • バイナリファイルなので git などでバージョン管理しにくい
  • 複数人で共同編集しにくい
  • テストケースのレビューがしにくい
  • テストケースの変更履歴や変更の経緯を残しにくい

今後テストケース数も関わる人も増えていく予定だったので、メンテナンスしやすく継続しやすい管理方法を検討することにしました。

Excel から Markdown へ

もろもろ検討した結果、Excel ではなく Markdown (GFM) 形式で記述して、プロダクトのコードと同じように GitHub 上で管理してみることにしました。そうすることで、

  • テキストエディタでどこでも気軽に編集できる
  • テキストファイルなので GitHub でバージョン管理・変更管理がしやすい
  • 複数人で同じファイルを編集しても git がよしなにマージしてくれる
  • Pull Request を使ってテストケースのレビューを行える
  • プロダクトの Issue/PR とテストケース変更の Issue/PR を紐付けておくことで、テストケース変更の経緯を後から git blame で追いかけることができる

といった効果が狙えます。記述ルールは、GitHub のプレビュー上でもそれっぽく見えるように下記のようにしてみました。

記述ルール

  • 大項目(画面名) : h2
  • 中項目(機能名) : h3
  • テスト内容: li
  • 確認内容 : checkbox

書き方の例

## ログイン画面

### ログイン機能
- 正しいメールアドレスとパスワードを入力してログインボタンをタップする
  - [ ] ホーム画面に遷移する

GitHub での表示

f:id:dreamagicjp:20160705014751p:plain

テスト実行時は Spreadsheet で

テストケースを管理する際は Markdown の方が扱いやすいですが、いざテストを実行する時は Excel 的な形式の方が一覧して見やすく、テスト時に気付いたことをメモとして残したりもできて、何かと便利なことがあります。そこで、Markdown 形式のテストケースを Google Spreadsheet に変換するための仕組みも準備しました。

具体的には、テストケースを GitHub に push したときに CircleCI で構文をチェックしつつ OK だったら、 google_drive gem で Google Spreadsheet に展開するようにしています。こんな流れです。

デプロイの流れ

f:id:dreamagicjp:20160705021057p:plain

Spreadsheet 上の表示

f:id:dreamagicjp:20160705143345p:plain

たかがテストケース管理だけのためには少々大げさかもしれませんが、これによってひとつのテストケースを Markdown 形式でも Spreadsheet 形式でも参照できるようになり、テストの編集時と実行時とで形式を使い分けることができるようになりました。

さいごに

今回は、テストケース管理について紹介しました。今後また、テストプロセス、テスト自動化への取り組み、CIまわりの取り組みなどこの場でお話できればと思っています。

そしてお約束。トレタは iPad アプリを Swift に移行しつつ、Testability の高い設計・コードに書き換えている真っ只中にあります。iOS エンジニア絶賛募集していますので、ご興味があれば一度オフィスに遊びにきてみてください。

EngineyardからAWSに移設してAuroraの運用を開始した

どうも佐野です。トレタのインフラはEngineyardワオワオやってたんですが、あの、なんていうのAurora?それを使いたかったわけです。 さて、私が書いた前々回の記事にて、「コア機能のAWS化」を今後のTODOとして挙げていましたが、5/9にEngineyardからAWSへの移設が完了していました。EngineyardはRailsやnodejsなどのWEB-DB環境を簡単に構築できるPaaSです。Herokuとの違いはサーバにsshしたり、chefを利用してFluentdなどのミドルウェアを入れたり、既存のコンフィグレーションをカスタマイズしたりすることができる点が挙げられます。比較的自由度の高いPaaSと言えるでしょう。トレタでは創業〜先月までお世話になりました。 今回は移設とAuroraの運用に関するTipsの紹介になります。なお、本記事に示す設計・運用方針はAWSのソリューションアーキテクトの支援を得て決定したものではなく、私の見解で決定したものなのでご了承ください。ベストプラクティスではないかもしれません。

以下、目次になります。

  1. 移設
  2. Auroraのコンフィグレーション
  3. 基本、マスターのみを使う
  4. スロークエリの検出
  5. フェイルオーバするとき
  6. スケールアップするとき
  7. Auroraのメンテナンスをするとき
  8. リストアするとき
  9. MySQL on EC2からレプリケーションを行う場合
  10. 失敗したこと

1. 移設

運用エンジニアを長らくやっていると移設は慣れっこなのですが、弊社エンジニアに移設経験者が私しかいませんでした。MTGで「なるほどー」という空気になったので書いてみます。システムの移設をやったことがない、これからやる、という方がいらっしゃいましたら参考にしてみてください。 移設は往々にしてデータをどのようにして新環境に移すか?というのが技術的な課題になります。トレタの場合、MySQL, Redisといったレプリケーション可能なよく知られたデータストアを使っていたので、技術的な難しさはほとんどなく、どちらかというと社外を含む関係各所へのメンテナンスの日程の調整の方が骨が折れました。このあたりはセールスチームなどの協力を得て今回はスムースに調整を進めることができました。 技術的な移設手順は下記の通り。

1.1. これを

Engineyardで稼働している状態です。AWSに新環境を作っておきます。

f:id:hiroakis:20160616113808p:plain

1.2.こうして

データストアは新環境からレプリケーションを張っておきます。Engineyardはsshポートがグローバルに開放されているので、sshトンネルを張ってトンネル経由でレプリケーションを行いました(Engineyardのサポートに連絡すれば3306ポートをIP制限掛けてグローバルに開放してくれたかもしれない)。またsshプロセスはmonitで監視し、もし落ちた際は自動再起動するようにしておきます。Redisについても同様、sshトンネル経由で6379ポートに接続してデータの同期を行います。 Auroraから外部のMySQLにレプリケーションを行う場合(Auroraがスレーブ、MySQLがマスタ)は、 call mysql.rds_set_external_master のようなストアドで行います。このあたりはRDSのマニュアルを参照してください。で、今回はEngineyardのMySQLにsshトンネル経由でレプリケーションを行う必要があるため、AWS上に踏み台のMySQLを用意し、カスケード接続でAuroraにデータを同期させます。図の通り、Engineyard MySQL <- (sshトンネル) <- EC2 MySQL <-(ストアド利用) <- Auroraというレプリケーションチェーンになります。

f:id:hiroakis:20160616113827p:plain

1.3. こうやって

これはメンテナンス時間中に行います。まずシステムをメンテナンス状態にします。そしてデータストアのレプリケーション遅延がゼロになっていることを確認して、ウェブアプリケーションのデータストアの接続先が新環境に向くようにします。終わったらメンテナンスを解除します。トレタではメンテナンス時間は1時間設けました(実作業時間は確認を含めて30分程度でした)。 蛇足ですが、Auroraなどのデータストアはパブリックアクセス可能な状態にし、旧環境であるEngineyardのAppサーバからのアクセスを許可しておく必要があります。

f:id:hiroakis:20160616113848p:plain

1.4. こう

あとは日中帯に落ち着いて新環境にデプロイを行い、DNSを新環境に向けて終わりです。

f:id:hiroakis:20160616113909p:plain

2. Auroraのコンフィグレーション

長らくMySQL運用おじさんをやっていた身としてはやはりコンフィグが気になります。私が気にした箇所についていくつか抜粋します。総括すると、大抵のものはデフォルトで良さそうな印象を受けました。

クラスタパラメータグループ

* 文字コード
character_set_client = utf8
character_set_server = utf8
character_set_connection = utf8
character_set_database = utf8
character_set_results  = utf8
skip-character-set-client-handshake = 1
* バイナリログ
binlog_format = MIXED
log_slave_updates = 1(デフォルト)
sync_bin_log = 1(デフォルト)
* InnoDB
innodb_commit_concurrency = 0(デフォルト)
innodb_purge_threads = 1(デフォルト)
innodb_file_per_table = 1(デフォルト)
innodb_flush_log_at_trx_commit = 1(デフォルト)
innodb_support_xa = ON(デフォルト)

文字コード周りとバイナリログの有効化を設定してあります。移設の段階でカスケード接続させるのでlog_slave_updatesは1にします。sync_bin_logは1で良いでしょう。またバイナリログの保持期間を設定する expire_logs_days は無く、 call mysql.rds_set_configuration('binlog retention hours', 24); などとしてストアドでバイナリログの保持期間を設定する必要があります。InnoDB関連でいくつか気になるものがありますが、デフォルトで納得できる値になっていました。

DBパラメータグループ

* 接続周り
max_connections = 自動計算(デフォルト)
thread_cache_size = 自動計算(デフォルト)
max_allowed_packet = 134217728(128M)
* スローログ
slow_query_log = 1
long_query_time = 2
log_queries_not_using_indexes = 1
log_output = TABLE(デフォルト)
* 各種バッファ
tmp_table_size = 67108864(64M)
max_heap_table_size = 67108864(64M)
sort_buffer_size = 8388608(8M)
join_buffer_size = 131072(128K)
innodb_sort_buffer_size = 1M(デフォルト)
innodb_log_buffer_size = 8M(デフォルト)
* InnoDB
innodb_buffer_pool_size = 自動計算(デフォルト)
innodb_flush_method = O_DIRECT(デフォルト)
innodb_buffer_pool_dump_at_shutdown = 1(デフォルト)
innodb_buffer_pool_load_at_startup = 1(デフォルト)
* 分離レベル
tx_isolation = REPEATABLE-READ(デフォルト)
* クエリキャッシュ
query_cache_size = 自動計算(デフォルト)
query_cache_type = 1(デフォルト)

接続周りの設定、スローログ、各種バッファ、InnoDB関連、トランザクション分離レベル、クエリキャッシュあたりをケアしました。

  • 接続周り

thread_cache_size、max_connectionsが自動計算されるようになっていて、計算後の値も適切だったのでAuroraの自動計算に任せました。max_allowed_packetは自分のMySQLの秘伝のタレの値をそのまま転用。

  • スローログ

スローログについては閾値を2秒とします。RDSの場合、log_outputはTABLEとなり、これはmysql.slow_logにログが蓄積されることを意味します。

  • 各種バッファ

バッファの数値はちょいちょいいじりました。とはいえこれらの数値の根拠はなくて、私の経験的にデフォルトではちょっと小さいのではないか?と思ってこのような数値にしてあります。

  • InnoDB

クラスタパラメータグループだけでなくDBパラメータグループにもInnoDB周りの設定があります。性能面において最も重要な設定の一つであるinnodb_buffer_pool_sizeはこちらにあり、これもAuroraによって自動計算されるようになっています。innodb_flush_methodもO_DIRECTになっており、これらは適切な値だったのでとくにいじりませんでした。

  • トランザクション分離レベル

確認したところ、tx_isolation = REPEATABLE-READがデフォルトで設定されていたので特に変更せず。

  • クエリキャッシュ

デフォルトで有効になっており、キャッシュサイズは自動計算されていました。実はこれが個人的にちょっと悩ましくて、私の経験上、過去にクエリキャッシュが効果を発揮したことはあまりなかったです(根拠のあるデータを出すことができずすみませんが...)。インデックスが効いていれば十分高速ですし。無効にしたいところだが、Auroraの推奨?と判断して特に変更せずこのままとしました。

3. 基本、マスターのみを使う

現状のトレタのトラフィックでは1DBで十分です。1DBでの運用を行います。(スレーブは深夜のバッチ処理で使うようにしてありますが)基本的にスレーブは昇格用のスタンバイです。

4. スロークエリの検出

上の方に書いた通り log_output = TABLE のためスロークエリは mysql.slow_log テーブルに出力されるようになります。監視用に立てたインスタンスから次のようなクエリを定期的に投げて、スロークエリを検出しています。

select * from mysql.slow_log where start_time > '%s' order by start_time

トレタでは次の様にしてSQL警察がslackに通知するようにしています。

f:id:hiroakis:20160614013936p:plain

5. フェイルオーバするとき

フェイルオーバーボタンをポチります。数十秒〜1分程度です。

6. スケールアップするとき

インスタンスサイズの大きいreader*1を優先度tier-0(優先度-0)*2で作成し、フェイルオーバーを行います。

7. Auroraのメンテナンスをするとき

Auroraも他のRDSがサポートしているエンジン同様、Aurora自体のメンテナンス(OSアップグレード、バージョンアップetc)が必要なケースがあります。トレタではAuroraのメンテナンスはフェイルオーバーで行う方針です。つまり先にスレーブをupgradeしてそれをマスタに昇格させます。このリンクのようにAuroraのメンテナンス時はフェイルオーバーじゃなくて再起動の方が早い、つまり無下に「upgrade now」を実行してもよいと言及されている場合もありますが、私が実験した結果では、upgrade nowの停止時間は短い時は短いが遅長い時もある、フェイルオーバは安定して1分程度の停止時間、という結果になったので停止時間が安定している方を採択する方針です。upgrade nowの停止時間はAuroraのメンテナンスの内容、インスタンスサイズ、実施時の負荷などに依存するのかもしれません。

  • db.r3.largeをupgrade now: 16秒停止
  • db.r3.largeをフェイルオーバ: 60秒停止
  • db.r3.xlargeをupgrade now: 1分59秒停止
  • db.r3.xlargeをフェイルオーバ: 55秒停止

なお、ここでいう停止時間とは、インターネット経由でシステムのエンドポイントを叩き、オフラインになった時間を計測しています。なのでAurora自体の停止時間に加えて、ヘルスチェックなどで切り離されてしまった時間から復活する時間も含まれています。

8. リストアするとき

任意の時刻でのpoint-in-timeリカバリが可能です。もし時刻ではなく、たとえばオペミスでdrop tableしちゃってdrop tableの直前まで戻したい場合などは、バイナリログを活用することになるでしょう。

9. MySQL on EC2からレプリケーションを行う場合

AuroraをマスタとしてEC2など外部のMySQLをスレーブにするパターンです。移設のときと逆ですね。こちらについてはいつもどおりAuroraにレプリ用のユーザを作成して 外部のMySQLから change master すればよいです。

10. 失敗したこと

リザーブドインスタンスにし忘れた...:(;゙゚'ω゚'): うーむ...。RDSってあとからリザーブドにできなかったよね...??? (追記)各所よりあとからリザーブにできると教えていただきました

おわり

*1:readerというのはいわゆるスレーブ。Aurora用語かな?マスタはwriterと呼ぶ。

*2:昇格の優先度です。後ろの数字が若いものが優先的に昇格されます。

© Toreta, Inc.

Powered by Hatena Blog