LINEヤフー Tech Blog

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

Kafka×Decatonで80並列化した通知基盤(インターンレポート)

こんにちは。東京電機大学理工学部情報システムデザイン学系4年の佐藤聖璃です。

8月18日から8週間、LINEヤフー株式会社の就業型インターンに参加させていただきました。私はLINEスキマニのサーバーサイドの機能開発にジョインさせていただきました。

本レポートでは、私がインターン期間中に取り組んだ内容、成果についてご紹介します。

LINEスキマニ

LINEスキマニは、LINEヤフー株式会社が運営する単発雇用マッチングサービスです。利用者は、すぐに働ける単発の求人案件を探せるので、「急に予定がなくなった」「数時間だけ空いている」そんな空き時間を有効活用できるのが特徴です。

LINEスキマニ画像

取り組んだタスク

インターン期間中は、主に以下の2つのタスクに取り組みました。

  • 求人情報へ天気情報の追加
  • プッシュ通知のパフォーマンス改善

求人情報へ天気情報の追加

就業日当日の天候は、誰もが気になるポイントだと思います。

LINEヤフーには社内にYahoo!天気・災害というサービスがあり、この社内APIを利用することで求人情報に天気情報を掲載する機能を開発しました。これにより、通勤経路や通勤時間の調整、持ち物や心構えの準備など、ワーカーの方に不安無く応募いただける機能提供ができたのではないかと思います。

また、旧LINE社内の環境からYahoo!天気・災害のAPIを内部的に呼び出したのは、スキマニが初の試みでした。

LINEスキマニ天気画像

社内APIの呼び出しには Athenz という社内の認可ライブラリによる認証が必要です。

Athenz は、旧Yahoo! Inc.にて開発されたOSSとして公開している 認証・認可システム で、アプリケーション間のAPI認証・認可の基盤システムに使われています。

今回の開発では Athenz の設定を行い、スキマニのサーバーからYahoo!天気・災害のAPIを安全に呼び出せる仕組みを構築しました。

参考:https://developer.yahoo.co.jp/oss/athenz/

プッシュ通知のパフォーマンス改善

背景・課題

従来のバッチ処理によるプッシュ通知

LINEスキマニにおけるプッシュ通知は、Firebase Cloud Messaging(FCM)を利用してモバイル端末へ配信していました。その処理は Spring BatchのJobとして構築され、以下のような流れで実行されていました。

  1. Job開始
    • 通知送信処理を開始
  2. Step(プッシュ通知送信)
    • 通知対象を取得し、WriterがChunk単位でまとめてFCMへ送信。
  3. Chunk処理
    • TaskExecutor を利用して最大50並列でFCMリクエストを送信。
    • ただし、Chunk内のすべての送信が完了するまで待機する仕組み。
  4. ログ記録
    • 通知結果(成功・失敗)をログに記録し、Chunkを完了。

AsIsプッシュ通知処理画像

現状の問題点

  • バッチ処理依存による処理時間の肥大化
    • ChunkごとにFCM送信処理の完了を待つ構造のため、Step全体の処理が遅延し、結果としてJob全体の実行時間が長引いていました。通知件数が数十万件規模になるようなピークタイムでは、1回のJobに 30分以上かかるケースもありました。
  • 即時性の欠如
    • Step全体の処理が遅延することは、ユーザーによって通知の到達タイミングにばらつきが生じることも意味します。即時性が求められるプッシュ通知において大きな問題でした。
  • リトライ機構の欠如
    • FCM API送信が失敗した場合でも、個別のメッセージ再送を制御する仕組みが存在していませんでした。そのため、一時的なネットワーク障害やFCM側の不具合によって通知が失われるリスクが高く、確実な配信保証が実現できていませんでした。

改善が必要な理由

プッシュ通知は「利用者に素早く確実に届けられるか」がサービス体験の面で大切です。

現状のバッチ依存型の仕組みでは、即時性・安定性・信頼性の観点で限界が見えており、今後のユーザー数や通知件数の増加に対応するためには、Jobの実行時間を短縮し、非同期かつ分散処理可能でリトライ制御を備えたアーキテクチャへの移行が考えられました。

解決策

従来のバッチ依存型の仕組みを改め、プッシュ通知は Kafka + Decaton を利用した分散処理へ移行しました。

Kafkaとは

Apache Kafkaは、分散型のメッセージングシステムです。 複数のプロデューサから受け取ったイベントをトピックとして保持し、複数のコンシューマが並列かつ独立に処理できる仕組みを持ちます。

  • 高い耐障害性
    • データを複数ブローカーにレプリケーションし、障害時も継続可能。
  • 高スループット
    • パーティション分割により、並列処理を効率的に実現。

プッシュ通知システムにおいては、バッチからの通知リクエストをKafkaに投入することで、「送信要求の記録」と「送信処理」の責務を分離でき、Jobの実行時間短縮、配信信頼性の向上を両立できます。

