データ解析で得られた知見

庄司久人氏:「プッシュ通知到達率100パーセントを目指して−データ解析で得られた知見」として発表いたします。

本日のアジェンダですが、最初に簡単にアプリの紹介をした後、ログ収集とデータ解析について、その後ドッグフーディングについて話して、最後にまとめをお話しします。

最初に自己紹介しますと、庄司久人と申します。LINE B2Bアプリ開発チームでエンジニアリングマネージャーをしています。担当領域は2つありまして、LINE公式アカウントというアプリのiOS・Android開発と、それからLINEアプリの中でのLINE公式アカウント関連の機能開発をしています。本日は前者のLINE公式アカウントアプリについて、お話しします。

本日のセッションですが、主にiOS・Androidアプリの開発に関わっているiOS・Androidエンジニアの方やPM、企画、QAの方などを対象として想定しています。

概要としては、LINE公式アカウントアプリの開発でデータの収集や解析、あるいはドッグフーディングを利用してアプリの通知問題について、どのようにアプローチしたのかを事例紹介します。アプリの開発に関わっているみなさんの、開発方法や通知問題の解析のヒントになれば幸いです。

「LINE公式アカウント」とは

さて、最初にLINE公式アカウントを簡単に紹介します。B2B2Cのプロダクトで、主に企業のユーザーの方が、LINEユーザーとチャットでコミュニケーションするためのサービスです。多くの企業ユーザーに利用してもらっているだけではなく、LINEの提供しているサービス、例えばLINEマンガだったり出前館でも利用されています。LINEを使っていれば「見たことがある」っていう方が多いのではないかなと思います。サービスとしては、グローバルで展開していて、1,000万を超えるアカウントが開設・展開されています。

LINE公式アカウントはB2B2Cのサービスなので、普通のLINEユーザーはなかなか「企業ユーザーが操作する画面を見たことがある」ということは少ないと思いますが、マルチプラットフォームをサポートしていて、iOS・AndroidアプリだったりPCブラウザ版だったり、あるいはWeb APIも用意しているので、なんらかのバックエンドサーバーとつなぎ込むことによって、API経由でメッセージのやり取りもできます。

iOS・Androidアプリもグローバルで展開をしていて、LINEユーザーのユーザー数に連動するようなかたちで、日本やタイ、台湾やインドネシアでのユーザー数が多くなっています。

Web APIを利用してLINEと連携している大企業のユーザーから、町のお店みたいなところまで、さまざまな業態の方に利用してもらっていると思っています。Web APIやPCブラウザ版もある中で、iOS・Androidアプリの位置付けとしては、主に中小企業の方々が使っていることが多いかな、と思っています。

具体的には、町のレストランや居酒屋、あるいは美容室やヨガ教室みたいなカルチャー教室といった事例が多いかと思います。

メインの機能としては、LINEユーザーとのチャット機能であったり、LINE通話だったり、あるいはクーポンの発行やタイムラインへの投稿だったりです。その中でも実際の利用頻度のデータを見ても、LINEユーザーとのチャット機能の利用比率が高くて、チャット機能がアプリとして重要な要素になっています。

ちなみにスクリーンショットは、後で紹介しますが開発チーム内でのドッグフーディングの様子で、チャットの画面はこんな感じのデザインになっています。

アプリの通知が遅れる・届かない

アプリ開発チームとして開発に取り組む中で、定期的にApp StoreやGoogle Playのレビューコメントを確認したり、あるいはCSでいただいたお客さまのお問い合わせ内容の確認をしたりとか、企画メンバーと合同で、ユーザーインタビューに参加したりしています。

その中で、チャット機能がアプリの重要な機能であるにもかかわらず、iOS・Androidの双方で「アプリの通知が届かない」、あるいは「遅れるよ」といったような指摘を継続的に受けてきました。

我々は当然、アプリ開発中であれば開発者テストをしたり、アプリのリリース前には専任のQA部隊で動作確認のQAを実施しているんです。しかし、レビューで継続的に指摘されているにもかかわらず、開発チームやQAチームの手元ではなかなか問題が再現しない状況が続いてきました。

もしかしたら、アプリを担当したことがある方なら「通知が届かないよ」という指摘を外部から受けた記憶がある方もいるかもしれません。

