Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Agenda ● HUEの変遷 ● Dependency戦国時代 ● MSA黎明期 ● MSAなう ● まとめ ● Q & A

Slide 3

Slide 3 text

0. HUEって?

Slide 4

Slide 4 text

HUE ● ふえ? – High Usability Enterprise application – 「ひゅー」と読みます – 電球ではありません。。。 http://www.worksap.co.jp/hue/ 

Slide 5

Slide 5 text

HUEの特徴 ● Cloud Native ● 分散処理機構 – 膨大な量の帳票の集計の高速化 (一億明細とか) ● 人工知能 – 学習に基づく、Input Less化 ● 応答速度にコミット – 100msで応答するという挑戦

Slide 6

Slide 6 text

規模感 ● 開発者 – 3000+ (日本、上海、シンガポール、インド) ● CIチーム – 30名(日本、上海) ● 運用チーム – 15名(増員中) ● 偉い人 – 一杯

Slide 7

Slide 7 text

今日、言いたいこと ● MSAへの移行は難しい、けど出来る! – 技術的な難しさ ● 言うても組み合わせ、実はそんなに新奇性はない – 精神的な難しさ ● 「諦める事」への慣れ ● 「仕様」という言葉の魔法感 – ノーガードになる ● パラダイムシフトを許容出来ない – 目に見える範囲で「改善」を積み上げる Springそのものの話は、あんまり無いですね、今回...

Slide 8

Slide 8 text

1. HUEの変遷

Slide 9

Slide 9 text

プロジェクト開始当初 ● Springエコシステムをある程度使う – 2年半ぐらい前の話 Spring MVC Spring JDBC Spring Cache Abstraction Application Code Forneus (自作超高速レンダリングエンジン) Google Closure Library

Slide 10

Slide 10 text

え?なんでRDBMSつかってるの? ● 大号令、「RDBMSから脱却!」 – 2年前ぐらい ● Cassandraの導入が決定 ● Sparkをバッチ処理にもってくる ● メイン処理からRDBMSは完全撤廃 Spring MVC Spring Cache Abstraction Application Code Forneus (自作超高速レンダリングエンジン) Google Closure Library KVA (C*ドライバ)

Slide 11

Slide 11 text

ねえ、バージョンアップしてみて? ● 1年ちょっと前 – 状況 ● 三週間あればバージョンアップ出来ます! これって。。。

Slide 12

Slide 12 text

Monolithic !!

Slide 13

Slide 13 text

苦闘の歴史の始まり ● 巨大でモノリシックなモジュール – 膨大なソースコードをマージして1つに ● ビルド時間 – ほぼ1日(14時間) ● 環境構築の時間は含まれておらず、構成確認は出来ない ● テストも流せない…… ● 浪費癖 – .warを動かすには、32Gbyteのメモリが必要です!! ● 進まない理解 – MSA、え?それって美味しいの??

Slide 14

Slide 14 text

正しく考えてみる:仮説 個別のサービス単位でバージョンアップする 他に影響は及ぼさず、高速にビルド・デプロイ サービスレベルでの依存の排除 WebAPIにのみ依存する開発スタイル ということは?

Slide 15

Slide 15 text

Micro Services Architecture !! ● これなんじゃね?

Slide 16

Slide 16 text

HUEの制約 ● 目的 – 100msでの応答速度を達成する – 統一感のある、UI・UX ● 戦略 – コンパイルの出来るJS ● Closure Compiler → Google Closure Library – 一元配信出来るCSS ● LESS – サーバサイドレンダリング ● Forneus

Slide 17

Slide 17 text

HUEの要求(一部) ● ビジネスドメイン単位で導入したい – 例:) お客様が購入されたライセンス単位で ● 品質を担保したい – 100msでの応答速度 ● フレキシブルなスケールアウト・スケールアップ – 理にかなった、UI / UX ● 導入作業を軽減したい – ERPの導入作業は凄く大変… ● 時間、リソース、複雑さ

