2015年12月08日

[JPOUG Advent Calendar] Oracle on Hyper-V 2015

charade_oo4oと申します。昨年に引き続き、今年も「JPOUG Advent Calendar 2015」へ参加致します。
昨日は渡辺 剛さんの「Oracle VM Server とその周辺のもの: OpenStack for Oracle Linux R2 の様子。」でした。

今年はOracleもMicrosoftも2016年に向けた準備期間だったと思います。
Oracleは「Oracle Database 12c Release 2」、Microsoftは「Windows Server 2016」、各種イベントで2016年リリース予定の製品の情報が公開されました。
それ以外にもStandard Edition系の見直しや「Windows 10」リリースがありました。
特にHyper-V環境はInsider向けの新Buildで度々見直しが必要でした。
Docker、Nested Hyper-V、新技術実現の為の変革なのでしょう。
Windows10は検証時点では頻繁にBuildが上がっていた為、今回はWindows8.1のClient Hyper-Vを使用しました。

 <1.きっかけ>

Oracle自身は12.1を薦めていますが、現時点では11.2と12.1のどちらで構築するのが良いか悩みます。
12cの導入は12.2のリリースを契機に本格的に進むのではないかと思います。
11.2のリリースが2009年なので、7年振りのRelease 2になります。
中には12.2がリリースされてから勉強しようと考える方も居るかも知れません。
きっかけとしては間違いではないと思います。
但しそれで充分かと言うと、否と言わざるを得ないでしょう。
Oracle Databaseは1-2年毎にリリースされるパッチセットの度に結構変わるので、その都度勉強が必要です。
Oracle Database Cloudではそれより早く新機能が提供されるかも知れません。
Microsoft Azure SQL Databaseはほぼ毎月機能追加があり、オンプレミスのSQL Serverとは別物の進化を遂げています。
継続的な勉強が必要なら、12.1での勉強も通過点に過ぎません。

http://www.oracle.com/technetwork/jp/database/upgrade/overview/upgrade-and-migrate-12c-ja-part1-2367968-ja.pdf
Oracle Database 12cへのアップグレード/移行とデータベース統合(Part 1)

「地球はまだ丸い(The earth is still a sphere)」
プラガブル・データベース使用可否のガイドに掲載されていた言葉です。
12cリリース当初は「まだ使わなくても良い」でした。

http://docs.oracle.com/cd/E57425_01/121/UPGRD/deprecated.htm#BABDBCJI
8.1.1 非CDBアーキテクチャの非推奨

しかし2015年のアップグレード・ガイドでは「Non-CDBは非推奨」と変わってしまいました。
今後はStandard Edition 2でもシングルテナント構成を検討する必要がありそうです。
12.2でもPDBは機能追加され、「PDB Relocate」ではライブマイグレーションが可能となる様です。

PDB間の通信はdblinkを使用する必要があるとの事でした。
PDB間通信にはどの位の帯域があるのか、Hyper-V上の仮想マシンで試行錯誤してみました。

 <2.転送量が少ない>

帯域を調べる為、大量のデータを流して、処理時間を計測しました。
PDB間通信を調べる前に、まずPDB内のテーブルに対してSQLPLUSから計測してみました。
・ゲストOS:2012R2で、DB:12.1.0.2 EEを実行。
・ホストOS:Windows8.1のコマンドプロンプトからSQLPLUS+Instant Clientを実行してDB接続。
・SQLPLUSで、SET TIMING ON、SET AUTOTRACE TRACEONLYを設定して、処理時間等を確認。
 (他にSET PAGESIZE 0、SET LINESIZE 1025、SET ARRAYSIZE 5000も設定。)
・SELECT文で大量データを取得。
・テストデータは12cのIn-Memory Optionを有効にしたテーブルへ格納。

構成


テストデータはINSERT SELECT文で作成しました。
INSERT /*+ APPEND */ INTO TESTTABLE (SEQNO, INFO)
SELECT LEVEL, RPAD('X',1024,'X')
  FROM DUAL CONNECT BY LEVEL <= 100000;

次に、単純なSELECT文を計測しました。
SELECT T.INFO FROM TESTTABLE T;

100000行が選択されました。

経過: 00:00:06.97

実行計画
----------------------------------------------------------
Plan hash value: 2221197626

