applepie-umai / SpringFest2019

0 stars 0 forks source link

dup #16

Closed yoshidaki closed 4 years ago

yoshidaki commented 4 years ago

[LINE公式アカウントのチャットシステムにおけるSpringおよびWebFluxの活用事例]

概要

このセッションに関連するキーワード

セッションの内容

話の流れ

LINE公式アカウントとは企業/事業者向けに開設可能なLINEアカウントである。 ブロードキャストやターゲティング配信などの機能を有しており、一般ユーザ向けのチャットシステムとは異なる「LINEチャット」を利用してLINE公式アカウントと一般ユーザがチャットできる。

チャットシステムとして「LINEチャット」に求められるものは以下のものである。

リアルタイム通信

リアルタイム通信の実現については、検討時期にはPolling、Long Polling、Server Sent Events(SSE)、WebSocketの4択となっていたが、SSEを採用することにした。 また、採用したSpring WebFluxはNon BlockingなWebフレームワークである。 1Request=1ThreadなServlet APIと異なり、1つのEvent Loop Treadで複数のRequestをさばけることから、サーバ台数を削減できる狙いがあった。

ユーザ操作起因のコアビジネスロジック

ユーザ操作起因のコアビジネスロジックの実現については、Spring WebMVCを採用した。 開発時期がSpring Boot 2.0.0.M1だったということもあったが、いきなりSpring WebFluxを全適用するのではなく、小さくて確実に向いているコンポーネントから試していこうという判断があった。

LINEユーザが送信した画像・動画・音声の取得

LINEユーザが送信した画像・動画・音声の取得については、Spring WebFluxを採用した。 画像・動画・音声ファイルは社内CDNにあり、認証等の事情によりアカウントオーナーにアクセスさせるにはProxyを掛ける必要があったが、Spring WebFluxのContent Proxyによりスレッドを占有することなくProxyを掛けることができた。

以下は開発時に困った点やノウハウのTips

Netty OOMEの発生(Nettyに報告・改修確認済)

WebFlux Clientを用いたコードでAPI callのtimeoutが大量に発生するとOutOfMemoryError(OOME)でサーバが落ちることがあった。 NettyのReadTimeoutExceptionがシングルトンであったため、ReadTimeoutExceptionが保持しているsuppressedExceptions(List)が肥大化してOOMEが発生した。 現在はIssueを起票して修正済である。

参考:

https://github.com/netty/netty/pull/9152

Blocking DNS Resolver

Reactor NettyではInetSocketAddressを使ったBlocking DNS Resolverを使用しているので、NettyのNon-Blocking DNS Resolverを使うように変更する必要がある。 また、ごくまれにTreadがハングしてしまう現象があったためIssueを起票済。(現在0.10.x向けBacklog) また、デフォルトをNon-Blocking DNS Resolverとする案もReactor Nettyに上がっている。

参考:

https://github.com/reactor/reactor-netty/issues/710
https://github.com/reactor/reactor-netty/issues/569

Reactor hooks with MDC

ServletのようにMDCにRequest情報を渡してログに出力させたかったがWebFluxのEvent Loop Threadと相性が悪かった。 WebFilter、Reactor Context、Hooksを活用して何とか実現した。

BlockHound

BlockHoundはNon BlockingスレッドにおけるBlockingコールを検出してくれるJavaエージェント。 あまり日本語で言及されている記事を見かけなかったので紹介。 GradleやMavenで依存関係に追加し、テストケースにてBlockHoundを有効化しておくと、テストケース実行時にBlockingコール発生部分でErrorを出力してくれる。 しばしば予期しないBlockingコールもあり、コードレビューで漏れることがあるので導入をお勧めする。

考察したこと

講義資料URL

https://speakerdeck.com/line_developers/examples-of-using-spring-and-webflux-in-the-chat-system-for-line-official-accounts