Slide 18

Slide 18 text

2. Dependency戦国時代

Slide 19

Slide 19 text

事実を詳らかにしていく作業 ● とりあえず孤軍奮闘 ● まずは依存性の調査 – mvn dependency:tree – Dependency Analyzer – JSレベルでも、deps.jsとかを眺めてみる

Slide 20

Slide 20 text

こうなった。。。

Slide 21

Slide 21 text

どうしよう。。。 ● 選択肢は2つ – 新しいものは美しく – 既存のものはサヨウナラ ● 分けると良さそうな気がする – 最早、管理できない単位なのは明白

Slide 22

Slide 22 text

レポジトリ分割闘争 ● 分割するってことは – 管理する単位自体を変えるっていうこと ● どっちがいいの? – 1レポジトリで全部やるか ● ツリーは1つ ● レポジトリも1つ – 細かく分けていくか ● ツリーは1つ ● レポジトリはN個

Slide 23

Slide 23 text

1レポジトリ派 ● Pros – インテグレーションレベルでの問題発見の早さ ● 製品の弱点がすぐに分かる仕組みをつくりやすい ● Cons – Cloneの速度 ● 単純な物量 – テスト時間 ● ユニットテストすら工夫して流す必要 – ビルド・デプロイ時間 ● Googleスタイル、彼らはビルドツール開発にも注力 – Bazel → https://bazel.build/

Slide 24

Slide 24 text

レポジトリ分割派 ● Pros – cloneが速い – ビルドも早い – テストもしやすい ● Cons – インテグレーションレベルでの問題は発見しづらい ● ここに対する処方箋は必要

Slide 25

Slide 25 text

HUEの戦略 ● Jenkinsレベルでどんどんテストを組み込む – 1レポジトリに組み込まれるもの ● Pre-merge build (Merge前にUnitTestは流す) ● Smoke Test (Dockerベースで起動確認だけする) ● GitlabでのReview Board (シニアのLGTM必要) ● 開発者を不用意に待たせない – 2000人を10時間も待たせられない… ● インテグレーションレベルの問題 – 0から環境を毎日作ってそこでテスト ● ビルドこけたら緊急出動! – Immutable Infrastructureを目指す

Slide 26

Slide 26 text

戦略が決まったので、実行 ● 「意味ある単位」に分解 – 業務機能での何となくの塊(完璧でなくていい) – 共通機能と業務機能は絶対に別 ● ここは理解が得られやすい FW (全部入り) 認証 経費管理 残り イテレーション単位で狙いを定めて、分解していく

Slide 27

Slide 27 text

得られた知見 ● 共通部分は以外と切り出せる – 機能的な重複は意外と少なかった – ソースはカオスでも一旦置いておける ● Refactoringは独立宣言後でも大丈夫(優先度的に) – 切り出せたものは極小に ● 32G → 650Mbyte ● 業務アプリはやっぱりFWにべったり – やったところでスリムにならない – メモリ:32G → 24Gぐらい(激重) 要はやっぱり、「依存関係」

Slide 28

Slide 28 text

3. MSA黎明期

Slide 29

Slide 29 text

作戦を立て直す #1 ● レポジトリを分割してしまえは正しい ● メモリ圧迫の原因は、Beanの過剰生成も – 去年の発表参照 ● 共通部分の分離が急務だが、影響範囲は莫大 – 可視化しないと、どうなっているか分からない ● ドメインの分割も出来ていない – 実は、大きなレイヤでは分かれている、ERPだから ● HR, AC, SCM ● 要するに、ヒト・モノ・カネ

Slide 30

Slide 30 text

作戦を立て直す #2 ● FWに入っているものにも何か混ざってる – 承認ワークフロー – Collaboration Features ● Spreadsheet, Timeline, Drive, Talk etc... ● 製品を構成する要素としてはFWに見えるけど – 実は、サービスとして切りだされるもの ● 例:) Spreadsheetは、Google SpreadsheetのERP版