先ほども述べましたが、我々のアプリはグローバルで展開されているので、もしかしたら海外では何か日本と違う事情があって問題が起きているのではないか、というような疑問も生じたりもするのですが、開発チームもQAチームも日本にいるわけで、議論しても想像の域を出ないのが実情です。

そこで我々のチームでは、ログを収集してデータを解析することにしました。そもそも手元で再現しない問題なので、本当に起きているのか、データでまず確認すべきだと考えました。

また、手元で再現しない問題の場合、もしかしたら修正確認をできないまま「きっとこれで直るはず」というようなパッチを入れる可能性もあります。そういった場合に、リリースの効果を測定するために、データを前後で比較できる必要性があると考えました。

LINE公式アカウントアプリでの通知配信の仕組み

LINEで「アプリの通知配信システムをやっているよ」と聞くと、「何か特殊なことをやっているんじゃないかな」と考える方もいるかもしれないと思ったので、LINE公式アカウントアプリでの通知配信の仕組みを簡単に紹介しておきます。

一番左側に、LINEアプリを使っているユーザーがいて、LINE公式アカウントに話しかけると、LINEのサーバーからLINE公式アカウントのサーバーを経由して、右側の、iOSであればAPNS、AndroidであればFCMのサーバーを通して、通知が各アプリに配信される仕組みになっています。iOS・Androidのアプリであれば、ごくごく一般的な構成かと思います。

特記事項としては、iOSについてはNotificationServiceExtensionを使っています。AndroidのFCMについては、Notification MessageとData Messageの2種類ある中でData Messageのほうを使っていて、JSONをサーバーから送信してアプリ内のFirebaseMessagingServiceでJSONをパースして、通知の文字列を取り出して通知を表示するような仕様になります。

具体的なログの実装ですが、iOS・Androidでアプリで広く利用されているサードパーティ製の有名なSDKがあって、「利用している」という方も多いと思いますが、我々の場合は内製のシステムにログを収集する仕組みを使っています。これによって、例えばサーバー側とのログとの突き合わせがやりやすい環境を実現しています。

iOSについては、先ほどスライドでも軽く触れましたが、Appleのガイドラインに沿うかたちでUNNotificationServiceExtensionを利用して、チャットで送信された画像をダウンロードして通知に表示するっていう仕様があるのですが、その処理に追加するようなかたちで、ログの収集も行なっています。

Androidについては、FCMの仕様に沿ってFirebaseMessagingService内でJSONの処理をしつつ、同時にログを収集しています。

1点注意事項として、ログの収集についてなのですが、社内に情報セキュリティの専任部署がありまして、そのレビューを受けて「プライバシー上問題ない」というかたちで収集を行なっています。

ログの解析

さてログ収集したら、その後解析になるのですが、我々の場合、iOS・Androidエンジニアが解析も行なっています。なぜかというと、社内にはデータサイエンティストの組織もあるのですが、今回の場合、通常のGUIのA/Bテストなどと違って、iOSであればAPNSやNotificationServiceExtensionの動作仕様をちゃんと理解していたり、AndroidであればFCMだったりAndroid Doze、あるいはBackground Restrictionの仕様をそもそもちゃんと理解したりしている必要があります。

iOS・Androidエンジニアの中でも、この仕様を「全部ちゃんと記憶しています」という方はなかなかいないんじゃないかなと思っていて、ドキュメントを確認したり、あるいは動作確認などで確認をしていく必要があると思うのですが、これをデータサイエンティストがちゃんと理解をして解析をするっていうのは、けっこうハードルがあるんじゃないかなと思っています。

また、1度ログを収集してみると、あるあるだと思いますが、別の疑問、あるいは仮説などが出てきて「追加のログを見てみたい」と思うこともあるのではないでしょうか。我々のチームの場合、iOS・Androidエンジニアが収集も解析もしていますので、この部分のサイクルを早く回せるんじゃないかなと考えています。

最後にiOS・Androidの開発チームではあるのですが、「データ解析もおもしろそう」あるいは「データに基づいた開発をぜひやってみたい」というような、興味を持ったメンバーも多かったので、こういったことにもチャレンジしています。

収集できたログ

ではさっそく、収集できたログをお見せします。このグラフは、通知の中でLINE公式アカウントのサーバーのタイムスタンプと、実際にアプリに通知が到達して、処理が完了して通知を表示できた時点でのタイムスタンプの差分が1分以内だった、つまり、ユーザーがチャットで話しかけて、それが実際のLINE公式アカウントアプリの通知として表示されるまでにかかった時間が1分以内だった通知が、通知全体の何パーセントあるかを示したグラフです。数字が下がれば通知が遅延している、ということになります。