----------------------------------------------------------------------------------------
| Id  | Operation                  | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |           |   100K|    97M|   196   (1)| 00:00:01 |
|   1 |  TABLE ACCESS INMEMORY FULL| TESTTABLE |   100K|    97M|   196   (1)| 00:00:01 |
----------------------------------------------------------------------------------------

統計
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
     506294  bytes sent via SQL*Net to client
        761  bytes received via SQL*Net from client
         21  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
     100000  rows processed

In-Memory Optionが効いており、0  db block gets、3  consistent gets、0  physical reads です。DISK I/Oは発生していません。
しかし肝心のデータ転送量は、506294  bytes sent via SQL*Net to client。約494KByteなのでかなり少ないです。
1カラム1KByteで100000行取得しているので、100MByte弱は転送するはずです。

データ作成時のSELECT文のみを抜粋しても、同様の結果でした。
SELECT RPAD('X',1024,'X')
  FROM DUAL CONNECT BY LEVEL <= 100000;

     506308  bytes sent via SQL*Net to client

SQLPLUSはDBサーバの仮想マシン外から実行した為、タスクマネージャからネットワークの使用帯域を確認可能です。
DBサーバ=>クライアントの使用帯域は608kbpsしか出ていません。

試行錯誤した所、どうやらSQL*Netは連続データを圧縮する事が判りました。INDEXのCOMPRESSと同じ様な動作です。
12cではSQLNET.COMPRESSION=ONでデータ圧縮が出来る様になりました。
9i等の以前のバージョンのSQL*Netでは連続データを圧縮します。

データが連続しなければ圧縮も効かない様で、行毎に異なる値を返すSELECT文では大量データを転送する様になりました。
SELECT DECODE(MOD(LEVEL,2),1,RPAD('X',1024,'X')
                            ,RPAD('Y',1024,'Y'))
  FROM DUAL CONNECT BY LEVEL <= 100000;

  103424345  bytes sent via SQL*Net to client

DBサーバ=>クライアントの使用帯域をタスクマネージャで確認すると93.6Mbpsまで上がりました。
今度はSQLPLUSのFETCHがネックとなって、100Mbps程度で頭打ちとなっている様です。

 <3.FETCH見直し>

単純SELECT文から、PL/SQLのBULK COLLECTへ変更しました。
テストデータも不連続データへ入替。
1ブロック内に偶数行(6行)含まれていた為、ORDER BY指定無でも不連続データでSELECTされました。
100000行では実行時間が短過ぎたので、10倍の1000000行へ増加。
1回では実行時間が短過ぎたので、FOR LOOPで10回実行。
今回の環境ではBULK COLLECTのLIMITは50000件あたりで処理速度が頭打ちでした。
DECLARE
  BULK_SIZE CONSTANT PLS_INTEGER := 50000;
  CURSOR C_INFO IS
  SELECT T.INFO FROM TESTTABLE@PDB T;
  TYPE T_INFO IS TABLE OF C_INFO%ROWTYPE INDEX BY BINARY_INTEGER;
  V_INFO T_INFO;
BEGIN
  FOR I IN 1..10
  LOOP
    OPEN C_INFO;
    LOOP
      FETCH C_INFO BULK COLLECT INTO V_INFO LIMIT BULK_SIZE;
      EXIT WHEN V_INFO.COUNT = 0;
    END LOOP;
    CLOSE C_INFO;
  END LOOP;
END;
/

PDB間通信の確認と一緒に、仮想マシンを複数台使用して、仮想マシンのDB間でも確認しました。
WindowsとLinuxの異種プラットフォーム間でも確認した所、いくつか注意が必要な点がありました。

・DB間のキャラクタセットが異なると速度激減。
 最初、LinuxはAL32UTF8、WindowsはJA16SJISTILDEでDB作成していました。
 しかし、キャラクタセット変換で速度低下した為、WindowsもAL32UTF8へ統一しました。

・パケットのジャンボフレーム化で処理速度改善。
 仮想マシン間の通信では、1.5Kの通常フレームより、9Kのジャンボフレームの方が高速でした。
 Hyper-Vの仮想スイッチ、各ゲストOSのNICでジャンボフレームを有効化しました。

・dblinkはEZCONNECTで作成。
 dblinkの接続文字列には、EZCONNECTの'192.168.x.y/[service_name]'を使用しました。
 TNSNAMESのローカルネーミングメソッドも使用可能ですが、複数端末、複数DBを追加するのが大変だったので、tnsnames.ora変更不要のEZCONNECTとしました。

 <4-1.パフォーマンス・レース!>

