Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Microservices Architectureを超大規模プロジェクトでやってみた

Microservices Architectureを超大規模プロジェクトでやってみた

B8ba54ba28814c0a23e1d8898abddad2?s=128

Yasuhiro Miyake

November 18, 2016
Tweet

Transcript

  1. Microservices Architecture を 超大規模プロジェクトでやってみた - 一筋縄でいかない苦闘の一年間 - 株式会社ワークスアプリケーションズ 三宅 泰裕

  2. Agenda • HUEの変遷 • Dependency戦国時代 • MSA黎明期 • MSAなう •

    まとめ • Q & A
  3. 0. HUEって?

  4. HUE • ふえ? – High Usability Enterprise application – 「ひゅー」と読みます

    – 電球ではありません。。。 http://www.worksap.co.jp/hue/ 
  5. HUEの特徴 • Cloud Native • 分散処理機構 – 膨大な量の帳票の集計の高速化 (一億明細とか) •

    人工知能 – 学習に基づく、Input Less化 • 応答速度にコミット – 100msで応答するという挑戦
  6. 規模感 • 開発者 – 3000+ (日本、上海、シンガポール、インド) • CIチーム – 30名(日本、上海)

    • 運用チーム – 15名(増員中) • 偉い人 – 一杯
  7. 今日、言いたいこと • MSAへの移行は難しい、けど出来る! – 技術的な難しさ • 言うても組み合わせ、実はそんなに新奇性はない – 精神的な難しさ •

    「諦める事」への慣れ • 「仕様」という言葉の魔法感 – ノーガードになる • パラダイムシフトを許容出来ない – 目に見える範囲で「改善」を積み上げる Springそのものの話は、あんまり無いですね、今回...
  8. 1. HUEの変遷

  9. プロジェクト開始当初 • Springエコシステムをある程度使う – 2年半ぐらい前の話 Spring MVC Spring JDBC Spring

    Cache Abstraction Application Code Forneus (自作超高速レンダリングエンジン) Google Closure Library
  10. え?なんでRDBMSつかってるの? • 大号令、「RDBMSから脱却!」 – 2年前ぐらい • Cassandraの導入が決定 • Sparkをバッチ処理にもってくる •

    メイン処理からRDBMSは完全撤廃 Spring MVC Spring Cache Abstraction Application Code Forneus (自作超高速レンダリングエンジン) Google Closure Library KVA (C*ドライバ)
  11. ねえ、バージョンアップしてみて? • 1年ちょっと前 – 状況 • 三週間あればバージョンアップ出来ます! これって。。。

  12. Monolithic !!

  13. 苦闘の歴史の始まり • 巨大でモノリシックなモジュール – 膨大なソースコードをマージして1つに • ビルド時間 – ほぼ1日(14時間) •

    環境構築の時間は含まれておらず、構成確認は出来ない • テストも流せない…… • 浪費癖 – .warを動かすには、32Gbyteのメモリが必要です!! • 進まない理解 – MSA、え?それって美味しいの??
  14. 正しく考えてみる:仮説 個別のサービス単位でバージョンアップする 他に影響は及ぼさず、高速にビルド・デプロイ サービスレベルでの依存の排除 WebAPIにのみ依存する開発スタイル ということは?

  15. Micro Services Architecture !! • これなんじゃね?

  16. HUEの制約 • 目的 – 100msでの応答速度を達成する – 統一感のある、UI・UX • 戦略 –

    コンパイルの出来るJS • Closure Compiler → Google Closure Library – 一元配信出来るCSS • LESS – サーバサイドレンダリング • Forneus
  17. HUEの要求(一部) • ビジネスドメイン単位で導入したい – 例:) お客様が購入されたライセンス単位で • 品質を担保したい – 100msでの応答速度

    • フレキシブルなスケールアウト・スケールアップ – 理にかなった、UI / UX • 導入作業を軽減したい – ERPの導入作業は凄く大変… • 時間、リソース、複雑さ
  18. 2. Dependency戦国時代

  19. 事実を詳らかにしていく作業 • とりあえず孤軍奮闘 • まずは依存性の調査 – mvn dependency:tree – Dependency

    Analyzer – JSレベルでも、deps.jsとかを眺めてみる
  20. こうなった。。。

  21. どうしよう。。。 • 選択肢は2つ – 新しいものは美しく – 既存のものはサヨウナラ • 分けると良さそうな気がする –

    最早、管理できない単位なのは明白
  22. レポジトリ分割闘争 • 分割するってことは – 管理する単位自体を変えるっていうこと • どっちがいいの? – 1レポジトリで全部やるか •

    ツリーは1つ • レポジトリも1つ – 細かく分けていくか • ツリーは1つ • レポジトリはN個
  23. 1レポジトリ派 • Pros – インテグレーションレベルでの問題発見の早さ • 製品の弱点がすぐに分かる仕組みをつくりやすい • Cons –

    Cloneの速度 • 単純な物量 – テスト時間 • ユニットテストすら工夫して流す必要 – ビルド・デプロイ時間 • Googleスタイル、彼らはビルドツール開発にも注力 – Bazel → https://bazel.build/
  24. レポジトリ分割派 • Pros – cloneが速い – ビルドも早い – テストもしやすい •

    Cons – インテグレーションレベルでの問題は発見しづらい • ここに対する処方箋は必要
  25. HUEの戦略 • Jenkinsレベルでどんどんテストを組み込む – 1レポジトリに組み込まれるもの • Pre-merge build (Merge前にUnitTestは流す) •

    Smoke Test (Dockerベースで起動確認だけする) • GitlabでのReview Board (シニアのLGTM必要) • 開発者を不用意に待たせない – 2000人を10時間も待たせられない… • インテグレーションレベルの問題 – 0から環境を毎日作ってそこでテスト • ビルドこけたら緊急出動! – Immutable Infrastructureを目指す
  26. 戦略が決まったので、実行 • 「意味ある単位」に分解 – 業務機能での何となくの塊(完璧でなくていい) – 共通機能と業務機能は絶対に別 • ここは理解が得られやすい FW

    (全部入り) 認証 経費管理 残り イテレーション単位で狙いを定めて、分解していく
  27. 得られた知見 • 共通部分は以外と切り出せる – 機能的な重複は意外と少なかった – ソースはカオスでも一旦置いておける • Refactoringは独立宣言後でも大丈夫(優先度的に) –

    切り出せたものは極小に • 32G → 650Mbyte • 業務アプリはやっぱりFWにべったり – やったところでスリムにならない – メモリ:32G → 24Gぐらい(激重) 要はやっぱり、「依存関係」
  28. 3. MSA黎明期

  29. 作戦を立て直す #1 • レポジトリを分割してしまえは正しい • メモリ圧迫の原因は、Beanの過剰生成も – 去年の発表参照 • 共通部分の分離が急務だが、影響範囲は莫大 –

    可視化しないと、どうなっているか分からない • ドメインの分割も出来ていない – 実は、大きなレイヤでは分かれている、ERPだから • HR, AC, SCM • 要するに、ヒト・モノ・カネ
  30. 作戦を立て直す #2 • FWに入っているものにも何か混ざってる – 承認ワークフロー – Collaboration Features •

    Spreadsheet, Timeline, Drive, Talk etc... • 製品を構成する要素としてはFWに見えるけど – 実は、サービスとして切りだされるもの • 例:) Spreadsheetは、Google SpreadsheetのERP版
  31. Beanの生成は手動定義 • Auto Confguration的ではなく – Confgurationクラスに必要なものを自分で書く – 依存ツリーは自分で意識して、@Importする @GuardedConfiguration(ExampleConfig.class) @Import({CassandraConfig.class})

    public class ExampleConfig { @Bean public Foo foo() { return new FooImpl(bar()); } @Bean public Bar bar() { return new BarImpl(); } @Bean @Autowired public Baz baz(KeyValueAccess kva) { return new BazImpl(kva); } } @GuardedConfigurationはご愛嬌
  32. Gitレポジトリは分割する • FWと称して全てを内包していたので – どんどん分解 Timeline Approval Spreadsheet Framework

  33. 普通の景色に戻す(ように頑張る) • ApplicationとLibrary – Library: 内製のラッパや、ユーテリティ、共通機能 – Application: サービスそのもの •

    Application間はWebAPIでやりとり Application A use Logging Encryption Spring Boot use use Application B Application C WebAPI WebAPI
  34. ビルドの単位も切り離そう • ドメインが分割不可能なら – 大きな開発組織単位で • Stakeholderが減る – 開発のやることは増えるが、責任は明確に •

    出来るだけ政治的混乱に開発は巻き込まない Framework Collaboration Human Resource Accounting I/F
  35. デプロイは一括でしか出来ない • ドメインの分割は本質的な問題 – 下記の状態。双方に初期出荷データが必要になる • 理想解 – サービス間でデータの共有をしない •

    検索Indexどうするの? • データの分割はとてつもなく難しい – 定義の曖昧さ、責任の曖昧さ • 例) 承認ワークフローって皆、使うけど誰のもの? • 歴史的問題 – 組織はMSAに都合良く組織されない F/W Accounting
  36. 得られた知見 • ここまでやると、そろそろ本質に気づいてくる – ドメインとは • 実は、売りたい単位? • 実は、バージョンアップしたい単位? •

    実は、ライセンスの単位? – こんな議論が繰り広げられるようになる • で、更なる(現実めいた)オーダが飛んでくる
  37. 4. MSAなう

  38. で、幾らかかるんだっけ? • メモリを大量に消費する作りで • インスタンス自体はバラバラになっていって – あまり、メモリ自体の削減効率は上がらず...... • ビルドは綺麗になったものの •

    デプロイは1回のみ
  39. None
  40. コストをさげるんだー!! • インスタンスコスト – 利用時間あたり、どれぐらい稼働させ続けるのか? • HUEは、1インスタンス、1サービスだと無理がある • Kubernetes –

    巨大インスタンス1つで、N個のPOD(サービス)という戦略が可能 • かつ、M/Wリソースは共有出来ないといけない – 各社毎にインスタンスを立てていくと、凄く高い • Multi-tenancyという選択肢 • Managed Serviceも活用しよう – AWS Lambdaとか • 100ms単位課金(使った分だけお金を払う)
  41. 余談ですけど、高いですよ!! • 冗長性 – だって、普通に落ちるからね – 昼間はN個、夜間はN/2個とかは必要です – Multi-AZとかMulti-Region考慮すると余計高い •

    というわけで、下記は必須です – 出納大臣(もしくは、Billing API) – 性能大臣 (もしくは、負荷試験と綿密なCP) コストと性能はトレードオフ、しかし、妥協点は見出すべきです!!
  42. じゃあ、こうしよう! (取組中) • APサーバも含めて、M/Wは、Multi-tenancy • Multi-regionも視野にいれる AP C* ES Kafka

    Redis Managed Service AWS Lambda とか... VPC
  43. War → Docker (取組中) • ライブラリの制約からの解放 – やっと、Spring Boot使える... •

    Docker Fileを成果物にする – Buildまで開発チームで責任もってもらう
  44. 運用も委譲しちゃえ (取組中) • ビルド – 開発者がやるもの • デプロイ – Ansibleベースで環境構築スクリプトも書いてもらう

    • Scaling Factorとか、非機能要件 – 負荷試験環境でCPして、決める – k8sベースなので、YAMLで決められる • モニタリング – 可視化ツールで頑張る • Prometheusとか使い出す
  45. CIの役割は? • インテグレーションの専門部隊へ – Jenkinsで魔法かけない • Monolithicアプリは往々にして、魔法で出来ている • インテグレーションレベルでの問題解決を! –

    MS単位でリグレッションテスト – MS間で結合テスト – データの適用テスト、SlowTest等 • 開発クオリティを担保する方向へ!! – ビルド屋さんからの卒業 • 開発ライフサイクルそのものを定義していく部隊へ
  46. 本番環境は? • もちろん、専門チームが必要 – コンプライアンスとかの問題 • Opsを担う人を育てねば。。。

  47. 5.まとめ

  48. インフラ #1 • インフラドリブンでいこう! – 個々の開発者の理想はチグハグ • 正直な所、意志の統一はほとんど不可能に近いかも…… • これは揃えとけ...

    – Jenkins的なビルドツール – Gitレポジトリ申請フロー – 依存性をチェックする機構 • マージ前、トピックブランチにpushした直後 • どんどん落とす:Failさせる • ビルドドメインを決めたら、そこもチェック対象に
  49. インフラ #2 • 構成管理はしっかりと – 毎日、環境は作りなおす – 当然、スクリプトで管理するべき • Ansibleとかいい感じ

    • 出来上がった環境もチェックに使う – 環境構築スクリプト時点でも問題は発覚する • CI的な役割をする人間もどんどん文句言う – 第三者的評価もする • 素朴な疑問に目を背けない – 「自分の評価対象だけ、最新に出来ないでしょうか??」
  50. 開発者 #1 • まずは、「依存」に目を向けてもらう – mvn dependency:tree, 自分たちの依存はしっかり分かっておく • 「依存」と闘うことに、嫌気がさしてきたら

    – Dockerベースでのビルドまでを出来るように頑張る • 当たり前をちゃんとやる – ステートレス, ドメインをしっかり定義して、そこを逸脱しない • 何でもテスト出来るようにしておく – Dependencyチェック, 初期出荷スクリプトのチェック, 各種テスト • 一番大事なことは – 「覚悟」しろ! って言うこと • 「運用」とか言われると、始めは誰しも怖いものです
  51. 開発者 #2 • Web APIベースでの開発には... – 互換性維持は基本、出来ればForwardも • Unit test、Swagger、バージョンを組み込んだAPIデザイン

    – 低レイテンシ • 非同期、バルク、キャッシュの有効利用 – 結合テストの効率化 • モック、SDKの提供 (Feign的な...) – 監視のためのWeb APIのトレーサビリティ • 相関ID (Sleuth的な...) – 可用性の確保 • サーキットブレーカパターン、インフラも含めて (Hystrix的な...)
  52. 組織 • 開発は出来るだけ、Agileで – 早く見つけて、早く修正 • レビュー機関の必要性 – 製品としてのコンセプトを判断できるチーム –

    Architectureを判断できるチーム • インフラチームとがっつりタッグを組まないと、形骸化 する • APIのルール、デザイン • M/Wの使用方法 – 無駄なコストをかけない – デザイン(UI/UX)を判断できるチーム
  53. 苦闘の歴史は? • 巨大でモノリシックなモジュール → 6個に分割、Gitレポジトリはもっと細かく • ビルド時間 – ほぼ1日(14時間) →

    5〜40分を「並列」で • 浪費癖 – Xmx:32Gbyte    →  Xmx:1-4Gbyte • ライ◦ップもびっくり • ちなみに、話者も20K減量(前年比) • 進まない理解 – 無理、無知 --> どうしたら分割できるだろう?
  54. Any Questions?

  55. We are hiring!!