自己紹介
はじめまして、立命館大学情報理工学研究科修士1年のQU BINGXINと申します。普段はアドホックネットワークについて研究しています。
今回参加させていただいた就業型インターンでは、LINEスキマニの開発チームでサーバーサイド開発を担当させていただきました。
LINEスキマニとは?
利用者の「ちょっとした隙間時間」「スキル」「好きな仕事」という3つの「スキ」を「お金(money)」に変える世界観をユーザーに提供すべく、2021年3月にリリースした単発雇用のマッチングサービスです。利用者は自分の経験・スキルに合った求人を探して応募し、企業とマッチングすると、書類選考や面接なしでその店舗で働くことができます。
タスクの説明
LINEスキマニのサーバーサイド開発ではKotlin+Spring Bootが使われています。Server-Side Kotlin は初めて開発することになりました。Spring Boot は Web-Application-Framework であり、実際インターンの期間中の約一週間はSpring Bootの基本的な使い方について勉強しました。
今回私が取り組んだタスクは主に二つありました:
- イベントを処理するサンプル実装の作成 (Producer, Consumer)
- 上記を使い、構成を少し変えた場合のパフォーマンス変化を検証
Decatonを説明する前に、ベースとなったKafkaについても説明します。
Kafkaとは
Kafkaは大規模なデータを処理するための分散メッセージングシステムです。最初はLinkedin社で開発されましたが、そのあとApache Software Foundationに寄贈され、オープンソースとなりました。
Decatonとは
Kafkaが開発された当初はストリームを扱う機能がありませんでしたが、後に公式ライブラリであるKafka Streamsが追加されました。しかしKafka Streamsでは膨大なメッセージを処理する必要があるLINE社内のニーズを完全に満たすことができていませんでした。
そのため、Kafkaをベースに効率的にメッセージ処理を行うことができるDecatonというライブラリが開発されました。
Decatonは順序保証をPatition単位ではなくKey単位としているため、一つのKafkaパーティションを複数のスレッドで同時に処理することができるように設計されています。そのため、大量のメッセージを高速に処理する必要があるようなケースにおいては、Kafka Streamsに対して特に優位性があります。
参考 : Kafkaを利用したジョブキューライブラリ「Decaton」の活用事例
実装
以下、今回取り組んだタスクで実装したモジュールについて説明します。
Decaton-Producer
リクエスト数を応じて、Messaging APIをコールするタスクを生成し、Kafka Brokerに通知するためのモジュールです。
Decaton-Consumer
Kafka Brokerからメッセージを取得して、同期処理でMessaging APIをコールするモジュールです。
なお、今回はサンプルを使ってパフォーマンス検証することが目的だったため、Messaging APIをSleepで代用しました。
タスクのシリアライズとデシリアライズにはProtobufを採用しました。
パフォーマンステスト
LINEスキマニではユーザのあるアクションをトリガーに、メッセージを送信するような状況が多くあります。
LINE社内のAPIを叩くような処理は現在同一アプリケーション内の別スレッドにて非同期処理で行っていますが、スレッドプールには上限が存在し、高トラフィックの場合にはスレッドが枯渇しパフォーマンスが頭打ちになるおそれがあります。
当然ながら同期処理で行った場合には、APIへの呼び出しを待ち合わせるためにシステム全体に遅延が生じ、ユーザエクスペリエンスを毀損する可能性が高いです。
この問題に対し、Decatonを導入して処理を移譲することでどれだけ性能を担保できるかを直観的に確認するため、パフォーマンステストを行いました。
検証環境
Verdaという、LINEのプライベートクラウドで検証を行いました。
Verdaについての詳細の説明はここでは割愛しますが、幾つかの公開記事があります。
- 「Verda」――LINEが独自に開発したNATサービスの裏側:LINE テクノロジー&エンジニアリング大全
- 【Team & Project】Meet the Team Developing the Verda Platform Using OpenStack and Kubernetes - LINE ENGINEERING
検証パターン
検証パターンは4つに分かれています。それぞれのパターンで回数を増やしつつリクエストを行い、所要処理時間を記録します。
パターン1
リクエストを同期で処理します。
パターン2
リクエストをDecaton-Producerでタスクを生成して、Decaton-Consumer側の1個のConsumerが処理します。KafkaのPartitionが1個存在しています。スレッド数を1に設定します。
パターン3
リクエストをDecaton-Producerでタスクを生成して、Decaton-Consumer側の1個のConsumerが処理します。KafkaのPartitionが1個存在しています。スレッド数を3に設定します。
パターン4
リクエストをDecaton-Producerでタスクを生成して、Decaton-Consumer側の3個のConsumerが処理します。KafkaのPartitionが3個存在しています。スレッド数を1に設定します。
Apache KafkaとDecatonの仕様上、並列処理数が Consumer数 × スレッド数になっています。よって、パターン3とパターン4両方の並列処理数も同じく3になります。
予想結果
パターン1とパターン2の処理時間は差がほぼ出ないと予想しています。
パターン3の場合に比べて、パターン4の場合はKafka Brokerと通信する必要があるため、遅くなると予想しています。
検証結果
パターン1はリクエスト数200回以上の場合、Timeoutのため測定不能でした。
パターン3とパターン4はリクエスト数によって異なる結果が出ました:
- リクエスト回数2000回以下の場合パターン3がパターン4より所要処理時間が少なかったです。
- リクエスト回数2000回から4400回までパターン4がパターン3より所要処理時間が少なかったです。
- リクエスト回数が4400回以上の場合、パターン3がパターン4より所要処理時間が少なかったです。
考察
パターン3とパターン4実際の検証結果の一部が予想結果と違うことについて、以下の仮説を立てました:
- リクエスト回数2000回以下の場合、パターン3がパターン4より早い理由はパターン3はパターン4に比べてKafka Brokerとの通信回数が少ないからだと思われます。
- リクエスト回数2000回から4400回まででは、パターン4がより多くのリソースを得ることができ、Kafka Brokerとの通信のコストを含めてもなお効率がパターン3より上回る。これが、この場合パターン4がパターン3より早い原因になっています。
- リクエスト回数が4400回以上の場合、パターン4がパターン3よりリソースを得ているものの、通信のコストがより大きくなっています。結果的に効率がパターン3より劣り、処理時間も遅くなっています。
今回は時間の関係上、残念ながらより深く検証することができませんでした。今後、この仮説が正しいかどうかの検証、そして異なるConsumer数とスレッド数と効率の転換点の関係性の調査を課題にしていきたいと思います。
その他
出社について
今回は基本リモート形式でインターンシップが行われました。オフィスへの出社自体は可能ですが、私が住んでいる滋賀県から福岡県までがあまりにも遠いので残念ながら結局出社できませんでした。(人より背の高いブラウンの写真を撮りたかったです)
チーム内での交流
毎日30分くらいメンターと1 on 1ミーティングがあります。内容は自由で、開発について話すときもあれば、雑談で終わるときもあります。
他にもオンライン飲み会が行われました。違う年代かつ外国人である私は飲み会で出る話題がよく分からない時もありましたが、楽しかったです。特にレトロな話になったとき盛り上がりました。
インターン生の交流会
私のインターンシップ期間では一度だけ参加しました。同年代のほかの大学の学生たちと交流できる貴重な機会でした。皆さんの大学(院)での研究も面白かったです。
インターンの感想
以前にアルバイトで開発したことがありますが、その時は私一人で開発全般担当、かつ小規模なシステムだったので、今回のインターンではチームで大規模なシステムに新しい機能を追加するというかつてない貴重な経験を得ることができました。
本文の冒頭で書いたとおり、私はこれまでKotlinでのクライアントサイド開発経験はありましたが、Kotlinでのサーバーサイド開発経験は全くなかったと言っても過言ではありません。実際、インターンでは毎日新しいものと直面していました。以下、今回インターンで扱ったこれまで使った経験のないものの一部です。
- Spring Boot
- Apache Kafka
- Decaton
- Docker
- Drone CI
- Kubernetes
- ・・・
その中でも特に、デプロイ関係(Docker、Drone CI、Kubernetes)の設定周りで苦労していました。
リモートワークであっても、SlackとZoomでメンターと先輩たちと簡単に相談できる環境でした。コードを他人にレビューしてもらうという経験が初めてということもあって、チームメンバーたちとの交流を通じて普段の開発で意識したことのない問題も指摘してくれました。彼らなしに、私が最後まで業務を行えることはできませんでした。
インターンが始まる前は、6週間は長いと思っていたのですが、本当にあっという間でした。分からないものが多すぎて大変ではありましたが、新しい知見を学ぶことができるのもまた、新しいことをチャレンジする醍醐味です。そこで得た大事な知識と経験を肝に銘じて、今後の開発で活用していきたいと思います。