ようやく本題のPDB間通信の速度検証する準備が整いました。
PDB間/DB間/異種PF間で6人のレーサーが登場します。
・SQLPLUSからPL/SQLのBULK COLLECTを実行し、経過時間を各構成で比較。
・仮想マシンはWindows2台、Linux2台の計4台使用。
・Windowsは2012R2、LinuxはOracle Linux 6.7(UEK)を使用。
・DBはWindows、Linux共に12.1.0.2 EEを使用。
・WindowsとLinuxの実線テーブルに同一テストデータを用意。点線テーブルはdblink経由での参照。
・Windowsの仮想マシンのDB間通信では、タスクマネージャからネットワークの使用帯域も確認。

構成


結果
構成 経過時間 帯域
@ Windows CDB内 PDB間 00:00:39.23 -
A Windows→Windows DB間 00:00:33.25 2.7Gbps
B Linux CDB内 PDB間 00:00:28.04 -
C Linux→Linux DB間 00:00:40.28 -
D Linux→Windows DB間 00:00:41.61 2.1Gbps
E Linux PDB内 00:00:05.95 -

レース結果は E >> B > A > @ > C > D でした。

・ELinux PDB内 のテーブル直接参照は、PL/SQLのBULK COLLECTがネックとなっていない事を確認する為の特別参加。帯域は15Gbps相当。
・LinuxのDB間通信 CLinux→Linux DB間 と DLinux→Windows DB間 は同程度。
・Linuxでは BLinux CDB内 PDB間 > CLinux→Linux DB間。PDB間通信は1.4倍高速。
●Windowsでは AWindows→Windows DB間 > @Windows CDB内 PDB間。PDB間通信は0.8倍低速。

この結果での問題点は、Windowsでは同一仮想マシンのCDB内のPDB間通信よりも、Hyper-Vの仮想ネットワークを経由した別仮想マシンとのDB間通信の方が速いという点です。
自組織内からの問い合わせより、他組織経由で自組織へ問い合わせた方が速い。組織的な腐敗や何らかの陰謀を連想させます。

・仮説1「WindowsでのOracle PDB間通信が腐っている。MicrosoftかOracleの陰謀。」

 <4-2.遅い処理は見つけたものの>

遅い処理を洗い出す為には、Diagnostics Packが必要ですが、Active Session Historyが便利です。
V$ACTIVE_SESSION_HISTORYでは1秒毎に情報が取得されます。特別な準備無に全セッションで1秒毎にトレースをとっている様なものです。

CDB$ROOTでV$ACTIVE_SESSION_HISTORY.SAMPLE_TIMEを処理開始/終了日時で絞り込み、必要項目を GROUP BYしました。
COUNT(*)が大きい行が遅い処理になるはずです。

BLinux CDB内 PDB間 ASH
COUNT(*) PROGRAM MODULE CON_ID SESSION_TYPE EVENT SESSION_STATE SQL_OPNAME
1 oracle@hostname (M000) MMON_SLAVE 1 BACKGROUND db file sequential read WAITING INSERT
5 sqlplus.exe SQL*Plus 4 FOREGROUND SQL*Net more data from dblink WAITING SELECT
5 oracle@hostname (TNS V1-V3) oracle@hostname (TNS V1-V3) 3 FOREGROUND ON CPU SELECT
9 oracle@hostname (TNS V1-V3) oracle@hostname (TNS V1-V3) 3 FOREGROUND SQL*Net more data to client WAITING SELECT
12 sqlplus.exe SQL*Plus 4 FOREGROUND ON CPU SELECT

@Windows CDB内 PDB間 ASH
COUNT(*) PROGRAM MODULE CON_ID SESSION_TYPE EVENT SESSION_STATE SQL_OPNAME
1 sqlplus.exe SQL*Plus 4 FOREGROUND ON CPU PL/SQL EXECUTE
2 ORACLE.EXE (PSP0) 1 BACKGROUND ON CPU
5 sqlplus.exe SQL*Plus 4 FOREGROUND ON CPU SELECT
23 sqlplus.exe SQL*Plus 4 FOREGROUND SQL*Net more data from dblink WAITING SELECT
37 ORACLE.EXE ORACLE.EXE 3 FOREGROUND SQL*Net more data to client WAITING SELECT

