サービスの成長を支えた

Railsとマイクロサービス

株式会社FiNC

森 久太郎 (@qsona)

@qsona

  • 2013/06- CyberAgent
    • ソーシャルゲーム
    • Node.js / MongoDB
  • 2016/02- FiNC
    • Rails, MySQL
    • Node.js
    • Microservices
      • 社内 3 サービスのowner
      • 旗振り役的な?

マイクロサービス時代に捧ぐ、Railsでの中規模APIサーバ開発のための技術構成

(Ruby on Rails Advent Calendar 2016 6日目)

(宣伝) Microservices Meetup

今日話すこと

  • Railsとマイクロサービスが、どのように
    サービスの成長に寄与してきたか
     
  • 現存する問題を振り返ってみて、回避できたかもしれないこと

FiNC とは(1)

  • ヘルスケアのベンチャー企業
     
  • 企業理念:
    「一生に一度のかけがえのない人生をサポートする」
     
  • 健康寿命を伸ばす

FiNC とは(2)

  • ヘルスケアに関する事業を多角的に展開
    • FiNC アプリ
    • FiNC for Business
    • FiNC Mall
    • オンラインワークス
      • 専門家とユーザをつなぐプラットフォーム
      • アプリを通して
  • パーソナライズ, 機械学習

1章

サービスの成長を支えた
Rails, マイクロサービス

1-1. Railsとサービスの成長

FiNCでのRailsの利用

  • Web API

    •  FiNC Appのバックエンド

    • 他多数

  • 動的HTML

    • FiNC Mall (ECサイト)

    • アプリ内のWebView

    • 管理画面 

FiNCでのRailsの規模

  • アクティブなRailsのサービス数: 約20

  • もっとも大きいサービスでは...

    • 開発期間: 3年半
    • ActiveRecordの数: 630

Railsでよかったこと

  • やりたいことを一通りカバーしてくれる
    • 余計なことで悩む必要がない
    • 技術スタックの乱立を防げる
  • 枯れている・情報量が多い
  • (開発者がある程度多い)
    • => 実際は、Rails経験者の社員はそれほど多くない

Rails でサービスを成長させる上で気をつけていること

学習コストは?

  • サーバサイドの開発をしている社員: 15人くらい
  • そのうち、Rails経験者は4人くらい
    • 私も未経験者で入った
  • ​学生のインターンも多い
    • ​プログラミング自体未経験
  • どのように学習コストを下げているか?

教えあう文化

教えすぎない文化

  • 特に、学生インターンや若手向け
  • 単に動かす方法をすぐに教えない
    • 1行ずつ丁寧にコードを読む習慣
    • なぜそう動くのか、を考えさせる
  • 目先の方法より、問題解決する力をつけてもらう

Rails の技術を取り入れる

  • 技術顧問: @willnet さん
    • 2016/1 -
    • Ruby, Railsにまつわる様々な問題を
      相談させて頂いている
    • 多くの問題を未然に回避
  • Railsに熟練した方に業務委託を依頼
    • コードから学べる
    • 既存の問題を指摘して下さることも多い

データベース設計 > Rails way

  • Railsで扱いやすくても、サービスが成長すると辛くなることがあるパターンがある
    • ポリモーフィック関連
    • STI (単一テーブル継承)
  • データベースの設計を、Railsの都合よりも優先させる
  • 社内推薦図書の1つにも
  • ​データが非常に重要である、という意識の表れ

1-1 まとめ

  • Railsは、様々な面でスタートアップに適している
  • 学習コストの問題は、教える(ない)文化でカバー
  • 積極的に外部の方の知見を取り入れる
  • データベース設計を優先させ、将来の負債を回避する

1-2. マイクロサービスとサービスの成長

マイクロサービスとは

  • 1つのプロダクトを、複数のサービスに分け、連携させるように作る手法
  • サービスとは?
    • ビジネスの単位で分けられる
    • 独立して開発・デプロイが可能
  • 各サービスはAPIを経由して連携する

FiNCのマイクロサービスとは

・・・の前に、
他社さんのマイクロサービスを
覗いてみる

AbemaTVさん

  • Google Cloud Platform + Kubernetes + gRPC で
    種々の物理的な難しさを解消

出典:
AbemaTVにおけるMicroservices Architecture

by 西尾亮太さん

  • Backendは Go 言語
    • 非同期処理に強い

FiNCのマイクロサービス

  • 特段、マイクロサービスのために何か使っていたわけではない (なかった)
    • ほぼすべてのサービスがRails
    • JSON over HTTP
    • Amazon EC2 (だった)
  • 物理的な難しさや種々の複雑さはつねに付きまとう

結構大変・・・

マイクロサービスにした理由

を、FiNCの初期開発メンバーに聞いてみた

マイクロサービスにした理由

マイクロサービスにした理由

  • FiNCは、すべての人を健康にするのがビジョン
     
  • そのために、ヘルスケアの中であれば分野を限定せず、
    様々なサービスを提供していく意志が初期からあった
    • それらのサービスは単体ではなく、緩く連携して動く
       
  • 将来の構想を見越した上での
    マイクロサービスの選択

マイクロサービスの恩恵

  • ビジネスとしての側面が大きい
    • ビジネス単位で独立することによる、開発のイテレーションの短縮
    • 後からそのビジネスが大きくなったときにも強い
       
  • ​技術的な独立
    • ​小さいサービスで技術チャレンジがしやすい
    • こちらの恩恵はもう少し先かも

マイクロサービスと成長

