プロダクトの成長を下支えする、Goによるマイクロサービス化とは?

f:id:poniki:20220124170447p:plain 「今後、習得・強化したいプログラミング言語は何ですか?」

ファインディがエンジニア1000人を対象に行った調査において、上位にランクインしたのが「Rust」そして「Go」でした。

2021年10月27日に開催した『注目の言語Go、開発現場でどう使われる?活用企業の現場に聞く』では、Goの有識者2名をお招きし、Goの特徴やメリット、採用した理由などを伺いました。モデレーターはファインディの取締役CTO佐藤が務めます。

パネリスト
河津 拓哉さん/(株式会社ARIGATOBANK CTO兼エンジニアリング部 責任者)[@takuz0_]
ヤフー、NTTデータ、ディーカレットを経て2020年11月より現職。 インフラ、バックエンド、アーキテクト中心のエンジニアキャリアを中核に、プロダクト開発に必要な先端技術の取り入れ、 チーム組成、アライアンス構築等、職務職責に限定されない広範な活動により事業推進に寄与。

四方田 貫児さん/(株式会社メルカリ ソフトウェアエンジニア)[@k_yomo_jp]
エムスリー株式会社を経て、2021年4月に株式会社メルカリに入社。メルカリUSの検索基盤チームにて、バックエンドエンジニアとして基盤の安定化や検索改善に従事。公私ともにGoを書く機会が多く、小粒のGoライブラリなども開発中。Go Conference’20 in Autumn SENDAI登壇。

モデレーター
佐藤 将高/(ファインディ株式会社) @ma3tk 東京大学 情報理工学系研究科 創造情報学専攻卒業後、グリーに入社し、フルスタックエンジニアとして勤務する。2016年6月にファインディ立上げに伴い取締役CTO就任。

Goでマイクロサービスを構築、完成形を走りながら作る

冒頭では、二人が関わるプロダクトのアーキテクチャやGoの選定理由について共有してくださいました。

ARIGATOBANKの河津さんは『kifutown』を含む、同社のプロダクトのアーキテクチャについて説明します。

河津さん:『kifutown』に加えて、認証基盤のIDのサービス、これからローンチ予定の決済サービスという、3つのプロダクトを作っており、基本的には同じアーキテクチャに沿って開発しています。

技術の中核としてはGoogle Cloudを全面的に採用。ソースコードをGitHubに置き、GoogleクラウドにCI/CDパイプラインを介してデプロイしています。

外からのトラフィックは、Cloud Load Balancingでバランシングし、Kubernates Engineで動くマイクロサービスに振り分けています。各アプリケーションはCloud SpannerのテーブルやデータベースにIOしています。

Goを使っているのはKubernatesで動いているマイクロサービス群です。現実に存在するオブジェクトやビジネスドメインに対してコンテナサービスを作り、必要に応じてマイクロサービス間のAPIコールを行っていて。このコンテナのアプリケーションをすべてGoで書いています。高負荷なときもありますが、安定して動いていますね。

『kifutown』は、2021年4月に開発が決定、7月にローンチされました。「最初から完成形を作るのではなく、いかに走りながらサービスをよくするかを考えながら、アーキテクチャを構築した」と河津さんは振り返ります。

またチームとして開発力を高め続けるにあたって「読みやすいコード、デプロイしやすいアーキテクチャ、書きやすいアプリケーションであることを重要視したかった」そうです。

なかでもGoを採用した理由は、大規模なトラフィックの増加にも耐えられる必要があったからでした。

河津さん:『kifutown』は前澤友作さんから出資を受けており、前澤さんがSNSなどでシェアした場合など、急にトラフィックが増える可能性が高い。何より沢山のお客様に利用いただきたいという思いがありました。

Goはビルドしたときのフットプリントが小さく、コンテナ管理ツールの『Docker』との親和性も良いこと、平行処理を手軽に書けることなども知っていて。マイクロサービスで提供する際に高負荷にも耐えられ、実装しやすいことからGoを選定しました。

大規模サービスやマイクロサービスとの親和性からGoを選定

続いて、四方田さんがメルカリUSのアーキテクチャについて説明します。

四方田さん:以下の図はバックエンドの言語にフォーカスして整理しています。

まず、ネイティブクライアント向けとウェブ向けのBFF層に分かれています。そこから各マイクロサービス群、認証やアイテムの情報を持つメルカリAPIというphpのサーバーに通信し、情報をアグリゲートし、クライアント側に返すという形です。メルカリAPIはサービス初期から使われているものです。

