LINEヤフー Tech Blog

LINEヤフー株式会社のサービスを支える、技術・開発文化を発信しています。

LINE公式アカウントチームのバックエンド開発に関わった話(インターンレポート)

はじめに

こんにちは。東京大学大学院情報理工学系研究科修士2年の東大樹です。

8月13日から4週間、LINEヤフー株式会社の就業型インターンに参加させていただきました。本インターンでは、ビジネスPF開発本部にジョインさせていただきました。私が配属されたチームでは LINE公式アカウントのサーバーサイドの開発を行っています。

本記事では、実際にインターン内で行った業務や感想について書いていきたいと思います。今回、メインタスクとしては社内用ツールへの機能追加に取り組み、インターン期間内で QA を行っていただいて本番環境へのリリースというとこまで行くことができました。そのほかにもいくつかサブタスクに取り組ませていただいたので、それについても紹介できたらと思っています。

LINE公式アカウントとは

LINE公式アカウント(Official Account, OA)は、LINE 上に企業や店舗がアカウントを作成し、友だち追加してくれたユーザーに対して情報を発信するサービスです。また、比較的新しい機能としてLINE公式アカウントにはメンバーシップという機能があります。これは、LINE公式アカウントがプランをいくつか設定して公開することで、ユーザーが月額のサブスク制でさまざまな特典を受け取れるというものです。メンバーシップは、次のLINE公式アカウントの管理画面(LINE Official Account Manager, OA CMS)を通じて設定されます。

LINE Official Account Manager のメンバーシップ機能の画面

私が配属されたチームは、この OA CMS を主に開発しています。LINE公式アカウントはクーポン、ショッピング、LINE VOOM などさまざまなファミリーサービスと連携しているため、社外(フロントエンド)に対しての API だけでなく、社内に対しての API の作成なども必要となります。このような背景から私が配属されたチームが開発するものは多岐にわたります。

メインタスク

今回メインタスクとして、メンバーシップ機能を運用しやすくするための社内ツールを開発しました。具体的には、ユーザーのメンバーシップ加入状況を確認でき、さらにユーザーのメンバーシップの課金状況を停止・再開できるようにするページを、社内ツール基盤上に作ることに取り組みました。

今回、私はフロント(Vue)とバックエンド(Kotlin)の両方を実装しました。特にバックエンドの方では、設計の部分から実装、テストまでひととおりのことを体験させてもらいました。具体的に実装した画面は以下のようになっています。ユーザーのIDや支払いのIDを用いて、メンバーシップの加入状況を見れたり、課金状況を停止・再開できるようになっています。

開発したメンバーシップ機能の運用ツールの画面

今回難しかったこととしては、主に決済周りの処理について理解することでした。どのタイミングで決済が行われるかや、決済が済んだ後のデータベースの更新などが複雑になっていて難しかったです。また今回直接触ってはいないのですが、決済に関して App Store / Google Play / Web決済 の場合があり、それらに対応するのが難しそうだなという印象を受けました。

本実装では決済回りなどビジネスにおいて重要な部分に触るため、意図しない挙動が起きたときのためにすぐに前の状態に戻せるようにすることが大切です。LINE のサービスでは、そのような設定を中央集権的に管理するために、Central Dogmaという OSS を開発しています。Central Dogma を用いると、アプリケーションやコンテナイメージの再ビルドやデプロイなしで設定の動的変更ができます。これは、デプロイ後に変更を巻き戻したり、各種設定値を変えたいといった場合に特に有効です。今回、この Central Dogma においてフラグを管理して、何か問題が起きたときはすぐに戻せるように実装しました。

上記のことに加えて、データベースのマイグレーションや効率的なインデックスの貼り方、例外処理、基本的なAPIの実装の仕方など幅広いことを学べました。

このタスクは、最初の2週間で実装した後に、QA さん方が QA を行ってくださり、最終的にインターン期間内に本番環境にリリースできました。実際に QA さんに意見をいただいたりバグの報告をいただけたりして、エンジニアとして安心して開発に臨める環境であると感じました。

サブタスク

メインタスクが終わった後、いくつかサブタスクに取り組みました。普段なかなか触れることのできない、サービス間の連携や、可視化・運用に興味があるという希望を聞いてくださり、以下のようなタスクに取り組ませていただきました。

  • Kafka に余計にイベントを送信している部分の削除
  • MySQL のクエリの監視
  • Argo Rollouts Dashboard の導入

ここからは各タスクについて軽く紹介したいと思います。

Kafka に余計にイベントを送信している部分の削除

マイクロサービスアーキテクチャでは、各サービスがそれぞれでデータベースを持つことが多いです。そして、データベースの同期は API を通して行います。こうすることで、それぞれのサービスが一つのデータベースに依存する形ではなくなり、アプリケーションが疎結合になるという利点があります。ここで、サービス間でのデータベースの整合性を取るために、データベースの中身が変わったという情報を他のサービスに伝えてあげる仕組みを作る必要があります。例えばLINE公式アカウントのサービスにおいては、OA CMS 側でアカウントの名前やステータスが変わった際に、各ファミリーサービスがその変更を知る必要があります。

LINEでは、そのようなサービス間の通信のために Apache Kafka を採用しています [参考]。Apache Kafka とは Pub/Sub メッセージングモデルの一つで、オープンソースの分散型イベントストリーミングプラットフォームです。Pub/Sub メッセージングモデルは、非同期メッセージングパラダイムの1つであり、メッセージの送信者(出版側)が特定の受信者(購読側)を想定せずにメッセージを送るようプログラムされたものとなっています。今回の場合は、LINE公式アカウントのサーバー側で変化があった際に、Kafka のイベントを送信します。それによって、そのトピックを受信しているファミリーサービス側が変化を察知して、LINE公式アカウントの API を通してデータベースを更新できるようになっています。

