cocoa-mhlw / cocoa

Mozilla Public License 2.0
990 stars 113 forks source link

ETag による通信量削減 #199

Open i-maruyama opened 3 years ago

i-maruyama commented 3 years ago

その機能リクエストは何らかの問題に関連しますか / Is your feature request related to a problem?

  1. 接触確認毎に毎回TEKリストを DLし、無駄な通信量が多い問題。
  2. CDN サーバーは ETag を付与しているが、有効活用していない問題。

なお接触確認が走る頻度はバックグラウンド (6 時間毎) あるいは, 手動によるホームページ再表示毎です. URL は https://covid19radar-jpn-prod.azureedge.net/c19r/440/list.json です. zip に比べれば対した通信量ではないと思いますが、電源消費も抑えられるかもしれません。

解決策についてお書きください / Describe the solution you'd like

現在は、 TEK リストは毎回 DL し、 LastProcessTekTimestamp より新しい TEK(zip) をDL して接触確認し、成功すれば LastProcessTekTimestamp を更新しています。 以下では、サーバーが付与する ETag をローカルに保存して、 ETag が違えば DL する通信(If-None-Match)を行う実装案を紹介します。重要なのは、 LastProcessTekTimestamp と同じタイミングで ローカル ETag を更新することです。もし、 接触確認失敗のときに、 ローカル ETag だけ更新すると TEK リストが DL されなくなり、 ETag がサーバー側で更新されるまで(現状では1日)接触確認できなくなります。それを考慮した実装案が以下です。

  1. ETag 利用のため, HttpDataService.cs (GetCdnAsync) を改変します. ETagの一時的なやり取りは Xamarin.Essentials.PreferenceKey を用います。
  2. ETag 保存のため, LastProcessTekTimestamp と同じ枠組みを使います。対応のため改変するのは2ファイルです -- PreferenceKey.cs (PreferenceKey.ETag追加) -- ExposureNotificationService.cs (Get&Set method追加。及び RemoveLastProcessTekTimestamp の中で ETag も 消去し再DL可能に)
  3. ETag 更新のため, ExposureNotificationHandler.cs を改変します

あなたが考える代替案についてご説明ください / Describe alternatives you've considered

1日様子を見た範囲(Android)では、ETag は機能していそうです(以下のスクショ)。もう少し様子を見ます。

アドバイスあれば。

その他 / Additional context

ETag

Internal Tracking Code: NFR 2527

i-maruyama commented 3 years ago

三日目も ETag は付与されていました。ETag が同じ値の場合には、 status も 304 を返しています。

上の https://github.com/i-maruyama/cocoa/commit/32c1c574b6eca3493638ee007b1db154c8c4da00 上、サンプルコードを載せています。(私自身はMockの方でテストしていますが、 Debug 系がPR 中なので、別途ブランチ作りました)

その中で疑問点があるのですが、以下のコードで2回同じコード(await)が必要なのは、この結果で result.StatusCode が変更されるからでしょうか?

https://github.com/cocoa-mhlw/cocoa/blob/cb1b9cc9de52c8f922f5032d5df8199dd90346cb/Covid19Radar/Covid19Radar/Services/HttpDataService.cs#L186-L190

もしご存じでしたら、ご教示ください。

https://docs.microsoft.com/ja-jp/dotnet/api/system.net.http.httpcontent.readasstringasync?view=net-5.0

b-wind commented 3 years ago

三日目も ETag は付与されていました

ETag を付けるか付けないか・どのように付けるかはサーバー依存なので観測するよりサーバー側の設定を確認して貰った方が良いかと。 Azure CDN の様なので特に何もしなくても付くような気はします。

https://docs.microsoft.com/ja-jp/azure/cdn/cdn-how-caching-works

(今後サーバー側の ETag 不対応等がある場合など) Last-Modified と If-Modified-Since を使う.

あまり深く考えずにEtagでの判定と併用してしまって良いと思います。

Etag(等)の保存場所としては CacheDirectory を使用する方が良い気がしますが、使い方はイマイチ理解していません。 https://docs.microsoft.com/ja-jp/xamarin/essentials/file-system-helpers?tabs=android

https://github.com/i-maruyama/cocoa/commit/32c1c574b6eca3493638ee007b1db154c8c4da00

PR の形にして貰った方が他の人が見やすいかと。 見る限り、304 応答( System.Net.HttpStatusCode.NotModified )の場合の対応が不足しているようです。

通信量削減という意味では、ファイル圧縮も有効です。(現時点で有効化されていないようです) https://docs.microsoft.com/ja-jp/azure/cdn/cdn-improve-performance

余談ですが curl がインストールされている環境では、以下の様に Etag...etc を確認出来ますね。

$ curl --head https://covid19radar-jpn-prod.azureedge.net/c19r/440/list.json
HTTP/2 200
accept-ranges: bytes
age: 2373
cache-control: max-age=3600
content-md5: lLePHwXKvuIBFSaaBiOKig==
content-type: application/octet-stream
date: Wed, 09 Jun 2021 20:03:43 GMT
etag: 0x8D92B5745276DD3
expires: Wed, 09 Jun 2021 21:03:43 GMT
last-modified: Wed, 09 Jun 2021 15:00:07 GMT
server: ECAcc (osa/2B63)
x-cache: HIT
x-ms-blob-type: BlockBlob
x-ms-lease-status: unlocked
x-ms-request-id: 1fd18309-501e-0003-1965-5df4ac000000
x-ms-version: 2009-09-19
content-length: 13427
i-maruyama commented 3 years ago

見る限り、304 応答( System.Net.HttpStatusCode.NotModified )の場合の対応が不足しているようです。

コードをご覧いただきありがとうございます。 304 への対応は、 https://github.com/cocoa-mhlw/cocoa/commit/d21e8cf877e3e43b016edda7e7ee9f9a7eb1493a のようにしています。PRにしますね。

余談ですが curl がインストールされている環境では、以下の様に Etag...etc を確認出来ますね。

教えていただきありがとうございます。content-length も見たいなと思っていたところでした。

b-wind commented 3 years ago

実際の所、通信量の削減は必要とされているのかがよく分かりませんね。 私自身はネットワーク屋として推奨していますが、関係者のご意見も聞いてみたいところ。

i-maruyama commented 3 years ago

PRしました。128kbps 環境なら、このETag による 13kB の通信量削減は体感できるかもしれません。

b-wind commented 3 years ago

サーバー側でも差分ダウンロードさせてくれれば良いのにと思っているのは秘密です。

b-wind commented 3 years ago

余談ですが、list.json のサイズが約 13kbyte , ファイル圧縮を有効にしたと仮定すると約 1.1kbyte 程度まで縮小できますね。 基本的には肥大化する一方の様なので、ファイル圧縮も有効化して欲しいなとは思います。

b-wind commented 3 years ago

gzip だけじゃ無く brotli も使えるのかな? だとしたらもう少し小さく出来そう。

b-wind commented 3 years ago

brotli での想定ファイルサイズは 663byte になりますね。流石の圧縮率。

b-wind commented 3 years ago

Xamarin.Android/iOS の要求バージョンは満たしているように見えますね。

https://docs.microsoft.com/ja-jp/dotnet/api/system.net.decompressionmethods?view=net-5.0

b-wind commented 3 years ago

Accept-Encoding ヘッダに br, gzip を指定するだけ。 https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Accept-Encoding

b-wind commented 3 years ago

AutomaticDecompression を設定すれば透過的に扱ってくれそう。 https://stackoverflow.com/questions/20990601/decompressing-gzip-stream-from-httpclient-response/27327208#27327208