BtoB SaaSスタートアップのインフラの失敗と選択の歴史を登壇の中で暴露してきました

f:id:kaminashi-developer:20210328194733j:plain

初めまして。株式会社カミナシPMの@gtongy1です。

先日行われた BtoB Startup Engineers Meetup 〜BtoB SaaSを支えるインフラ〜 - connpass にて「失敗しても前に倒れる。高速検証のための壊しやすいインフラ」というタイトルで登壇してきました。

登壇資料

登壇内容

スタートアップで事業を成長させていく過程では失敗も数多くあり、その中でも前に倒れてインフラを組み立てていく必要があります。
その様子はまさに飛行機を飛び降りながらインフラを組み立てていく感覚と近く、増えていくユーザーに迷惑かけずに形を作っていくのかがとても重要です。
その中で「壊しやすさ」は一つの目安であり、こんなインフラを作っていくのか。
これが一つ堅牢なインフラ構築の鍵なんじゃないか?と考えています。
そこで、トラブルと解決事例を交えながら壊しやすいインフラを如何に作ってきたのか、発表させていただきました。

登壇の中でお話ししきれなかった部分を掻い摘んでご紹介出来ればと思っています。

Deployの整理とコンテナ化の実施

f:id:kaminashi-developer:20210328124706j:plain

移行への舵切りはミドルウェアとかのバージョンなど色々ありますが、結局一番怖かったのがダウンタイムが発生する恐怖でした。
リリースを行う度に数秒ほどシステムが止まる。
PoCから契約へ至ったお客さんがいる中で、このインフラは迷惑をかける事が何よりも嫌だし、これを成長の足枷にしたくないです。
そこで、正式リリースまでの期間が1.5ヶ月くらいと短い期間でしたが、えいやっと移行しました。

f:id:kaminashi-developer:20210328123315j:plain

Fargate内のタスクの定義はsidecar構成で組み立て、メインとなるAPI Serverからログを各種コンテナへ流し込む。
FargateにはFirelensというlog routerというものがあり、これを利用する事でシームレスにコンテナとfluent bitを紐付ける事が出来ます。

docs.aws.amazon.com

他にもdatadogやX-Rayなども切り分けられて、起動しているミドルウェアも極力最小に保つ。
小さく、かつ各コンテナが責務以上の行動をしない。
そんなUNIXらしい設計を意識して作っています。

負荷テストの作成。運用の手間削減

f:id:kaminashi-developer:20210328151846j:plain

実際の負荷テストにはK6 + Grafanaを利用した負荷シナリオテストツールを利用しています。 こちらは以前記事にしているので、詳しい操作方法等はこちらをご覧ください。

kaminashi-developer.hatenablog.jp

  • CLI Likeな設計の作り込み
  • ES2015/ES6のjsに対応、ローカル/リモートのモジュールを利用可能(importも使えるよ)
  • チェックとしきい値の記述も直感的なAPI

こそがK6のメリットと言えます。この手軽さと痒いところに手が届いている感じがいいですよね。

またシナリオ以外にも、Datadog Syntheticsを利用したAPIテストも作ってました。
全てのURL × HTTP Methodのパターンに対してワンパスを通せるので、移行時の動作を一定保証出来るのがいいところです。

docs.google.com

自前でコードを書くのもいいのですが、こういう選択肢もあると知っておくといざという時にさっと使えていいですよね。
実際インフラ移行までの期間が1ヶ月半と限られた中ではあったので、1週間くらいで環境を整えられたのもツールを駆使出来たからこそだと感じます。

クリスマスLock Waitボムの投下

f:id:kaminashi-developer:20210328154215j:plain

クリスマスに投下されたLock Waitボムでしたが、垂直スケールとDead Lockの解消で血を止めました。
実は今回に限らず、これまでにもgolangを利用した負荷問題には頭を悩ませる事が多いです。
その中でも結構困ったAuroraとgolangの事例をご紹介します。

AuroraへのRead/Writeアクセスの切り替えで困った

AuroraはClusterを利用してRead/WriteのホストをURL単位でアクセス先を切り替える事が出来て、かつReadに関してはCPU/Connectionのボリュームによってスケールする事が可能です。
この特性を活用するため、golangを利用した接続先の切り替えを行う実装を追加しました。

f:id:kaminashi-developer:20210328185451p:plain

gorm.Open によってDSNを直接指定するのではなく、sqlwrap を噛ませています。

f:id:kaminashi-developer:20210328192107p:plain

gorm v1は第二引数で指定したオブジェクトは

  • DSNの場合は内部で sql.Open を直接呼び出し
  • SQLCommonのinterafaceを満たす場合は直接dbをオブジェクトのまま渡す

こんな実装となっています。

f:id:kaminashi-developer:20210328171339p:plain

そこで、SQLCommonのメソッドを満たす、sqlwrap.DBを作成します。

f:id:kaminashi-developer:20210328190204p:plain

ここで各接続先を切り替え、リクエスト先のRead/Writeの分岐を行っています。
Master/Slaveメソッドで呼び先のDSNを切り替え、そこで接続先ごとに接続先を切り替えるような実装を自前で行っています。
ただ現在はgorm公式でresolverを出していたりします。
こちらに乗り換えていくべきか、これから合わせて見ていく必要がありますね。

github.com

まとめ

今回はBtoB SaaSのインフラ的な観点というところで発表させていただきましたが、各社ステージごとにそれぞれ共通で持つ課題感がとても面白かったなと感じていました。
自分自身、登壇時のいろいろと反省点はありつつも発表自体はとてもいろんな経験が出来てまたとても新鮮な気持ちで終わる事が出来ました。
また他の場で再挑戦したい!という気持ちでいっぱいです😄

カミナシ自身、インフラ的な課題もより複雑度をましてきて、よりいいカオスな感じになってきました。 成長期のスタートアップならではの課題が増え始めた中で一緒に闘うメンバーを募集しています!

EM/アプリエンジニア/SREと幅広く募集しているので、気になった方は是非気軽にお話しましょう。

open.talentio.com open.talentio.com open.talentio.com