Slide 31

Slide 31 text

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はご愛嬌

Slide 32

Slide 32 text

Gitレポジトリは分割する ● FWと称して全てを内包していたので – どんどん分解 Timeline Approval Spreadsheet Framework

Slide 33

Slide 33 text

普通の景色に戻す(ように頑張る) ● ApplicationとLibrary – Library: 内製のラッパや、ユーテリティ、共通機能 – Application: サービスそのもの ● Application間はWebAPIでやりとり Application A use Logging Encryption Spring Boot use use Application B Application C WebAPI WebAPI

Slide 34

Slide 34 text

ビルドの単位も切り離そう ● ドメインが分割不可能なら – 大きな開発組織単位で ● Stakeholderが減る – 開発のやることは増えるが、責任は明確に ● 出来るだけ政治的混乱に開発は巻き込まない Framework Collaboration Human Resource Accounting I/F

Slide 35

Slide 35 text

デプロイは一括でしか出来ない ● ドメインの分割は本質的な問題 – 下記の状態。双方に初期出荷データが必要になる ● 理想解 – サービス間でデータの共有をしない ● 検索Indexどうするの? ● データの分割はとてつもなく難しい – 定義の曖昧さ、責任の曖昧さ ● 例) 承認ワークフローって皆、使うけど誰のもの? ● 歴史的問題 – 組織はMSAに都合良く組織されない F/W Accounting

Slide 36

Slide 36 text

得られた知見 ● ここまでやると、そろそろ本質に気づいてくる – ドメインとは ● 実は、売りたい単位? ● 実は、バージョンアップしたい単位? ● 実は、ライセンスの単位? – こんな議論が繰り広げられるようになる ● で、更なる(現実めいた)オーダが飛んでくる

Slide 37

Slide 37 text

4. MSAなう

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

コストをさげるんだー!! ● インスタンスコスト – 利用時間あたり、どれぐらい稼働させ続けるのか? ● HUEは、1インスタンス、1サービスだと無理がある ● Kubernetes – 巨大インスタンス1つで、N個のPOD(サービス)という戦略が可能 ● かつ、M/Wリソースは共有出来ないといけない – 各社毎にインスタンスを立てていくと、凄く高い ● Multi-tenancyという選択肢 ● Managed Serviceも活用しよう – AWS Lambdaとか ● 100ms単位課金(使った分だけお金を払う)

Slide 41

Slide 41 text

余談ですけど、高いですよ!! ● 冗長性 – だって、普通に落ちるからね – 昼間はN個、夜間はN/2個とかは必要です – Multi-AZとかMulti-Region考慮すると余計高い ● というわけで、下記は必須です – 出納大臣(もしくは、Billing API) – 性能大臣 (もしくは、負荷試験と綿密なCP) コストと性能はトレードオフ、しかし、妥協点は見出すべきです!!

Slide 42

Slide 42 text

じゃあ、こうしよう! (取組中) ● APサーバも含めて、M/Wは、Multi-tenancy ● Multi-regionも視野にいれる AP C* ES Kafka Redis Managed Service AWS Lambda とか... VPC

Slide 43

Slide 43 text

War → Docker (取組中) ● ライブラリの制約からの解放 – やっと、Spring Boot使える... ● Docker Fileを成果物にする – Buildまで開発チームで責任もってもらう

Slide 44

Slide 44 text

運用も委譲しちゃえ (取組中) ● ビルド – 開発者がやるもの ● デプロイ – Ansibleベースで環境構築スクリプトも書いてもらう ● Scaling Factorとか、非機能要件 – 負荷試験環境でCPして、決める – k8sベースなので、YAMLで決められる ● モニタリング – 可視化ツールで頑張る ● Prometheusとか使い出す

Slide 45

Slide 45 text

