システムの改善がなかなか進まず、古くから独自にカスタマイズされてきたコードの学習コストが高いため、新たにエンジニアを増やすのも難しく、従来のコードベースで開発するので精いっぱいという状況でした。
一方で、社内ではさらに多くの開発量とローンチまでの期間短縮を求められていました。また、インフラ面ではお客さまの増加スピードに合わせて年々サーバの負荷が上がり、ボトルネックをつぶしてもすぐに新たなボトルネックが発生し、その対応に追われる状況が続いていました。
私たちは問題を解決するために、新たな開発トレンドを調査しました。「Twelve-Factor App」やInfrastructure as Code、DevOps、Site Reliability Engineering(SRE)のような方法論、コンテナやAnsibleのような技術を学習して、既存システムのモダン化も試みました。しかし、前述のようにその作業はなかなか進まず、古い部分を変えている間に、それ以上のスピードで新たなサービスが古いフレームワークに追加されていきました。
このような状況の中で、マイクロサービスというキーワードに出会いました。私たちのシステムはモノリシックな状態で改善が難しい状態であると判断し、複数の独立したシステムが疎結合された状態に一から作り替える必要がある(=マイクロサービス化する必要がある)という結論に至ったのです。
マイクロサービス化で物理的にシステムが分割されることで、次のような効果を期待していました。
マイクロサービス化を決断した一方で、マイクロサービスを運用するための組織にも課題がありました。システム本部全体が、事業部の新規サービス開発とオペレーションに全リソースを充てていたため、エンジニア視点で独自の改善活動がしづらい状態だったのです。
これを解決するため、システム部内の判断で改善が進められるような体制づくりを行いました。端的に言うと、システム本部長が執行役員会議で改善活動に関する予算の承諾を取り、そういった活動ができるようにしました。
予算確保により数年間自由に動けるめどが立った後は、開発メンバーの採用を行いました。既存メンバー全員が事業部案件の開発にアサインされていたこと、社内で知見のないスキルが必要だったからです。
選定したスキルに精通し即戦力が期待できるエンジニアを中心に採用活動を行いました。幸いなことに、マイクロサービスに必要な各種スキルと実績を持つメンバーを新たに5人以上採用でき、マイクロサービスに専念できる体制が整いました。現在システム本部には55人のエンジニアがいて、6人のメンバーがサーバサイドのマイクロサービス化にアサインされています。また、フロントエンドやCI/CDまで含めると10人以上のエンジニアが、Oisixブランドを支えるECシステムのモダン化に取り組んでいます。
既存のJavaシステムはServletを直接ラップした独自フレームワークで動いており、その他のライブラリも、マイクロサービス化を決めた当時でさえ、古いといえるものが多い状況でした。マイクロサービスで作り直すに当たり、サーバサイドのJavaエンジニア、フロントのエンジニア、SREチームのエンジニアが一体となって、技術選定を行いました。
準備期間を入れると数年単位で検討が行われ、紆余(うよ)曲折もありましたが、マイクロサービスを開始した時点の状況を分野別に紹介します。
サーバサイドでは、フレームワークの選定から行いました。モダンなフレームワークをJVM言語中心に調査し、JVM言語では「Dropwizard」やScalaの「Play Framework」、JVM言語以外では「Ruby on Rails」などが候補になりました。そうした中で、「Spring Boot」を選択しています。
Spring Bootを選択したのは、その基盤となる「Spring Framework」が老舗のフレームワークで経験者が多いことと、最新バージョンのBootではクラウド環境に対応しているためです。ビルドすると1つのjarファイルのみで起動できるため、Dockerコンテナで動作させやすくなっています。
サーバサイドのプログラム言語は、マイクロサービス単位でJavaと並行して「Kotlin」を選択してもよいというルールにしました。Kotlinは「better Java」として設計されたJavaの仕様に近いモダンな言語で、社内の大半を占めるJavaエンジニアの学習モチベーションが高く、AndroidやSpring BootがKotlinに対応しており、不安材料が少ないことも選定を後押ししました。
フロントエンドでも、サーバサイドのマイクロサービス化に合わせ既存のシステムから変換することを検討しました。既存のECサイトはJSP(JavaServer Pages)を使用しており、JSPは既にメインストリームからは外れているからです。そのためもっとモダンでエンジニアから注目を集めているものを調査し、Spring Bootでも公式サポートされているテンプレートエンジン「Thymeleaf」が有力な候補になりました。
しかし、Thymeleafへの具体的な転換を検討した結果、当時、React、Angular、Vue.jsのようなJavaScriptフレームワークがエンジニアから注目を集めていたのもあり、サーバサイドとフロントエンドのエンジニアを分離することで、スケールする開発体制になると考えるようになりました。
現在は、前述の3フレームワークの中で比較的学習コストが低いとされるVue.jsを採用しています。ビジネスロジックを扱うサーバサイドのJavaアプリケーションと、UX(ユーザーエクスペリエンス)を専門に扱うJavaScriptのシステムを分離。REST APIで疎結合させる設計にしています。またフロントエンドを専門とするエンジニアチームを別途立ち上げています。
SREチームが担当するインフラ面では、アプリケーションのコンテナ化を決めました。既存ECサイトのサーバはデータセンター(DC)のVMで動作していましたが、環境構築をOSから始めたり、その都度CI/CDを実施したりする点でモダンな状態ではありません。
Ansibleでサーバを構築するような取り組みも始まっていたのですが、マイクロサービスを念頭に置いてからはDockerコンテナを利用する方向にシフトしていきました。また選定当時、徐々にデファクトとしての地位が明確になってきたKubernetesをコンテナのプラットフォームとして選択しています。
「AWS Lambda」「Azure Functions」のようなサーバレスアーキテクチャも検討しましたが、Spring Bootのアプリケーションをコンテナで実行するという従来の延長線が私たちには理解しやすかったので、サーバレスアーキテクチャは採用しませんでした。
最後に運用面では、「Papertrail」と「Mackerel」を導入しています。Papertrailはマイクロサービス化で増えたアプリケーションを一元管理するため、MackerelはKubernetesのノードを監視するために利用しています。
Spring BootとKubernetesでマイクロサービス化する方針ができたときに、ほぼ全て開発経験のない技術であったため、包括的に相談できる経験者やコンサルタントを探しました。さまざまな人に相談する中で、Javaの国内第一人者でKubernetesの普及に力を入れている寺田佳央さんに技術顧問をお願いすることができました。
参考: 寺田佳央さんの社内インタビュー
Oisixでマイクロサービス化を始めた当初は、KubernetesをDC内に自前構築していました。いろいろ苦労して環境を作成し、あるサービスを本番サービスインするまでこぎ着けたのですが、その後の保守が大変でした。
Kubernetes自体の開発が活発でバージョンの上がるペースが早く、常に動向を追いながら環境を最新化する必要があり、その作業に想定以上に時間をとられ、SRE活動に専念できなくなってしまったのです。そのため、Oisixのマンパワーを考えると「マネージドKubernetesサービスを使用するのが現実的だ」と考えるようになりました。
当時、日本リージョンでマネージドKubernetesサービスの提供を開始していたことや、技術顧問の助言を受けて、Azure Kubernetes Servicesを選択しています。
24時間365日稼働しているサービスを止めることはできず、一気に全システムをマイクロサービス化することは無理でした。そこで、徐々に既存のシステムを置き換えていく「ストラングラーパターン」を採用することにしました。トランザクションが発生しない参照のみのマスターデータをAPI化したり、ループしながら大量にデータの更新を行うバッチ処理のロジック部分などを切り出したりして進めています。
開発開始後、ECサイトのアプリケーションが巨大なモノリシックな状態なのと同時に、DBもモノリシックな状態になっているという実感を得ることになりました。ECサイトのDBにはOracleを利用していますが、DBが高性能であるが故にほぼ全てのデータを1つのDBに格納していたのです。その結果、アプリケーションとDBが密結合な状態になっていて、システムの分割を難しくする要因になりました。現在のDCから移行できない状態ですが、アプリケーションから先にマイクロサービスに分離し、DBの各テーブルと対話するサービスが固まった後、DBを分離する方針です。
Kubernetesの同一クラスタ内でサービスが連携する一般的な構成で発生する問題ではありませんが、Oisixでは既存のDC内で動作しているモノリシックなシステムから、ストラングラーパターンでAzure Kubernetes Services上のマイクロサービスへ移動させる方式を採用したため、2つのDC間で通信が頻繁に発生する構造になってしまいました。
メソッド単位のような細かい単位でKubernetesのマイクロサービスを呼び出す構成を本番環境で利用した結果、通信回数が多くなってしまい、ECサイトのページ表示に時間がかかり過ぎることが判明しました。この問題はDCを複数使い続ける限りはつきまとう問題で、現在も残るなかなか悩ましい問題です。この問題は、短期的には、両DCでキャッシュしたり、通信回数を減らしたりすることで対応しています。長期的には、フロントエンドを既存のECサイトから分離することでDC間の通信を行わない状態にして解消させる方針です。
今回はマイクロサービス開始時のOisixのECサイトの状況を紹介しました。次回からは、より具体的にマイクロサービスのアーキテクチャの設計や、運用について掘り下げます。
システム本部シニアアーキテクト。2010年にフリーランスでオイシックスにジョインしてその後入社。もともとの担当はJava全般だったが、2018年からマイクロサービス化の推進を担当。
複雑化、老朽化、ブラックボックス化した既存システムの残存で、2025年以降に予想される経済損失は最大12兆円/年といわれている。これを経済産業省は「2025年の崖」と呼び、企業に警鐘を鳴らす「DXレポート」を公開した。レポートでは、システム開発に取り入れるべきアーキテクチャとして「マイクロサービス」を挙げている。本特集では、マイクロサービスとは何か、システムをマイクロサービスにさせるとどのような課題が生まれるのか、モノリシックなサービスをマイクロサービスに移行させた事例などを通じて、どの場面でマイクロサービスを活用すべきか、現実解を探る。
Copyright © ITmedia, Inc. All Rights Reserved.