本当はヒストグラムなどのほうが正確性が高いのかもしれませんが、この後各地域での比較などを出していくので、プレゼン内でのわかりやすさのために、今回の発表ではこの形式のグラフで今後表示していきます。

注意点として、圏外だったり、電源が切れているっていったこともあるのですが、その後オンラインになると、通知が遅延したとその場合検知されてしまいます。特にiOSでは、こういったパターンの場合は排除する、ということが技術的にできなさそうだったので、グラフとしてはそういった場合のデータも含んでいます。したがって、このデータは最善の状態でも100パーセントにはならない、ということになります。

データをユーザーの地域ごとに確認してみます。左から、日本、台湾、タイ、インドネシアになります。まず、iOSに比べてAndroidの遅延の程度が大きいことがわかりますので、開発チームとして「ではAndroidの調査により注力をしよう」ということで決定しました。

また、先ほど「もしかしたら海外では何か特異の事情があって通知が遅れているのではないか」という想像があった話をしましたが、実際のデータとして、日本や台湾に比べてタイやインドネシアではやはり遅延の割合が大きいことが確認できます。

日本で開発やQAを実施しているので、データを仮に確認していないと、現地のこういった問題に気づけない可能性があると思います。コロナでなければ現地のユーザーや市場調査なども兼ねて、インドネシアに出張に行ってデバッグするのは手ではありますが、残念ながら海外出張などが制限されている情勢なので、データを確認していくことはより重要になってきているかなと思います。

単純にこのグラフだけだと、iOSに比べたらAndroidの品質が悪いように感じたりもしますが、Androidについてより細かく見ていきます。

どの処理の部分が遅れているのか

では、Androidの遅延がどこで起きているかっていうところについて、まずは中身を見ていくことが重要だと思いますので、どの処理の部分が遅れているのかをまず調べてみました。

上からそれぞれ、LINE公式アカウントのサーバーからFCMのサーバーまでにかかった時間、それからFCMのサーバーからAndroidアプリのFirebaseMessagingServiceに到達するまでの時間、そして3つ目がService内でJSONのパーシングをしてNotificationのAPIのコールまでにかかった時間です。

帯グラフにすると真ん中が圧倒的になってしまうので表にしていますが、明らかに真ん中のFCMサーバーからFirebaseMessagingServiceが支配的で、平均で70秒程度かかっています。

FCMのサーバーのタイムスタンプは、Androidアプリにデータが到達した時点で参照可能なRemoteMessageのgetSentTimeというAPIで取得可能でした。

なお、一番下のFirebaseMessagingService内の処理ですが、Googleのガイドライン上は「10秒以上時間かかるような画像などのダウンロードは避けて、一度通知を表示した後、画像のダウンロードをWorkManagerに渡して、画像がダウンロードできた時点で通知をアップデートしてください」っていうような案内があります。

我々のアプリは、実際ガイドラインどおりに実装していて、平均で36ミリ秒ぐらいしかかかっていないので、10秒以内に収まっていそうなため、この部分に関しては少なくとも問題なさそうだ、ということがデータ上も確認できました。

Androidエンジニアの方なら詳しいかもしれませんが、Android DozeモードというのがAndroid 9から搭載された機能で、基本的には電池の持ちを良くするために、ユーザーがスマートフォンを使ってなければCPUの利用を制限するといった機能です。

FCMに対して影響があるかというところは、Android Developersの記載によると、PriorityがHighであれば特に影響はないが、Normalに設定されていると、Dozeモード中はCPU節約のためにすぐには処理されず、ある程度遅延する可能性があると書かれています。

仮にPriorityがNormalに設定されていて、開発者テストやQAで、Dozeモードの確認が漏れていたりすると、市場でユーザーの手元ではDozeの影響で通知が遅延することが起きるかもしれません。

LINE公式アカウントアプリの場合は、チャット機能が通知の即時性を求められるので、FCMのPriorityは、Highに設定されています。

ではHighであれば問題がないかというと、Dozeと一緒に実装されている、App Standby BucketsというAndroid OSの機能があります。ユーザーのアプリの仕様頻度の高いほうから、左側のActive、Working set、Frequent、Rare、Restrictedと、Android OSによって分類されます。

