どのようにしてDB同期のパフォーマンスを改善したか | JFrog Xray

How We Improved Our DB Sync Performance

要約

私たちは皆、すべてを超高速で開発したいと思っています。そのため、「単純な」データベースの同期処理などに時間がかかる場合は既成概念にとらわれずに考え直す必要があります。ここではDBのパフォーマンスを向上し、同期時間を16時間から2時間に短縮するために、JFrog Xrayに実装したソリューションをご紹介します。

JFrog Xrayとは

まず、課題とソリューションをご説明する前に、JFrog Xrayとは何かをおさらいしましょう。JFrog XrayはDevSecOpsチームのためのツールでソフトウェア・アプリケーションのオープンソース・コンポーネントを得るために使用します。JFrog Artifactoryのリポジトリに保存されているアーティファクトを再帰的にスキャンすることで、Xrayはセキュリティの脆弱性を特定し、組織のために定義されたポリシーに沿ったライセンスのコンプライアンスを保証するのに役立ちます。

現在のXrayの仕組み

脆弱性をスキャンし、ライセンスのコンプライアンスを確認するためにXrayは多くの公開されているコンポーネント、脆弱性、ライセンスを含む大きなデータベースを使用しています。初めてXrayをインストールする際、最初にDBの同期が行われ、Xrayで知られているすべての公開データをダウンロードして保存しますが、これは公開情報の中心となるナレッジベースです。

現在、このデータベースの圧縮サイズは約6GBで日々増え続けています。ダウンロードしたデータをXrayのデータベースに保存した場合、45GBのディスクスペースが必要です。このデータをPostgresデータベースに保存するために、Xrayは100MBのzipファイルを展開し、zipファイルの中にあるjsonファイルの2000個のオブジェクトを分析します。この作業には最小のシステム要件では15時間近く要していました。

Waiting* Image credit

考えられるソリューション

この課題に取り組むために、Xrayチームは似たような動作をするいくつかの異なるソリューションを検討しました。1つ目のソリューションはユーザー側でデータを再作成するのではなく、既にあるデータをデータベースのテーブルとして配布することでした。この場合、ソフトウェアの一部として配布するデータの数が多くなってしまいます。もう一つの方法はコンポーネントや脆弱性に関する情報を得るためにオンラインサーバーを使用することでしたが、これには多くの時間がかかりました。3つ目の選択肢はハイブリッドなもので、余り使用されていないコンポーネントの中央データベースを用意し、共通のコンポーネントを配布するというものでした。そこで私たちは3つのソリューションを組み合わせることにしました。

調査ステップからスタート

現状を調査する為、pprofツールを使用しました。pprofはGoogleが開発したマルチスレッドアプリケーションを分析するためのgperftoolsの一部であるcpuプロファイラです。pprofにはプログラムのコールグラフを可視化するgraphvizを生成する機能が備わっています。その結果、Xrayはデータベースの操作に多くの時間を費やしていることが分かりました。以下はpprofのグラフの例です:

Example pprof graph

pprofグラフの例

バッチではなく以下のようなシングルエントリーのINSERTステートメントが多数ありました:

INSERT INTO table VALUES (a,b,c)

以下のように複数エントリーを一度に実施可能にも関わらず:

INSERT INTO table VALUES (a,b,c), (d,e,f), (g,h,i)…

改善点1: 大きな課題はこの改善点をコードに集約することでした。そこで特定の期間やサイズを処理するための小さなキューを作成しました。

集約

goチャンネルのオブジェクトを内部で集約し、500ミリ秒毎または100オブジェクトを排除しました。

これは私たちが行った主要な改善の一つです。これまでの変更点と今回の変更点を合わせると、当初よりも約60%のパフォーマンス向上が計測されました。

初期DB同期と日次DB同期

初期DB同期を改善することが重要でした。初期状態ではDBは空で、99%のオブジェクトが追加されても更新されないことが分かっています。

改善点2: オブジェクトを検索して処理するのではなく、単純にデータを挿入する楽観的アプローチを採用しました。これにより更に数時間短縮し、パフォーマンスが少し向上しました。

しかし、日次同期は話が異なります。というのも、コンポーネントや脆弱性に関する情報を含むDBをすでに保持しており(初めて実行するわけではありません)、新しい脆弱性があれば、このDBを自動または手動で更新されるようにしたいのです。

ワーカーを利用

現在、Xrayでは以下の異なる3ワーカーが実行されています:

  1. Zipファイル・ワーカー
  2. Jsonファイル・ワーカー
  3. コンポーネント/脆弱性・ワーカー(jsonファイルのエンティティ)

改善点3: Xrayでは1つのファイル上のコンポーネントを並行して読み取るのではなく、ワーカーを使って生ファイルを並行して読み取るようにしています。ZIPファイルには2000個のエンティティをjsonで保持する100MBのファイルです。

インデックス化の削減

大量データの挿入に楽観的アプローチ(初期DB同期の為だけに追加)を採用しましたが最後に一番大きなテーブルに対して以下の方法を適用しました。

改良点4: 最大のテーブルを作成するには、コピーを使ってテーブルのデータを一括で読み込んだ後、テーブルに必要なインデックスを作成します。ご存知かも知れませんが既存のデータにインデックスを作成する方が各行の読み込み毎に更新するよりも迅速です。

JFrog Xray Summary of Performance Improvement

JFrog Xrayパフォーマンス改善の概要

サマリー

これらの改善により、お客様が経験されている同様の動作に役立つことを願っています。今後のXrayの改善にもご期待ください。

DBの改良点をもっと聞きたいですか? DevOpsユーザーカンファレンスのswampUPで私たちの講演をご覧ください