本タスクでは、LINE公式アカウントのサーバー側で余計にイベントを送信している部分があったので、そこを廃止するということに取り組みました。具体的には、API のアクセスがあると、API自身でイベントを送信すると同時に、データベースの変更をフックとしてイベントを送信するという、二重でイベントを送信する形になっていました(下図の produce event の矢印)。そのため、本タスクでは、データベースの変更によって正しくイベントを送信できていることを確認した上で、API 側のイベントの送信を削除しました。今回も、イベントを正しく送信することはファミリーサービスに変化を通達する上で大切なので、Central Dogma を用いてすぐに戻せるように実装しました。

OA とファミリーサービス間の連携

ちなみに、後者のデータベースの変更によってイベントを送信する方法は CDC(Change Data Capture)を利用するものになります。CDC とは、データベースの変化を監視しそれをフックにさまざまなことができるというものです。パブリッククラウドが提供するデータベースサービスなどでは、だいたいこういった仕組みが標準装備されています。

本アプリケーションでは Debezium を用いて CDC を行っていて、その変更があるたびに Kafka でイベントを送信してファミリーサービスに変化を通達しています。

もしマイクロサービスにおけるデータ共有・同期方法に興味がある方はこちらに素晴らしい記事があるので読んでみてください。

MySQL のクエリの監視

アプリケーションが MySQL に対して実行したクエリの指標をメトリクスとして収集して、Grafana 上に可視化するということに取り組みました。MySQL へのアクセスライブラリには MyBatis を採用していたため、MyBatis のインターセプタを実装しました。インターセプタで収集したメトリクスは、あらかじめ構築されている Prometheus サーバーが収集しに来るため、Grafana から見ることができるようになります。ちなみに Kotlin + Spring Boot 環境におけるメトリクスの取り方に関してはこの記事が大変参考になると思います。

可視化に関わる中で、Prometheus サーバーがメトリクスを自動的に収集しに来る部分がすごいなと思いました。Kubernetes 上で動いているアプリケーション(Pod)は起動するたびにIPアドレスが変わってしまうという問題があります。また、Prometheus サーバーは社内共通基盤で、Kubernetes のクラスタ外からアクセスしてくるため、そのままでは Pod に到達できません。これらの問題は、Prometheus からのリクエストをプロキシする内製のアプリケーションにより解決されていました。

Argo Rollouts Dashboard の導入

OA CMS のサーバーは Kubernetes 上で動作しており、Argo Rollouts を使ったカナリアリリースを採用しています。しかし、次のような状況に対しての運用が十分整備できていないという課題がありました。

  • カナリア(新しいバージョン)に問題があったので、すぐにロールアウトを中断したい。
  • 緊急の hotfix を当てるために、カナリアリリースの待機時間をスキップしたい。

もし Argo Rollouts Dashboard があれば、これらの課題に対して Web UI 上から Abort や Promote のボタンを押すだけで対応できます。もともと開発環境にはすでに Argo Rollouts Dashboard が導入されていたのですが、そもそも上記ニーズは本番環境特有のものなので、本番環境にも導入したいという要望がありました。

Argo Rollouts や Argo Rollouts Dashboard の導入は基本的には Argo Rollouts の GitHub 上にある yaml ファイルを用いました。今回はすでに開発環境の方で実装されていたので新しく実装することは少なかったのですが、Kubernetes 全般について触れながら勉強できてとてもいい機会となりました。また、Kustomize を用いた管理が行われていたのですが、共通化によって重複した実装が抑えられて便利だなと感じました。

最終的に以下のように無事ダッシュボードが見られるというところまで確認しました。

Argo Rollouts Dashboard の画面

インターンの感想

優秀な社員さんに囲まれて業務に就かせてもらって、すごく学びの多い経験をさせていただきました。実際に働く中で、内製のソフトや OSS が多く会社としての力というものを感じることができました。また、会社全体としての動きの早さというのも感じました。例えば、GitHub Copilot for Business が全社で導入されていたり、ChatGPT が 内製のアプリケーションとして実装されています。このような動きの早さは、エンジニアとしての働きやすさだけでなく、セキュリティ的な観点でも大きなメリットがあると感じました。これは、例えば社員が好き勝手に個人でこういったツールを使うと内部情報が漏れてしまう恐れがあるためです。

また、すごくグローバルな会社であることを感じました。例えば、他の国の支部の人たちと働く機会があったり、日本国内でもドキュメントやコミュニケーションが英語であるチームが存在したり、そういった環境で働くことができるというのも魅力的だなと感じました。

終わりに

インターン期間中は、チームの人にものすごくお世話になりました。PR や Slack 上ですぐにコメントをくださったり、デプロイ作業などを一緒に行っていただけたりしてとても助けてもらいました。コメントも、適切な言い回しと指摘内容で、とても心理的安全性が高いチームだと感じました。同じことを指摘していても言葉遣いで受け手側の印象が大きく変わることを実感したので、これからはそういったことにより気をつけていきたいなと思いました。また、特にメンションせずとも PR や Slack 上でフラっと現れて参考になるコメントをいただくことが多く、チームの方々のそういった優秀さに震えていました。その中でも特にメンターとマネージャーの方にはすごくお世話になりました。各タスクについて詳細に説明してくださったり、困ったときに毎回助けていただいたおかげで、4週間という短い期間でも多くのタスクに取り組むことができました。1on1などでフラットに話せる機会も多く設けていただいて、技術的なことからキャリアについてまで多くのお話を伺うことができました。

とても有意義なインターンを経験することができました。本当にありがとうございました。