・ネットワーク系の待機イベントが多い。
 Linux、WindowsどちらもEVENTで、dblink側の「SQL*Net more data to client」と、テーブル側の「SQL*Net more data from dblink」が計上されています。

・Windows側のCPU負荷が計上されていない?
 Linux側ではSESSION_STATE=「ON CPU」が計上されていますが、Windows側ではあまり計上されていません。
 タスクマネージャのCPU使用率は90%と高負荷だったので、もっとSESSION_STATE=「ON CPU」が計上されても良い筈です。

V$ACTIVE_SESSION_HISTORYの1秒毎のサンプリングではWindows側のCPU負荷が計上されなかった為、SQLトレースを有効化して再確認しました。
TKPROFで整形して、最も負荷が掛かっていたSQLは、Linux、Windowsどちらも下記のSELECT文です。

BLinux CDB内 PDB間 TKPROF
SELECT T.INFO
FROM
 TESTTABLE@PDB T
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute     10      0.00       0.00          0          0          0           0
Fetch      210     18.80      21.67          0          0          0    10000000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      221     18.80      21.67          0          0          0    10000000

@Windows CDB内 PDB間 TKPROF
SELECT T.INFO
FROM
 TESTTABLE@PDB T
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute     10      0.00       0.00          0          0          0           0
Fetch      210     30.81      37.26          0          0          0    10000000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      221     30.81      37.27          0          0          0    10000000

SQLトレースでは、FETCHのCPU負荷が高い事が判りました。

@Windows CDB内 PDB間 実行時は、タスクマネージャでCPU使用率が90%近くまで上がりました。
仮想マシンには2CPU割り当てていたのですが、3CPUへ変更するとCPU使用率は60%まで下がったものの処理時間は変わりませんでした。
どうもマルチスレッドに対応していない処理がネックとなっている様な気がします。
2台(DB間)で動かすと分散実行されるので、1台(CDB内 PDB間)で動かすより速くなるのかも知れません。

遅い処理は見つけたものの、対策に結び付きませんでした。

 <4-3.更なる陰謀>

更に別の構成でも確認しました。
Windowsの同一マシン内にNon-CDBの別インスタンスを2つ作成し、Non-CDB間でdblinkした所、@Windows CDB内 PDB間 とほぼ同等の処理時間でした。
PDB間通信が遅いというより、同一マシン内でのDB間通信が遅い事になります。

同一マシン内でのDB間通信が遅いのならば、ループバック接続に問題があるのかも知れません。
PDB内に'127.0.0.1/[自service_name]'のdblinkを作成し、ローカルループバックアドレスのdblink経由でPL/SQLのBULK COLLECTを実行しました。
結果、Windows PDB内 ローカルループバック = @Windows CDB内 PDB間 とほぼ同等の処理時間となりました。
Linuxでも同様で、Linux PDB内 ローカルループバック = BLinux CDB内 PDB間 となりました。

構成


・仮説2「Windowsでのループバック接続が腐っている。MicrosoftかOracleの陰謀。」

ネットワーク帯域を調べる為、iperf2を使用しました。
iperf2では、TCP window sizeを変更すると、ネットワーク帯域が増減しました。
・Windows内ループバック、Windows→Windows、Linux内ループバック、Linux→Linuxでネットワーク帯域調査。
・iperfのサーバ側、クライアント側で、TCP window sizeを64Kから2048Kまで順次変更(Linux側では-wの設定値の2倍で実行される)。
・サーバ側: iperf -s -w 64-2048k
・クライアント側: iperf -c 192.168.x.y or 127.0.0.1 -w 64-2048k

結果(iperf2)
TCP window size (KB) Windows内ループバック Windows→Windows Linux内ループバック Linux→Linux
64 7.12 4.49 11.3 1.2
128 7.15 6.8 16.6 2.32
256 6.79 8.24 22 3.04
512 7.31 9.01 24 4.14
1024 7.4 8.39 23.7 4.73
2048 7.69 8.67 21.6 5.4

グラフ(iperf2)


・Linuxでは Linux内ループバック接続 >> Linux→Linux間通信。
・Windows→Windows間通信 >> Linux→Linux間通信。Hyper-V仮想ネットワークはWindowsの方が最適化されている。
・Windows→Windows間通信、Windows内ループバック、Linux内ループバックは TCP window size = 512KB で頭打ち。
・TCP window size <= 128KB では Windows内ループバック接続 > Windows→Windows間通信。
・TCP window size >= 256KB では Windows→Windows間通信 > Windows内ループバック接続 へ逆転。
・Windows内ループバック接続は、Linux内ループバック接続と比べて遅い。