Goは、マイクロサービス群とネイティブクライアント向けのBFFに使っています。バックエンドにもGoで書いているマイクロサービスが沢山あります。KubernatesのNamespaceの数は100個くらいですかね。

Goを採用した理由については、三世代にわたるアーキテクチャの変遷を踏まえて説明します。

四方田さん:2016年くらいまで、メルカリUSのアーキテクチャにはBFFがなく、メルカリAPIとクライアント、メルカリAPIの裏にMySQLがあるというもの。メルカリAPIとクライアント側のコードベースを、メルカリJPと共有して開発をしていたため、一時期ベロシティが上がらないこともありました。

その後、2017年頃にメルカリUSでリテンション率が低いという課題があって。リテンション率を2倍にするプロジェクトが動き始めたんです。

それで、まずはクライアント側のコードベースをメルカリJPと分離し、刷新しました。合わせて、バックエンド側もメルカリAPIに機能追加するのではなく、新しくマイクロサービスとして切り出し、開発していこうという流れになりました。そこで技術選定をするにあたって、もともとグループ会社で使った経験があり、大規模サービスやマイクロサービスとの親和性の高いGoを採用しました。

活用企業におけるアーキテクチャ、フレームワークの試行錯誤

続いて、Goでマイクロサービス化を進める際にどのように構成を決めていったのか。佐藤がたずねると、河津さんはアーキテクチャの3世代の変遷を紹介しました。

河津さん:第1世代は色んな処理をHTTPリクエストを受けるところから、データベースに読み書きし、レスポンスを返すまでをシンプルに書く方法でした。

第2世代はクリーンアーキテクチャ風。サーバーとHandler、ビジネスロジックを書くユースケースがあり、リポジトリを介して依存を作り、データベースに読み書きするパーシステンス層を作って….といった形でレイヤーを設け、責務やコードを書きやすくしていきました。

今一番新しい世代のアーキテクチャは決済のチームのものです。DIを使って、よりモダンかつシンプルなGoらしい書き方で書いています。このように3世代のプロダクトが混ざりつつ、変遷している形です。

四方田さんもメルカリUSでどのような全体の設計姿勢でアーキテクチャを組んできたのかを話します。

四方田さん:メルカリUSでもマイクロサービスの書き方は様々。統一されたマイクロサービスの書き方があるというより適材適所で書いています。最初に立ち上げるときのboilerplateなどは整備されているかなと思います。

関連して、参加者からは「過去に採用したフレームワークやツール、アーキテクチャの所感を聞きたい」と質問が挙がりました。

河津さんは「ほとんど自分たちで書いている部分が多い」と前置きしつつ、Goのhttpサーバーとして動かす部分は『go-chi/chi』を活用していると紹介します。

河津さん:『go-chi/chi』はhttpでリクエストを受ける段階で前さばきをしてパフォーマンスを出せるミドルウェア。最初に試して今でも採用しています。CI/CDの部分は『GitHub Actions』でアクションを書いています。

メルカリUSでもフレームワークやアーキテクチャの試行錯誤を重ねてきたそうです。

四方田さん:社内において、『Revel』で書かれていたAPIを書き直したということがありました。

あと以前レイヤーを切りすぎたアーキテクチャを組んだ結果、やりすぎだと思って薄くした経験があります。

レイヤーを切りすぎると、最初にリクエストを受け取ったパラメーターからの詰め替えが多数発生し、バグが起こりやすくなる。やりたいことに対して「そこまでレイヤーを切る必要はないのでは?」を問い直す重要性は感じますね。

シンプルかつ柔軟さを兼ね備えたGoの良さ、他言語との違い

採用理由や活用したフレームワークを踏まえ、それぞれがGoで開発して感じるメリットを共有します。

河津さんは「シンプルに記述できる言語であること」に言及します。

河津さん:必ずしもGoだけの特性ではないのですが「見ればわかる」ことは大きなメリットです。複雑なコードベースをすべて理解していなくても、今書こうとしているユースケースやレイヤリングの見通しが効きます。

また、私たちは小さなマイクロサービスとしてアプリケーションを沢山作っているので、試してみて良ければAPIを残し、ダメなら別のものと変える…..といった新陳代謝を大切にしています。それを回しやすいのも、Goとマイクロサービスで作ったからこそだと思っています。

四方田さんも「一定コードが読めるようになるまでのコストが少ない」と言語特性を挙げつつ、RubyやJavascript、Typescriptを書いてきたからこそ感じた違いにも触れました。

四方田さん:Rubyだとスマートにメタプログラミングができる一方、言語への理解が浅いとライブラリの中身が追いづらい場合があると感じています。一方、Goでは実際に中まで読んでバグを発見する、低レイヤーのミドルウェアのコードを読むといったことがやりやすい。