Decatonとは

Decatonは、LINEヤフーが開発・公開している Kafkaタスク処理ライブラリです。Kafkaのコンシューマとして動作しつつ、大規模なメッセージ処理を安定的に行うための機能を備えています。

  • 効率的にJobを処理
    • Kafka パーティションを複数のスレッドで同時に処理が可能。
  • リトライ処理
    • Decatonは内部的にリトライ用トピックを管理し、開発者が個別のリトライロジックの実装は不要。

参考:https://engineering.linecorp.com/ja/blog/decaton-case-studies

Kafka+Decatonによる処理方式

ToBeプッシュ通知処理画像

  • 処理方式
    • Kafkaトピックを 8パーティション に分割し、各パーティションを最大 10並列で処理することで、合計最大 80並列処理を実現しました。これにより、従来のバッチ内の並列度50を超える高スループットが可能となり、特にピークタイム時の効果を期待できます。 また、将来的に並列度を上げたい場合でも、容易にチューニングが可能と柔軟な拡張性を実現しています。
  • 待機時間の短縮
    • Jobは「通知送信リクエストをKafkaに投入」した時点で完了できます。FCM送信の成否に関わらずバッチ処理は即時終了し、Jobの実行時間を大幅に短縮できます。 これにより、デプロイ時に走る Graceful Shutdown において、最大許容時間を超えて強制シャットダウンされてしまうリスクを排除することができます。
  • リトライ処理の追加
    • Decatonのリトライ機構を利用し、FCMからのエラーコードが INTERNAL または UNAVAILABLE の場合に 最大3回まで自動リトライを行うようにしました。これにより、一時的なネットワーク障害やサービス側の不安定性による通知ロスを削減できます。

結果

今回の開発では、本来であれば本番環境のピークタイムでどの程度パフォーマンスを改善できたかを検証したかったのですが、インターン期間中にリリースを見届けることはできませんでした。一方で、開発環境上では以下の成果を確認できました。

  • Job内で完結していた処理の分離
    • FCM送信処理をKafka経由の非同期処理へ切り出すことに成功し、バッチJobの完了をKafka投入時点で終える構成を実現。
  • Kafka経由によるFCMリクエストとレスポンスの確認
    • Kafka経由で投入されたメッセージに対して、Decaton側でFCMリクエストが実行され、FCMからのレスポンスが正常に返却されることを確認しました。これにより、処理の流れが正しく動作していることを確認できました。
  • 構成の柔軟性の確認
    • 今後、実際の通知件数や負荷状況に応じて、パーティション数やコンシューマの並列度を調整することで柔軟にスケールできる設計となっていることを確認。

今後は本番環境でのピークタイムの負荷をもとに、Kafkaのパーティション数・Decatonの並列度などをチューニングすることで、より高いスループットと安定した通知配信の両立が期待されます。

成長できたこと

インターンを通じて、Kafka + Decaton を用いた非同期分散処理の実装を経験しました。

Spring BatchとKafkaを組み合わせることで、Job内で完結していた処理を分離し、FCM送信をKafka経由の非同期処理へ切り出す設計を学びました。また、Decatonを用いたKafkaパーティションのマルチスレッド処理やリトライ制御を通じて、高いスループットを維持しながら信頼性を確保する設計思想を理解することができました。

また、実装を進める中で特に感じたのは、「AS-ISを正確に理解すること」 の重要性です。現状の構造や課題を深く把握せずに改善案を出すと、根本的な問題解決にならないことを、実際のコードリーディングと議論を通じて実感しました。メンターさんが「まず現状を理解し、なぜその構成になっているかを考える」という姿勢を徹底されていたことが印象的で、今後の開発でこの考え方をより大切にしたいと感じました。

おわりに

8週間のインターンを通じて、技術的な学びはもちろん、人として大きく成長できた期間となりました。定例MTGなどを通じて、チーム全体が「より良いサービスを提供する」ために意見を出し合い、一人ひとりがサービスの価値向上に真剣に向き合う姿勢に強く感銘を受けました。

最後に、チームの皆さんの温かいサポートと丁寧なフィードバックに、心より感謝申し上げます。この貴重な経験を糧に、これからも学び続け、より良いサービスづくりに貢献できる人を目指していきます。

メンターからの一言

佐藤さんのメンターを担当した山岸です。

今回のインターンでは Athenz を用いた社内API連携や Kafka/Decaton による処理性能の改善など、難易度の高い開発課題に挑戦していただきました。短期間でキャッチアップし、自走して着実にやり切ってくれました。

明るい人柄で、チームとして一緒に働いていてとても楽しかったです。難しい課題に対しても「ワクワクしますね」と前向きに学び、主体的に取り組む姿勢がとても印象的でした。

私自身も多くの学びがありました。またご一緒できる日を楽しみにしています!