FCMについては、Frequent以下になると1日当たり10件や5件にHigh Priorityのメッセージが制限されて、それ以上送信するとNormal Priorityに下げられます。すると、1つ前のスライドで説明したDozeの影響を受けて、Doze中であれば通知が遅れるといったことになります。

これは、そもそもユーザーにとって利用頻度の低いアプリであれば、そんなにHigh Priorityな通知を受け取る必要はないだろうし、むしろ通知がCPUを起こす頻度を下げて、バッテリーの持ちをよくしようというAndroid OSの機能であって、通知が遅れるのは仕様ということになります。

例えば休眠中のユーザーを掘り起こそうと思って、即時性の高い「タイムセール!30分以内の購入なら15パーセントOFF」みたいなマーケティングの通知は、Androidユーザーには送らないほうがいいかもしれません。通知が届いた時点で、すでに30分以上経っている可能性があるということになります。

LINE公式アカウントでの実データを確認

LINE公式アカウントでの実際のデータを確認してみます。我々のアプリの場合、Restrictedとしてカテゴライズされた状態で通知を受け取ったデータは見受けられなかったので、Active、Working set、Frequent、Rareでの通知遅延具合の比較になります。

Frequent以下の場合は、App Standby Bucketの影響を受けて、1分以内に通知が届く割合が大幅に低下しているのが確認できます。開発中のテストやQAチームでのテストなどの場合は、大概アプリはActiveと判定されていると思われるので、この挙動をマニュアルQAで捕まえるのは仕様を正確に把握していない限り、なかなか難しいのではないかなと思います。

先ほどの各地域のグラフについて、Android側をすべてのApp Standby Bucketを含んだものを一番左側に、App Standby BucketがActiveかWorking setのもののみに絞り込んでのデータを、真ん中に表示しています。

どの地域についても、アプリを頻繁に使っているユーザーであれば基本的に遅延が少なくなる傾向がありますが、インドネシアについてはあまり変化がありません。

これ以外にも、例えばSIMを挿しているユーザーとWi-Fiで運用しているユーザーでは、Wi-Fiではディスプレイの電源が切れている時にはオフラインになる可能性があるので、通知が遅延する可能性があるのではないかと考えて、数値比較をしてみたりもしたのですが、確かにSIMを挿しているユーザーのほうが遅延が少ないような傾向は得られましたが、インドネシアの遅延の原因を明確に説明できるというほどではありませんでした。

各地域で比べてみると、遅延幅が異なるという事実の確認はできるのですが、該当地域での遅延の原因をデータだけから正確に把握していくのは、ちょっと難しいところがあるのではないかと感じています。

今回のプレゼン内容に興味を持って、ご自身のアプリでも調べてみたいという方がいるかもしれないと思うので、こちらにAPIの一覧を出しておきます。

App Standby Bucketの状態は、UsageStatesManagerのAPIで確認できます。FCMのPriorityについては、FCM内のRemoteMessageのAPIで確認できます。PriorityとOriginal Priorityがずれている場合、App Standby Bucketの影響によってPriorityが変更されたと認識しています。

Bucketを無駄遣いしない工夫

実は、LINE公式アカウントのアプリの場合で以前あった問題としては、サーバーサイドでイベントが発生した時に、受信するアプリがiOSかAndroidかを特に意識せずに「とりあえずJSONでプッシュして、アプリ側で必要か不必要かを判定して、通知を表示するか捨てるかをAndroidやiOSのほうで判断してくれ」という仕様がありました。

これが、FrequentやRareのユーザーでBucketが無駄遣いになっている状態だったので、サーバー側で本当にAndroidアプリに必要な通知だけをJSONのデータで送ってもらうように修正したところ、Androidの通知が100秒以上遅延していたものが17パーセント減るという改善が見られました。

もっとも、改善したのはLINE公式アカウントアプリをあまりアクティブに使っていないユーザーの通知なので、ユーザー側の実感として、遅延の程度が心理的にどの程度減ったのかはちょっと定かではないところがあります。

無駄な通知を避ける以外にも、LINE公式アカウントでは、通知の種類によってチャットほど即時性を求められないような通知は、PriorityをNormalに設定して、Bucketを無駄遣いしないようにする工夫もしています。

後半へつづく