Slide 1

Slide 1 text

鳥越 貴智 #meetup_ds 2023/03/03 HdrHistogram紹介 ストリーミングで統計値を算出するための 高速・省メモリなライブラリ 鳥越 貴智 2023/06/16 データサイエンス共有会 #meetup_ds

Slide 2

Slide 2 text

Webサービス運用とかでよく見る画面 Grafafana Sandbox https://play.grafana.org/

Slide 3

Slide 3 text

ストリームデータのメトリクス需要 ● ストリームデータのメトリクスをモニタリングしたいことはよくある ● たとえばWebサービスのレスポンスタイム ○ アドテクだと、数万〜数十万QPSの99%を数十msecで捌く必要があったり。 ○ 悪化してきたらオートスケールしたり、運用者を呼び出したりしたいので、 なにかしらの統計値をもってトリガーを仕掛けたい ● 単純にメトリクス値を全記録して後から集計するのでは、遅いし、重い ○ 記録時・算出時ともに高速・省メモリが求められる ○ ただし多少の誤差は許容できることが多い

Slide 4

Slide 4 text

ストリーミングの素朴な平均と分散 ● 平均は簡単 ○ 記録:総和・総数を足しこむ ○ 算出:総和を総数で割る ● 分散も公式を使えば簡単……? ○ 記録:総和・総二乗和・総数を足しこむ ○ 算出:右式に従って計算 ○ 大きな数の小さな差を求めるため 計算誤差が大きく、負数が出ることも 分散の意味と2通りの求め方・計算例 https://manabitimes.jp/math/1081

Slide 5

Slide 5 text

Welford法 ● 平均と分散の漸化式を用いる算出方法、精度良く、負数になることがない ● Knuth本(Art of Computer Programming)で紹介されているらしい Initialize M1 = x1 and S1 = 0. For subsequent x‘s, use the recurrence formulas Mk = Mk-1+ (xk – Mk-1)/k Sk = Sk-1 + (xk – Mk-1)*(xk – Mk). For 2 ≤ k ≤ n, the kth estimate of the variance is s2 = Sk/(k – 1). Accurately computing running variance https://www.johndcook.com/blog/standard_deviation/

Slide 6

Slide 6 text

平均と分散だけでいいんだっけ? ● 平均・分散が同じでも、分布の形は様々 ○ 最大値・最小値も算出しやすいが、やはり分布の情報量は少ない ● トリガーも99パーセンタイルとかで仕掛けたいので、ヒストグラムを描きたい if 2 random variables have exactly same mean and variance https://stats.stackexchange.com/questions/314000/if-2-random-variables-have-exactly-same-mean-and-variance

Slide 7

Slide 7 text

ストリーミングの素朴なヒストグラム (1) ● 固定幅ビンでカウンターを持つ方法 ○ 例:0~10、10~20、20~30、…… ■ 上例の精度:±5 ○ 遅延時間などの場合、だいたい10msec、たまに10secとか、レンジが広い ■ ビン幅が狭いと、値がほとんどない領域のためにメモリを食う ■ ビン幅が広いと、値が集中している領域の解像度が悪くなる ● 90%が10msec以内に収まっているのに、さすがにビンが一つでは……

Slide 8

Slide 8 text

ストリーミングの素朴なヒストグラム (2) ● 指数幅ビンでカウンターを持つ方法 ○ 例:1~2、2~4、5~8、…… ■ 上例の精度:70~141% ○ レンジが広くてもメモリは抑えられる ○ 記録時のビン決定にlog計算を行う必要があるので記録がちょっと重い ■ logの底が2の場合はビット演算でいいため軽いが、さすがに精度が粗い

Slide 9

Slide 9 text

HdrHistogram: A High Dynamic Range Histogram ● 指数幅の主ビンを、固定幅の幅ビンで分割する、ハイブリッド方式 ○ 0~255 (256 bins) ■ 0~1、1~2、2~3、…… ○ 256~512 (128 bins) ■ 256~258、258~260、260~262、…… ○ 512~1024 (128 bins) ■ 512~516、516~520、520~524、…… ○ …… ○ 上例の精度:±0.4%(有効桁数2)

Slide 10

Slide 10 text

HdrHistogram実装 int getBucketIndex(final long value) { return leadingZeroCountBase - Long.numberOfLeadingZeros(value | subBucketMask); } int getSubBucketIndex(final long value, final int bucketIndex) { return (int)(value >>> (bucketIndex + unitMagnitude)); } ● 記録時にカウントアップするビンのインデックス決定が、 高速な足し算・引き算・ビット演算のみで尽きているのがポイント(なはず) https://github.com/HdrHistogram/HdrHistogram/blob/3904a74e1896c22dc8a8afb0b29176a04f ee7a28/src/main/java/org/HdrHistogram/AbstractHistogram.java#L2425

Slide 11

Slide 11 text

HdrHistogramパフォーマンス ● 1回の記録が、2014のIntel CPUで3~6ナノ秒(=10^-9秒) http://hdrhistogram.org/ ● 1〜10^9のレンジでメモリ使用量が、 ○ 有効桁数2で31KB ○ 有効桁数3で220KB https://psy-lob-saw.blogspot.com/2015/02/hdrhistogram-better-latency- capture.html

Slide 12

Slide 12 text

HdrHistogramライブラリ情報 ● オリジナルはJava実装 ○ JavaScript、C、C#、Python、Erlang、Rust、Go、に移植されている ● Java実装にはHistogramのバリエーションが色々ある ○ DoubleHistogram ■ 記録値の型の違い(デフォルトはlong) ○ IntCountsHistogram、ShortCountsHistogram ■ カウンター値の型の違い(デフォルトはlong) ○ AtomicHistogram、ConcurrentHistogram、SynchronizedHistogram ■ Javaにおけるマルチスレッドの取り扱いの違い