iperf2の結果を見るとWindows内ループバック接続に問題がありそうな気配です。

Windows版のiperf2.0.5が32bit版だったので、64bit版のiperf3.0.11でも同様に確認しました。
バッファ長のデフォルト値がiperf2の8KBからiperf3では128KBへ変更されていた為、両方確認しました。
iperf3ではサーバ側のオプション設定が不可となっていました。
・サーバ側: iperf3 -s
・クライアント側: iperf3 -c 192.168.x.y or 127.0.0.1 -w 64-2048k (-l 8k)

結果(iperf3 8KB)
TCP window size (KB) Windows内ループバック Windows→Windows Linux内ループバック Linux→Linux
64 3.45 1.41 6.39 1.53
128 3.28 1.56 7.49 2.54
256 2.37 1.72 7.27 3.51
512 3.04 1.67 7.34 4.66
1024 2.17 1.63 7.51 5.09
2048 1.28 1.57 7.59 4.76

グラフ(iperf3 8KB)


結果(iperf3 128KB)
TCP window size (KB) Windows内ループバック Windows→Windows Linux内ループバック Linux→Linux
64 6.67 4.65 11.6 2.29
128 7.14 6.84 15.5 3.45
256 7.43 7.64 20 4.33
512 7.33 7.69 20.5 5.17
1024 7.29 6.74 19.4 6.3
2048 7.78 6.03 20.5 6.98

グラフ(iperf3 128KB)


・バッファ長8KBのiperf3はiperf2よりも遅い。
・iperf3でもLinux内ループバック接続が最速。
・iperf3ではWindows内ループバック > Windows→Windows間通信 の範囲が多い。

iperf3の結果を見るとWindows内ループバック接続はWindows→Windows間通信と比べると悪くは無さそうです。
アプリケーション側の使い方次第でWindows内ループバック接続は問題が発生するのかも知れません。
Microsoftの腐敗なのか、Oracleの陰謀なのか、真相まで辿り着けませんでした。

12cでは、THREADED_EXECUTION、DEDICATED_THROUGH_BROKER_listener-nameで、 Linuxでも一部プロセスをまとめてマルチスレッド化出来る様になりました。
マルチスレッド化でプロセス数が削減されると、プロセス自体のメモリ削減や、共有メモリ(SGA)のPage Table Entry使用量削減に効果があります。
Windowsではかなり昔のバージョンからoracle.exe内でマルチスレッド化しています。
その点では、WindowsはOracleのDB統合に向いているプラットフォームと言えなくもないです。
中にはHugePagesの事を知らずにLinuxでのDB統合を止めたベンダーもあったそうです。
しかし、Windowsではマシン内のDB間通信の遅さやCPU高負荷が問題となる事もありえそうです。

 <5.イベント資料>

Oracleに限りませんが、ベンダーが推している機能はベンダー自身が情報提供しています。
マルチテナントについても昨今のイベントで発表がありました。
資料によると、dblinkでの他システムへのアクセス性能を考慮して、本番環境ではスキーマ分割を採用したとの事でした。

Oracle DBA & Developer Days 2014
http://www.oracle.com/webfolder/technetwork/jp/ondemand/ddd2014/B1-4.pdf
事例から見えてきたマルチテナント・アーキテクチャとOracle Database 12c新機能の活用ポイント

Oracle CloudWorld Tokyo 2015
http://www.oracle.co.jp/campaign/cloudworld/download/pdf/S1-508.pdf
事例から見えてきたマルチテナント・アーキテクチャの活用ポイント

丁度本日2015/12/08から、品川でOracleのイベントが開催されます。
12.2の情報や事例紹介が楽しみです。

Oracle Cloud Days Tokyo
http://www.oracle.co.jp/events/clouddays/2015/

Oracle DBA & Developer Day 2015
http://www.oracle.co.jp/events/ddd2015/

 <6.まとめ>

・かなり昔のSQL*Netでも圧縮機能有。
・PL/SQLのBULK COLLECTはとても速い。
・WindowsでのPDB間通信(ループバック接続)は遅い。

明日はAyumu Shibataさんです。

posted by charade at 00:00| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする