Life of Oracle I / O:SystemTapを使用した論理および物理I / Oのトレース

PG Day'17 Russiaの商用データベースに特化したセクションにすべての専門家を招待します! ドイツ銀行のAlexander Khalukhinは、Oracle Databaseのパフォーマンス診断に関する集中ワークショップを準備しています サイト上のプログラムのパフォーマンスの完全なリストを参照してください!



また、CERNのデータベース専門家からの記事の翻訳を公開し続けています。 今日の資料は、SystemTapを使用したOracle DBパフォーマンスのトレースとデバッグに関する一連の記事の第2部です。







この記事では、SystemTapを使用してOracleの論理的および物理的な読み取り値を追跡することに焦点を当てています。 ここでは、物理的および論理的なI / Oを実行するためにOracleが使用する基本的なメカニズムを示すいくつかの例を紹介し、SystemTapスクリプトを作成してOracle I / Oを後で診断およびトラブルシューティングする方法を学びます



はじめに



メディアとの間で入出力を実行する、つまり 物理的な入出力は、すべてのデータベースエンジンの根底にある最も重要なタスクの1つです。 RAMのデータベースキャッシュに格納されたデータにアクセスするとき、 論理的な入力/出力について話すことができます 。 物理I / Oは、OSカーネルシステムコールを使用してデータベースによって実行されます。 使用されるシステムコールのタイプは、データベース、OS、およびストレージタイプによって異なります。 論理I / Oは、Oracleカーネル機能を使用するデータベースプロセスによって実行されます。 Oracleでは、 待機イベント・インタフェースを使用して物理I / Oコール時間の測定が提供され、論理I / O時間は一般にCPU時間とみなされます。 Oracleプロセスによって実行され、Oracle待機イベントインターフェイスによって提供される詳細によって補完されるI / Oトレースは、Oracleの内部 I / Oを調べるための強力な方法です。 いくつかの実際の例を使用して、Oracleがリポジトリにアクセスするために使用するメカニズム、I / O操作が待機イベントインターフェイスとどのように相関するか、また最も一般的なI / O待機イベントの時間率を見つけます。



トレースツールを作成する



I / O操作の実行時にOracleおよびOSが実行する操作の調査には、特別なツールが必要です。 SystemTapは、Linux用に特別に設計された動的トレースツールであり、OSとOracleの両方の機能(Linuxカーネル機能、システムコール、およびOracleデータベースカーネル機能)を追跡できます。 以下は、Oracleの論理および物理I / Oを追跡するために使用できるsystemtapスクリプトの説明です。対象の関数呼び出しを結合し、関数パラメーター、メモリ、およびプロセッサレジスタ読み取ることができるプローブで構成されます。



Systemtapでは、比較的最近のカーネルバージョンでユーザー空間のプロファイルを作成する必要があります:utraceまたはuprobe_events機能が利用可能でなければなりません。 たとえば、RHEL / OL 6.5以上が適切ですが、RHEL 5は適切ではありませんさらに、トレースシステムコールには、 debuginfoカーネルパッケージをインストールする必要があります



この記事で、 これとテスト環境の作成方法について詳しく読むことができます。 この投稿で使用する、Oracleの論理I / Oと物理I / O、および待機イベントインターフェイスをトレースするスクリプトは、 trace_oracle_logicalio_wait_events_physicalio_12102.stp (Oracle 12.1.0.2の場合)のようになります。 バージョン11.2.0.4では、オプションtrace_oracle_logicalio_wait_events_physicalio_11204.stpも使用できます。 Oracle I / Oのケーススタディに進む前に、スクリプトの3つの主要な部分、物理I / O、論理I / O、および待機イベントの追跡に注目します。



物理I / Oトラッキング



最終的に、OracleはI / Oを実行するシステムコールを行います。 呼び出しのタイプは、データベース設定、OSタイプ、およびストレージタイプによって異なります。 この記事では、ブロックデバイス上のASMストレージを使用したLinux上のOracleの例を見つけることができます。 asmlibを使用したダイレクトNFS、ローカルストレージ、ASMはこの記事には含まれておらず、今後の調​​査で検討される可能性があることに注意してください。 システムコールは、Linuxのstrace (1)ユーティリティを使用して追跡することもできます。 ただし、この記事では、SystemTapプローブを作成して、興味深いシステムコール( pread、pwrite、io_submit、io_getevents)に関する情報を収集する方法について説明します。 次のSystemTapプローブは、ブロックI / Oの基礎となる層に役立ちます:ioblock.request、ioblock_trace.request、ioblock.end(これらはシステムコールではなく、Linuxカーネル内の関数呼び出しのトレースポイントであることに注意してください)。

名前プローブ 機能 お気に入りのオプション
syscall.pread / pwrite 同期I / O:ファイル記述子の読み取り/書き込み fd(ファイル記述子番号)、オフセット、番号。

戻り値:読み取り/書き込みバイト
syscall.io_submit 非同期I / O:処理のためのブロックの送信 nr(入出力操作の数)。 各操作について:ファイル記述子、オフセット、バイト、操作コード(読み取りの場合は0、書き込みの場合は1)

戻り値:実行されたI / O操作の数
syscall.io_getevents 非同期I / O:実行キューからイベントを読み取る min_nr(読み取る入出力操作の最小数)、イベント待機のタイムアウト。

戻り値:収集されたI / O操作の数

各操作:ファイル記述子、オフセット、バイト。
ioblock.request、ioblock_trace.request ブロックデバイスインターフェイスのカーネルレベルに送信されるI / O要求 devname、セクター、サイズ、rw、block_io構造体アドレス
ioblock.end ブロックデバイスインターフェイスのカーネルレベルから戻る devname、セクター、rw、block_io構造アドレス


2015年8月に追加された注: kernel.trace( 'block_rq_issue')およびkernel.trace( 'block_rq_complete')の Systemtapプローブは、追加の利点を使用してブロックI / Oインターフェイスを調べるためにも使用できます:カーネルdebuginfoを必要としません。 そのようなプローブの例は、 ダウンロードページまたはGitHubで見つけることができます。



論理I / Oトラッキング



Oracleがメモリ(バッファキャッシュ)からデータのブロックを読み取るときの論理I / Oの履歴と詳細についてです。 論理I / O操作には、物理​​I / O操作のサブセットが含まれます。Oracleがメモリ( バッファキャッシュ )でデータを見つけられない場合、物理的な読み取りを実行します。 この記事の後半で実際にこのメカニズムの例をいくつか見つけることができます。



Oracleツールキットは、 V $ SYSSTAT 、V $ SESSTAT、V $ SYSMETRICなど、複数のV $ビューで論理読み取りに関する広範な情報を提供します。 論理読み取りデータは、sql *に加えて、「set autotrace on」パラメーターとtkprofでイベントトレース10046をレポートすることもできます。 論理読み取り値には、一貫性と最新の2つの主な形式があります。 Oracleは、特定のシステム変更番号SCNのデータを読み取るときに一貫した読み取りを使用し、ブロックでDML操作を実行するときに現在の読み取りを使用します。 イベント10200および10201を使用して、一貫した読み取りをOracleでトレースできます。 詳細については、 Julian Dykeの論理I / Oに関するプレゼンテーション参照してください



この記事では、プローブSystemTapをOracleカーネル機能セットに接続して、論理I / Oを追跡する方法を示します。 一貫性のある現在の読み取りトレースに対するkcbgtcrおよびkcbgcur関数の役割は、Alexander Anokhinの優れたDtrace LIO記事ですでに説明されています。 最近、このトピックを調査し、関数kcbzib、kcbzgb、kcbzvbをトレースすることも有用であることがわかりました



これらの機能についてわかったことの概要を以下の表に示します。 注:%rdi、%rsi、%r8式は、対応するプロセッサレジスタの値を示します。 SystemTapを使用すると、register関数を使用してレジスタ値を読み取ることができます。例:register( 'rdi')。 CPUレジスターは、 関数呼び出し引数を抽出するために使用されます 。 Systemtapは、実行可能ファイルのデバッグシンボルがない場合、関数呼び出し引数を提供しません。 特に、 www.x86-64.org/documentation/abi.pdfで説明されているx86-64の呼び出し規則は、関数を呼び出すための整数パラメーターが次のレジスターで(順番に)使用可能であることを示しています:%rdi、%rsi 、%rdx、%rcx、%r8および%r9。

機能名 進行中のタスク お気に入りのオプション
kcbgtcr カーネルキャッシュバッファーの一貫した読み取り

一貫した読み取りに使用
tbs#= user_int32(%rdi)

rel file n#= user_int32(%rdi + 4)>> 22&0x003FFFFF

ブロック#= user_int32(%rdi + 4)&0x003FFFFF

data_object_id#= user_int32(%rdi + 8)

object_id#= user_int32(%rdi + 12)



注:大きなファイルの表領域の場合:

ブロック#= user_int32(%rdi + 4)
kcbgcur 現在のカーネルキャッシュバッファー

現在の読み取りに使用
tbs#= user_int32(%rdi)

rel file n#= user_int32(%rdi + 4)>> 22&0x003FFFFF

ブロック#= user_int32(%rdi + 4)&0x003FFFFF

data_object_id#= user_int32(%rdi + 8)

object_id#= user_int32(%rdi + 12)



注:大きなファイルの表領域の場合:

ブロック#= user_int32(%rdi + 4)
kcbzib kcbZIBは、Z(kcbz.o-物理入出力の補助機能用モジュール)、IB:入力バッファーの略です。

Oracleは、バッファキャッシュに対して物理的な読み取りを実行します。
kcbzgb kcbZGBのGBサフィックスは、バッファーの取得(スペース)を表します

Oracleは、特定のブロック(通常はI / Oの前)にバッファ領域を割り当てます。
tbs n#=%rsi、

rel file n#=%rdx >> 22&0x003FFFFF

ブロック#=%rdx&0x003FFFFF

data_object_id#=%r8

object_id#=%r9



注:大きなファイルの表領域の場合:

ブロック番号=%rdx
kcbzvb Oracleが指定されたブロックを読み取った後に呼び出されます。

これは、db_block_checkingパラメーターによって制御されるブロックをチェックするための呼び出しチェーンの一部です。 推定復号化:カーネルキャッシュバッファー検証ブロック。 この説明をありがとう@FritsHoogland



この関数は、バッファキャッシュの読み取りと直接読み取りの両方に使用されます。
tbs n#=%rsi、

rel file n#=%rdx >> 22&0x003FFFFF、

ブロック#=%rdx&0x003FFFFF

data_object_id = user_int32(%rdi + 24)

注:大きなファイルの表領域の場合:

ブロック番号=%rdx


:執筆時点では、バージョン3.10以降のカーネルのアップローブのみがユーザー空間関数のプローブを返していました。 したがって、この機能はRHELまたはOL 6.xでは使用できませんが、RHEL 7.xカーネルでは使用できます。



待機イベントを追跡する



待機イベントインターフェイスは、パフォーマンスの問題とボトルネックを特定するための定量的な方法を提供するため、おそらくOracleパフォーマンスのチューニングで最も優れた機能の 1つです。 Cary Millsapは 、このテーマに関するインスピレーションを与える作品を発表しています。



この目的のために、待機イベントは、Oracleカーネルの選択されたアクションが測定される計測ポイントであることを示すことで十分です。 特に、Oracleはほとんどの物理I / O操作の開始コールと終了コールをマークするため、物理I / Oのプロセスに費やされる時間を十分に理解できます(このメカニズムの制限については、この投稿で後述します)。 待機イベントインターフェースを使用してI / Oレイテンシを調査することに制限があります。特に、例のセクションでは、 非同期 I / Oイベントの継続時間の測定に関連する興味深いタスクを見つけることができます。



通常、待機イベントのトレースは、Oracleでイベント10046を使用するか、DBMS_MONITOR.SESSION_TRACE_ENABLEを呼び出してアクティブにします。 この記事では、プローブSystemTapをOracleカーネルの対応する関数( kskthbwtおよびkskthewt )に接続して 、各待機イベントの開始時と終了時に情報を収集することにより、待機イベントに関する詳細情報を取得します。 レベル8のイベント10046およびその他のメソッドを使用して待機イベントトレースを有効にすることは、待機イベントの時間に関する情報(およびSQL処理に関するその他の詳細)を取得する方法であり、待機情報を含める方法ではありません。 次に、これはTIMED_STATISTICSデータベースパラメータを使用して行われます。最新のOracleデータベースでは、TRUEに設定する必要があります。 Oracleカーネルのkskthbwtおよびkskthewt関数によって提供される情報の重要な部分は、 X $ KSUSEサービステーブル (または、SGAの「基礎となる」メモリ構造) へのポインタです 。したがって、待機イベントと、SQLを実行しているセッションに関する多くの有用な情報を一致させることができます。 レジスターr13のポインターをX $ KSUSEのベース値に逆参照し、対象のフィールドのオフセットを計算するには、前の記事で詳しく説明した追加の作業が必要です(スクリプト: ksuse_find_offsets.sqlも参照)。

機能名 進行中のタスク お気に入りのオプション
kskthbwt カーネルサービスKompileスレッドは待機を開始します。

この関数は、Oracle待機イベントの開始時に呼び出されます。

kslwtbctxはその親関数の呼び出しであり、待機イベントの開始をマークします。
関数のプロファイリングに役立つ情報:

レジスタr13-> SGAのX $ KSUSE(V $ SESSION)のセグメント化された配列を指します

register rsi->待機開始のタイムスタンプ(マイクロ秒)

レジスタrdx->待​​機イベントの数
kskthewt カーネルサービスKompileスレッド終了待機。

この関数は、Oracle待機イベントの終了時に呼び出されます。

kslwtectx-待機イベントの終了をマークする親関数の呼び出し。

接尾辞「ewt」は、「end wait」を意味する可能性があります。
関数のプロファイリングに役立つ情報:

レジスタr13-> SGAのX $ KSUSE(V $ SESSION)のセグメント化された配列を指します

register rdi->待機開始のタイムスタンプ(マイクロ秒)

登録rsi->待機イベントの数


スクリプト実行



以下に、一般的なOracle I / Oアクセスパターンのトレース例を示します。 トレースは、コマンドstap -v trace_oracle_logicalio_wait_events_physicalio_12102.stp -x _pid_で受信されました。ここで、_pid_は、監視対象セッションのプロセスの識別子です。 結果はsed -f eventsname.sedに渡され、そこでイベント番号がそれに関連付けられた名前に変換されます。 eventsname.sedファイルは、eventsname.sqlスクリプトを実行して作成されます。 テスト前にスクリプトを再起動してイベント名を生成することが重要です。待機イベントの数は、新しいバージョンへの移行後やパッチのインストール後など、警告なしに変更される可能性があるためです。 次の例でトレースを収集するために使用されるシステムは、VirtualBoxの下でUEK3を使用してOEL 7.0で実行されるOracle 12.1.0.2です。



例1:単一ブロックのランダム読み取り



この例は、単一ブロックのランダム読み取りのカテゴリに属します。 このデータアクセス方法は、インデックスキーを介してテーブルにアクセスするために使用されるため、多くのOLTPワークロードにとって非常に重要です。 以下の図1では、indexed_col = valのテーブルタブからcol_listを選択するタイプのクエリのトレースファイルのフラグメントを見ることができます。





図 1:dbファイルからのOracleシングルブロックランダム読み取りおよび順次読み取り待機イベント



キーポイント





例2:同期I / Oを使用したバッファーキャッシュへの順次I / O



この例では、キャッシュ内のマルチブロック読み取りを扱います。 これは、たとえばOracleが全表スキャンを実行するときに使用されるアクセス方法です。 Oracleがリポジトリにアクセスして全表スキャンを実行する方法はいくつかあります。この例では、Oracleが同期I / O(つまり、preadコール)を使用してOS読取り操作を実行する場合を示しています。例3および4非同期I / Oによる順次読み取りをカバーします。 下の図2では、 テーブルタブselect col_listなどのクエリのワークロードを追跡するためのスニペットを見ることができます。Oracleはテーブルタブのフルスキャンを実行します。





図 2:pread OS呼び出しを使用して読み取りが行われる場合のOracle Sequential I / O



図2の主要なトレースポイント





例3:OS非同期I / O関数呼び出しによるバッファーキャッシュへの順次I / O



図3では、SQLトレースのフラグメントが表示されており、 テーブルタブからcol_listを選択しています 。ここで、Oracleはテーブルタブの完全スキャンを実行します。 これは、例2で使用したのと同じクエリです。違いは、図3のトレースが、Oracleプロセスがpread呼び出しによる同期I / Oの使用から非同期 I / O インターフェイスの使用に切り替えたときに、クエリの後の段階で行われたことです。 非同期I / Oは、I / O要求を送信して結果を取得するio_submitおよびio_getevents呼び出しによってLinuxに実装されます。 この例では、Oracleは非同期インターフェイスを使用して読み取り操作を実行しますが、最終結果は例2で示した結果と非常によく似ています(つまり、同期I / Oを使用)。 同じOracle待機イベント“ db filescattered read” 、読み取りもバッファキャッシュで実行され、I / O結果はブロック呼び出しを使用して収集され、実際にプロセスを同期化します。 以下の例4で説明する直接読み取りを実行すると、Oracleでは非同期I / Oのインターフェイスの「積極的な使用」が発生します。