また、言語を一定理解してOSSに貢献できるレベルに達するまでにかかるコストも小さかったように思います。

メリットがいくつも上がったところで、あえて苦労した点を佐藤が聞くと、河津さんはエラーハンドリングに言及します。

河津さん:一日のうち何回「if err != nil {}」を書くのかとか(笑)一定の泥臭さは否めないと感じます。コードの記述量が増えるのはGoの特徴です。

そういえば弊社のエンジニアが、タッチバーをクリックして「if error != null」を出せるものを開発していましたので、よかったら見てみてください。

参考記事:golangのif err != nil {}面倒だと言ったな?
四方田さんは「認知度は高まっているが、書ける人はなかなか少ない」ため、採用はまだまだ難しいと語ります。

一方で「言語仕様のシンプルさは、バックグラウンドのない人がプロダクションレディなコードを書くうえではメリットになり得る」とつけ加えました。

イベント後半では参加者からも多数の質問がありました。「Goの実行速度は速いのでしょうか?」という質問から言語の特性について盛り上がりました。

河津さん:実行速度はビルドする対象によって変わる印象です。コンテナをビルドしてデプロイし、走り出すという部分では、非常に早いと感じます。クイックでフレキシビリティがあるなと。

四方田さん:私も同じくビルドやスピンアップも速い印象です。またGoだとマルチコアのCPUに効率よくスケジューリングできるので、並行処理を書くときも速度は出しやすいと思います。

佐藤が「逆に使っていてGoではなくてもいいかも」と思う場面があるかと聞くと、四方田さんは「小さいスクリプトとかはGoだとtoo muchな感じがします」と教えてくれました。

四方田さん:GoだとJSONのバリューが動的な型のときに大変なので、そういった小さい部分は動的な言語で処理するのもいいかなと思います。

河津さんも「小さいスクリプトを書くときにGoで書くかを迷うことがある」と頷いていました。

「言語のここが改善されてほしい」があるかについて、河津さんは「特に強い課題感はなく、今のシンプルさや柔軟さを兼ね備えた状態で、正常に進化してほしい」と語ります。

四方田さんも同意しつつ、Rustとの違いに言及します。

四方田さん:組織で開発するときにどうかは別の議論ですが、個人としてはもう少し言語仕様がリッチになると嬉しいですね。例えば、RustのResultのハンドリングみたいなものがあると、不要なエラーハンドリングが減るのでいいなと。

Rustは型を拡張したり、マクロを使ったりすることで柔軟な処理ができるライブラリがあって便利だと感じます。。だからこそ覚えることが多い。一方、Goは全部愚直にやる必要があるのですが、とっつきやすい。両方良い面、悪い面があるなと思います。

河津さんもPHPの経験が長く「関数がない、車輪の再発明をしている感はある」と語ります。

“愚直にやる”部分の効率化、更に綺麗なマイクロサービスを目指して

イベント後半では二人が今後どのような設計を作っていきたいのか、展望を語っていただきました。

河津さんは「愚直にやっているところを効率化してスマートにしていきたい」と言います。

河津さん:現状『Cloud Spanner』でRead / Writeして返すといった実装が多いのですが。ちゃんと適切なキャッシュを挟むとか、全体的なトラフィックを削減していく仕組みを作っていきたいです。

また、インフラに乗っている顧客向けのリッチな機能にもフォーカスしていきたいと思います。

コストの抑制やトラフィックの適正化、アプリケーションの開発を両立していきたいですね。

四方田さんは「マイクロサービスのアンチパターン的な実装を減らしていきたい」と言います。

四方田さん:機能開発のスピードが上がったこととのトレードオフなので、一概に悪いわけではないと捉えてはいます。ですが、複数のサービスが同一のDBを見ているなどは少なからずあるので、より綺麗にマイクロサービス化していきたいです。

Goの文脈でいくと、メルカリUSでも2017年くらいからGoを使い始めてナレッジも溜まり始めています。今ならより良い形で書けるコードもあるので、地道に改善していきたいですね。

Findyでは、GoやRustなど注目の技術にまつわるイベントを定期的に開催しています。ぜひイベント情報をチェックしてみてください。
https://findy.connpass.com/

また、Findyでは、Goを採用している企業の求人を特集しています。 7社の求人が掲載。 「実務でGoを使いたい!」という方はぜひチェックして、気になる求人には「いいかも」してみてくださいね。
https://findy-code.io/pick-up/articles/golang-beginner ​​