CIの役割は? ● インテグレーションの専門部隊へ – Jenkinsで魔法かけない ● Monolithicアプリは往々にして、魔法で出来ている ● インテグレーションレベルでの問題解決を! – MS単位でリグレッションテスト – MS間で結合テスト – データの適用テスト、SlowTest等 ● 開発クオリティを担保する方向へ!! – ビルド屋さんからの卒業 ● 開発ライフサイクルそのものを定義していく部隊へ

Slide 46

Slide 46 text

本番環境は? ● もちろん、専門チームが必要 – コンプライアンスとかの問題 ● Opsを担う人を育てねば。。。

Slide 47

Slide 47 text

5.まとめ

Slide 48

Slide 48 text

インフラ #1 ● インフラドリブンでいこう! – 個々の開発者の理想はチグハグ ● 正直な所、意志の統一はほとんど不可能に近いかも…… ● これは揃えとけ... – Jenkins的なビルドツール – Gitレポジトリ申請フロー – 依存性をチェックする機構 ● マージ前、トピックブランチにpushした直後 ● どんどん落とす:Failさせる ● ビルドドメインを決めたら、そこもチェック対象に

Slide 49

Slide 49 text

インフラ #2 ● 構成管理はしっかりと – 毎日、環境は作りなおす – 当然、スクリプトで管理するべき ● Ansibleとかいい感じ ● 出来上がった環境もチェックに使う – 環境構築スクリプト時点でも問題は発覚する ● CI的な役割をする人間もどんどん文句言う – 第三者的評価もする ● 素朴な疑問に目を背けない – 「自分の評価対象だけ、最新に出来ないでしょうか??」

Slide 50

Slide 50 text

開発者 #1 ● まずは、「依存」に目を向けてもらう – mvn dependency:tree, 自分たちの依存はしっかり分かっておく ● 「依存」と闘うことに、嫌気がさしてきたら – Dockerベースでのビルドまでを出来るように頑張る ● 当たり前をちゃんとやる – ステートレス, ドメインをしっかり定義して、そこを逸脱しない ● 何でもテスト出来るようにしておく – Dependencyチェック, 初期出荷スクリプトのチェック, 各種テスト ● 一番大事なことは – 「覚悟」しろ! って言うこと ● 「運用」とか言われると、始めは誰しも怖いものです

Slide 51

Slide 51 text

開発者 #2 ● Web APIベースでの開発には... – 互換性維持は基本、出来ればForwardも ● Unit test、Swagger、バージョンを組み込んだAPIデザイン – 低レイテンシ ● 非同期、バルク、キャッシュの有効利用 – 結合テストの効率化 ● モック、SDKの提供 (Feign的な...) – 監視のためのWeb APIのトレーサビリティ ● 相関ID (Sleuth的な...) – 可用性の確保 ● サーキットブレーカパターン、インフラも含めて (Hystrix的な...)

Slide 52

Slide 52 text

組織 ● 開発は出来るだけ、Agileで – 早く見つけて、早く修正 ● レビュー機関の必要性 – 製品としてのコンセプトを判断できるチーム – Architectureを判断できるチーム ● インフラチームとがっつりタッグを組まないと、形骸化 する ● APIのルール、デザイン ● M/Wの使用方法 – 無駄なコストをかけない – デザイン(UI/UX)を判断できるチーム

Slide 53

Slide 53 text

苦闘の歴史は? ● 巨大でモノリシックなモジュール → 6個に分割、Gitレポジトリはもっと細かく ● ビルド時間 – ほぼ1日(14時間) → 5〜40分を「並列」で ● 浪費癖 – Xmx:32Gbyte    →  Xmx:1-4Gbyte ● ライ○ップもびっくり ● ちなみに、話者も20K減量(前年比) ● 進まない理解 – 無理、無知 --> どうしたら分割できるだろう?

Slide 54

Slide 54 text

Any Questions?

Slide 55

Slide 55 text

We are hiring!!