総じて、サービスの成長とともに恩恵が増えてきている

  • デプロイの頻度を下げないことに成功している
    • ビジネスとマイクロサービスの単位がマッチ
    • 我々の設計がこなれてきた
  • 非同期的なアーキテクチャにして、ユーザからみた応答時間を速くする
  • 技術的な挑戦が増えている

1-2 まとめ

  • マイクロサービスは、コストも大きい
    • 特に、物理的な心配事
  • サービスの成長とともに恩恵が増えてくる
  • 多角的なビジネス展開にマッチする

2章

FiNCの技術の現在から
開発の歴史を振り返る

技術的負債の棚卸し中

パフォーマンス低下の原因、開発が遅くなる原因、
バグや障害のリスクなどを洗い出している

(議事録より抜粋)

何が真の負債か?

  • スタートアップにおいて、初期から綺麗で問題がないコードベースを保つのは難しい
    • 時間・資金的制約
    • 丁寧な設計より勢いが必要なことも
  • ビジネスの方針が変わりやすい
    • 全てを想定して拡張に開くのは難しい
    • 捨てる可能性があるものにコストをかけにくい

何が真の負債か?

  • YAGNI (You ain't gonna need it)
     
  • 問題が顕在化してから、取り組めばいい
     
  • 逆に言うと、問題が顕在化したころにはもう対処できないような類のものは、真の負債だといえる
     
  • このような視点で、対処が難しい負債と
    それに対する取り組みを3つ紹介する

負債1. [Rails]
ActiveRecordの
callback地獄

ActiveRecordのcallback

save などの、ActiveRecordのライフサイクルをフックして、別の処理を走らせる仕組み

class User < ActiveRecord::Base
  after_save :change_xxx_count, if: :xxx_chnaged?
  after_create :sync_yyy

  def change_xxx_count
     # ...
  end
  
  def sync_yyy
    # ...
  end
end

ActiveRecordのcallback地獄

  1. 気軽にafter_saveなどのcallbackをつけてしまう
  2. after_saveでその処理を走らせたくないときが出てくる
    (この時にこのcallbackを消せれば負債回避)
  3. skip_callbackなどでなんとかする
  4. Hell!

対応策

  • 現状対応できてない。

教訓

  • ActiveRecordの (特にsaveをトリガにした) callbackを使うのは慎重にも慎重を期しましょう。
     
  • 未来含めどんなときにも100%起こっていい処理だけをcallbackに書きましょう。
     
  • サービス間の同期処理などをcallbackに書くのはやめましょう。

負債2. [マイクロサービス]
ビジネスのロジックが
複数サービスにまたがる

ビジネスロジックが複数サービスにまたがる

  • いくつかの機能は、2, 3のサービスにまたがってロジックが実装されている
    • 2, 3のサービスを使うこと自体は問題ない
    • ロジックがまたがるのが問題

ビジネスロジックが複数サービスにまたがる

  • 機能修正や追加時に、複数のサービスに変更が入ることが多い
    • 単純に面倒
    • リリース順の問題
    • レビューの負担 (別チームの人がそのビジネスを理解しないといけない)

今後の対応策

  • Design Doc の取り組み
    • 複数サービスをまたがるような実装をする前に、設計のレビューを必ずする

教訓

  • 単一責任の原則を忠実に守る
  • サービス間にまたがる設計は容易に変更できないので、注意深く設計し、レビューもすべき

負債3.
万能API ( kill v3/me )

v3/me というAPI

  • そのユーザに関する情報が、何から何までとれるAPI
    • プロフィール
    • 各種設定
    • いろんなフラグ
    • 他サービスに飛ばすURL
    • サーベイの結果
      • 他サービスに問い合わせている
  • 「マイページに出したい全データ」に近い

問題点

  • クライアント・サーバ問わず、いろいろなところから呼ばれてしまう
    • 実際はそんな多くデータいらない・・・
    • 認証のためだけに他サービスから呼ばれていた例も
    • パフォーマンス問題に
  • サービス間で循環参照
    • オーケストレーションを担っているのが原因
  • リソースになっていない

対応策(1) リソースの分割

  • v3/me のレスポンスを、リソースとして切り分けられる単位に分割していった
     
  • それぞれを別のAPIとして提供

リソース指向のAPIへ

  • Rails上の技術スタックの変更
    • apiの定義: Grape => ActionController
    • jsonの生成: rabl => active_model_serializers
      • リソースを明確に定義していく
         
  • 参考: FiNCのWeb API開発事情

リソース指向APIの作成

リソース指向APIの浸透

  • クライアントも問題を抱えていた
    • iOS, Android, Web appでそれぞれ
      ​サーバのレスポンスのマッピング方法が違う
  • サーバとクライアントで議論し、リソースを抽出する

対応策(2) Front-end Server

  • クライアントとバックエンドの間のサーバ
  • オーケストレーションの役目を負わせる
    • 1つの画面で、2つ以上のAPIが必要なとき
  • Node.js で作った
    • 非同期的な処理がメインなため
  • ​バックエンドは、自らの責務にフォーカスできる

教訓

  • バックエンドは「画面」を意識しすぎたAPIを作らないように気をつける
    • とはいえ、スタートアップ初期では難しそう
    • リソースの定義も結構ころころ変わりそうで難しいし・・・?
    • このような問題が将来起きうることを想定しておく

まとめ

  • FiNCでは、Rails をメインに据え、その恩恵をうけながら、マイクロサービスを指向してサービスを開発している
  • Railsでは、サービスの拡大には罠となるような機能もあるので注意する
  • マイクロサービスは、サービスの成長に伴い恩恵が増えていく
  • 技術的負債はその全てを回避するのは難しいが、
    将来に渡って改修できなくなるような真の負債は残さないよう努力する

We are hiring!!

Made with Slides.com