OpenTelemetryのバックエンドを作ってparquetと戯れている話株式会社Vaxila Labs杉中宏亮
View Slide
⾃⼰紹介● 杉中 宏亮 (@m_rasu)● 株式会社 Vaxila Labs● 趣味では昔からGo、仕事では1年ぐらい
SRE NEXTに落ちたので来ました
SRE NEXTに落ちたので来ましたSRE NEXTは明⽇。SRE NEXTではOpenTelemetry関連のOSSの話をしようと思ってましたが、Goの⼈たちの前なので僕が書いている実装の話をします。
OpenTelemetryネィティブの監視SaaSで会社を作りました
話したいことParquetのためにしてる⼯夫-> Parquet 楽しい
⽬次1. Parquetとは2. OpenTelemetryとは3. Vaxilaとは4. Parquetと遊ぶa. ファイルの内容を考えるb. Athenaと遊ぶ
Parquetとは● 列指向のファイルフォーマット○ CSVやJSONは⾏指向● ⼤規模なデータを保存するときによく使われる● カラム単位でエンコーディング⽅法を変えられる● Readに強い代わりに、Writeはダメ
Parquetのエンコーディング⽅法代表例● Run length Encoding○ 「a,a,a,b,b,b,a,a」 -> 「a3b3a2」みたいな● Delta Encoding○ 差分を書くことで容量圧縮○ 時間の列で⾼威⼒○ 「7,5,3,1」 -> 「7,-2, 3 (最初が7で、-2を連続3回)」みたいな● zstd,snappy,lz4 なども
Goで使うGoなら● xitongsys/parquet-go● parquet-go/parquet-goVaxilaでは「parquet-go/parquet-go」を使⽤
OpenTelemetry とはOpenTelemetry is a vendor-neutral open-sourceObservability framework- 公式 https://opentelemetry.io/docs/
OpenTelemetry とは簡単に⾔うと、● 分散トレーシング● メトリクス● ログを作ったり、送信したりするのに必要なSDK、プロトコルなど⼀式ベンダー⾮依存が特徴
OpenTelemetryの流れ
OpenTelemetry で分散トレーシング分散トレーシングという名前だが、分散環境じゃなくても便利下図の1本1本がSpanSpanにはHTTPのパスやSQLなど⾊々記録している
OpenTelemetry は Protocol Buffers● データを送信する時は基本的にProtocol Buffers● json もできる● Apache Arrow の実装もそのうちできそう
Protocol Buffers例message TracesData {repeated ResourceSpans resource_spans;}message ResourceSpans {repeated ScopeSpans scope_spans;}message ScopeSpans {repeated Span spans;}message Span {bytes trace_id;bytes span_id;repeated KeyValue attributes;}例えば、トレーシングのProtocol Buffersはこんな感じattributes の中に、URLや実⾏したSQLが⼊っている
OpenTelemetry は Protocol BuffersVaxilaではParquetのフォーマットで保存している
Vaxilaとは● 問題を解決するための監視ツール● OpenTelemetryを使ってエラーや速度低下の原因を探して教える「SLOを良くするために」
なんで作った?● 原因を⾒つけるために⾊々な特徴を探してた「これ、⼈間がやる必要ある?」-> 機械がやれよ● 「それ、前からエラー鳴ってたみたいですが、全員無視してますね‧‧‧」を無くしたい● 安く
SLOに問題が!原因特定の流れ
エラーのトレースと、それ以外を⽐べて原因を推測する原因特定の流れ
attributes の分布からエラー原因を探すことも原因特定の流れ
アーキテクチャS3にParquet
Parquetと遊んでいます● S3にParquet● Athenaで検索
Parquet (OpenTelemetry) ファイルから原因を探す● 例外が起きたか?● 実⾏時間が⻑すぎないか?● エラーではないSpanと⽐較すれば○ 「user_idが99のときだけエラー起きてるな」○ 「このインスタンスだけ遅いから捨てよう」というのがわかる
OpenTelemetryのフォーマットは使わないAthena (trino) は配列内に触れるとスキャン量がかなり増える-> GoではSpanをトップレベルにtype TraceSpan struct {TraceID []byte `parquet:"trace_id"`SpanID []byte `parquet:"span_id"`Attributes []Attribute `parquet:"attributes,list"`Scope InstrumentationScope `parquet:"scope"`}message ScopeSpans {InstrumentationScope scope;repeated Span spans;}message Span {bytes trace_id;bytes span_id;repeated KeyValue attributes;}gopb
エンコーディングを選ぶ今は無難なところを指定している● stringの列はzstd● 時間を表す列はdelta encodingtype TraceSpan struct {SpanID []byte `parquet:"span_id"`Name string `parquet:"name,zstd"`StartTimeUnixNano uint64 `parquet:"start_time_unix_nano,delta"`EndTimeUnixNano uint64 `parquet:"end_time_unix_nano,delta"`}
頻出フィールドを冗⻑化するSpanの属性には “service.name”というキーがよく検索条件になる-> トップレベルにフィールドを作る他にも、「例外が起きたか」などを事前に計算type TraceSpan struct {TraceID []byte `parquet:"trace_id"`ServiceName string `parquet:"service_name,zstd,dict"`HasExceptionEvent bool `parquet:"has_exception_event"`}トレース検索の絞り込み
Athenaを使う = SQL を書くSQLは頑張る● Athenaは途中の結果を再使⽤しない○ 2回参照したら2回読み込まれる -> 遅い‧お⾦かかる● つまり、UNIONと相性が悪い-> concat, case, filter などで1回しか読まなくてもいいように頑張る
ファイル数を減らして⾼速化Athenaはファイルを参照するのは時間がかかる「⼩さいファイルが⼀杯」よりも、「巨⼤なファイルが少々」の⽅が速い(Parquetの効率も良くなる)
×「データが来るたびにファイルを作る」○「数秒待って1ファイルにまとめる」キューで⼀括保存
別DBにある項⽬で絞り込み検索項⽬がRDB(Aurora)にあることがある「この問題が起きたTraceの中から検索したい」-> 100万Traceあったら100万個のORがついたSQLが必要ってこと‧‧‧?-> TraceIdを全部⼊れたファイルを⼀時的にアップロードしてAthena上でTraceIdを取得できるようにするトレース検索の絞り込み
と、⾊々している
結論Parquet 楽しい
以上X(@vaxila_labs)もよろしくお願いします。