図 3:非同期I / O呼び出しを使用してバッファキャッシュへの順次I / O読み取りを実行するOracle



キーポイント





例4:直接読み取りと非同期I / Oを使用したフルスキャン



この項では、 ASMを使用して構成されたブロック記憶域での直接読取りの場合のOracle I / Oの2つの例を示します。 例2および3と同じ全テーブルスキャンを実行する同じクエリを使用します。この例では、例2および3とは異なり、Oracleはシリアルダイレクトリードを使用してデータにアクセスします。 シリアルダイレクトリードは、11gR2で導入された機能で、フルセグメントスキャン操作を最適化し、バッファキャッシュレイヤーバイパスします。これは、並列リクエストで発生するものと同様です。 Oracleは、いくつかのパラメーターに基づいて、キャッシュ読み取りの代わりにシリアル直接読み取りをいつ使用するかを選択します。 最初の近似では、バッファキャッシュのサイズと比較してテーブルが「大きい」場合は直接読み取りが望ましいですが、実際のメカニズムはより複雑であり、Oracleのバージョンに応じて変更される可能性があります。 このトピックの詳細については、 Tanel Poderの記事をご覧ください



これらのテストを実行するには、リクエストを実行する前にシリアルダイレクトリードの使用を強制する必要がありました。これは、 alter session set "_serial_direct_read" = always;



リクエスト変更セッションセット "_serial_direct_read" = never; シリアルダイレクトリードを無効にして、Oracleにキャッシュリード(つまり、上記の例2および3で見たI / Oのタイプ)を使用させることができます。 _serial_direct_readパラメーターのデフォルト値はautoです。



この例の研究では、以前のものとは少し異なるSystemTapプローブを使用できます。 - - , probe userspace io_getevents_0_4 libaio (libaio — Linux, -). , serial direct reads -, libaio , (Frits Hoogland) . SystemTap, . 4a 4, : trace_oracle_wait_events_asyncio_libaio_12102.stp ( 11.2.0.4 trace_oracle_wait_events_asyncio_libaio_11204.stp ).





図 4a: Oracle I/O full table scan serial direct read -. , full scan



4a:





serial direct reads Oracle , , . 4a. direct reads Oracle . , Oracle direct reads , . - -. I/O slots. , Oracle 10353 : « (slots) — -, -».



, -, direct reads, . , Oracle io_getevents timeout=0, - . . 4. full scan, 4, , adaptive serial direct reads Oracle I/O, « » .





図 4. Oracle I/O full table scan serial direct read -. , , -



4:





5: - random reads



Oracle single-block reads , / -. random I/O -, Oracle - io_submit, , 1, pread OS. . 5 SLOB (Kevin Closson) 12c. 3 , Oracle «TABLE ACCESS BY INDEX ROWID BATCHED» .





図 5: SLOB, (batch access)



6 Oracle I/O SLOB. , - random I/O. , . 6, 126 io_submit, io_getevents, . — «db file parallel read», — 126 . db file parallel read - single block random reads .





図 6: Oracle, - -, batched reads. ( 126 , block#) "..."



6: DML



7 Oracle logical I/O , . - ( ). , current read, DML. , ( 7 tbs#=11), rollback segments ( 7 tbs#=2). , .





図 7: Oracle logical I/O, commit



7: log writer



8 log writer commit. commit, 6 (. . 7 ). — «log file parallel write», Oracle -. , «log file parallel write» , . , 8, , log writer , 1 redo- , ASM- normal: log writer 2 - — - — .





図 8: log writer commit



おわりに



, , SystemTap Oracle I/O, Oracle I/O Oracle Linux. , , .



Oracle Oracle I/O OS , Oracle. Oracle - - . random reads, «db file sequential read». , , -, : -. , , - Oracle direct reads .



: この作品にインスピレーションを与えた独創的なアイデア。この問題に関する彼の深い専門知識を私にgeneしみなく分かち合ってくれたフリッツ・フーランドに感謝します。



スクリプトのダウンロード:この記事で説明したスクリプトは、ダウンロード資料のあるWebページまたはGitHubから入手できます



All Articles