nkjmkzk.net

powered by Kazuki Nakajima

Archive for the ‘cx_oracle’ tag

超シンプルなOracle Database負荷掛けツール、oraload.py

oraload.pyはマルチスレッドでOracle Databaseに負荷をかけられるpythonスクリプトで、猫でも使えるのが特徴です。

  • 現在どれくらいTPSがでるのか?
  • とりあえずデータベースにできるだけ負荷をかけたい!
  • でも負荷掛けの準備はしたくない!

こういうシーンに役立ちます。元々デモ用に作成したものなので精度よりも結果と使い方の「わかりやすさ」を何より重視したツールです。

oraload.pyのダウンロード:http://github.com/nkjm/oraload

oraload.pyを実行すると下記のように1秒ごとに現在のTPSが表意され、最後に平均のTPSが表示されます。ただそれだけ、というシンプルさ。

TPS:    1133
TPS:    1673
TPS:    1946
TPS:    2014
TPS:    2148
TPS:    2236
TPS:    2115
TPS:    2391
TPS:    2526

TPS Average:    1962

oraload.pyはターゲットとなるデータベースノード上で実行することもできますし、他のノードからネットワーク越しに実行することもできます。

 

実行環境

  • cx_Oracleが利用できること(cx_Oracleのインストール方法はこちら
  • interview.pyがインストールされていること(後述)

機能

  • 任意のユーザであらかじめ定義されたSELECTまたはINSERT文をマルチスレッドで繰り返し発行し、そのときのTPSを表示する
  • テストで使用するユーザは既存のものを選択するか新規に自動作成可能 テーブルは自動的に作成

調整できるパラメータ

  • 使用するユーザ
  • 対象となるデータベース(ホスト名/サービス名)
  • クエリタイプ(SELECTまたはINSERT)
  • クエリ数
  • 負荷の強弱(スレッド数)

使用方法

まず実行環境を整えます。cx_Oracleを先のブログエントリに従ってセットアップし、次にinterview.pyをダウンロードしてインストールします。

interview.pyのダウンロード:http://github.com/nkjm/interview

interview.pyのインストールはダウンロードしたinterview.pyファイルを/usr/lib/python2.4/site-packages/に配置するだけです。

[root@~]# mv interview.py /usr/lib/python2.4/site-packages/

次にoraload.pyをダウンロードします。

oraload.pyのダウンロード:http://github.com/nkjm/oraload

ダウンロードしたoraload.pyをvi等のエディタで開き、SYSDBAで接続するためのアカウント、sys_userとsys_passwordだけ設定します。

[oracle@~]$ vi oraload.py
#!/usr/bin/python
import optparse
import random
import string
import sys
import threading
import time
import cx_Oracle
import interview

### Configuration Area ###
sys_user = 'sys'
sys_password = 'secret'
default_user = ''
default_password = ''
default_ip = ''
default_service = ''

*sys_user、sys_passwordは必ずしも設定する必要はありませんが、設定しない場合にはあらかじめデータベース上にテストで使用するユーザが作成されている必要があります。

以上でセットアップは完了です。oraload.pyを実行してみましょう。プロンプトが表示されテストに必要な情報を訊いてきますので入力していきます。

[oracle@~]$ ./oraload.py

Please enter DB IP Address: 172.22.0.54 <= データベースのIPアドレスまたはホスト名を指定

Please enter DB Service Name: orcl.kawasaki.nkjmkzk.com <= データベースのサービス名を指定

Please select USER NAME from following list. (Enter the number)

        [0] DBSNMP
        [1] SCOTT
        [2] SYSMAN
        [3] MGMT_VIEW
        [4] CLOUD_LARGE
        [5] SYS
        [6] SYSTEM
        [7] CLOUD_SURVEY
        [8] FLOWS_FILES
        [9] MDSYS
        [10] ORDSYS
        [11] EXFSYS
        [12] WMSYS
        [13] ORACLE_OCM
        [14] APPQOSSYS
        [15] XS$NULL
        [16] APEX_030200
        [17] OWBSYS_AUDIT
        [18] MDDATA
        [19] ORDDATA
        [20] CTXSYS
        [21] ANONYMOUS
        [22] OUTLN
        [23] DIP
        [24] APEX_PUBLIC_USER
        [25] XDB
        [26] SPATIAL_CSW_ADMIN_USR
        [27] SPATIAL_WFS_ADMIN_USR
        [28] ORDPLUGINS
        [29] OWBSYS
        [30] SI_INFORMTN_SCHEMA
        [31] OLAPSYS
        [32] +Create New User
Answer: 32 <= 新規にユーザを作成することを選択

Please enter NEW USER NAME: nkjm <= 新しいユーザ名を入力

Please enter PASSWORD: secret <= パスワードを入力

Please select TABLESPACE from following list. (Enter the number)
(just Enter to accept default 'USERS')
        [0] SYSTEM
        [1] SYSAUX
        [2] UNDOTBS1
        [3] USERS
        [4] TEMP
Answer: 3 <= このユーザが使用する表領域を選択

New User has been created.

Table has not been created yet. Create it right now? [y/n]: y <= テストに使用するテーブルを自動作成することを選択

Done.

Sequence has not been created yet. Create it right now [y/n]: y <= テストに使用するシーケンスを自動作成することを選択

Done.

Please select Type of Load from following list. (Enter the number)
        [0] select
        [1] insert
Answer: 1 <= 負荷のタイプを選択(初回はデータが入っていないのでselectを選択するとエラーで終了します)

Please enter Number of Queries: 10000 <= クエリ数を指定

Please enter Number of Threads (just Enter to accept default '1'): 4 <= スレッド数(同時接続数)を指定

#Thread-1 taking off...
#Thread-2 taking off...
#Thread-3 taking off...
#Thread-4 taking off...

TPS:    1536
TPS:    1683
TPS:    1817
TPS:    1721
TPS:    1450
TPS:    394
TPS:    0
TPS:    276
TPS:    39
TPS:    683

TPS Average:    927

[oracle@~]$

先ほど対話的に入力した値をワンライナーで入力するには下記のように実行します。

[oracle@~]$ ./oraload.py -u nkjm -p secret -i 172.22.0.54 -s orcl.kawasaki.nkjmkzk.com -o insert -c 10000 -t 4

* -u => ユーザ名
* -p => パスワード
* -i => DBのIPアドレスまたはホスト名
* -s => DBのサービス名
* -o => 負荷のタイプ(selectまたはinsert)
* -c => 発行するクエリ数
* -t => スレッド数(負荷の強弱を調整)

ここまでのテストでデータが20000件程格納されていますので、それを用いたSELECTも実行できます。

[oracle@~]$ ./oraload.py -u nkjm -p secret -i 172.22.0.54 -s orcl.kawasaki.nkjmkzk.com -o select -c 5000 -t 4

また、デフォルトのユーザ名、パスワード、DBのIP、DBのサービスを事前に設定しておくこともできます。

[oracle@~]$ vi oraload.py
#!/usr/bin/python
import optparse
import random
import string
import sys
import threading
import time
import cx_Oracle
import interview

### Configuration Area ###
sys_user = 'sys'
sys_password = 'mexico'
default_user = 'nkjm'
default_password = 'secret'
default_ip = '172.22.0.54'
default_service = 'orcl.kawasaki.nkjmkzk.com'

デフォルト値を設定しておくとオプションなしでoraload.pyを実行したときに、プロンプトにデフォルト値が入力されているためリターンキーを押すだけで進むことができます。

オプションで–helpを指定することで使い方を確認できます。

[oracle@~]$ ./oraload.py --help
usage: ./oraload.py [OPTIONS]

options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -u USER, --user=USER  User Name
  -p PASSWORD, --password=PASSWORD
                        User Password
  -i IP, --ip=IP        Hostname or IP Address of Oracle Database
  -s SERVICE, --service=SERVICE
                        Service Name of Oracle Database
  -o OPERATION, --operation=OPERATION
                        Type of Load [select|insert]
  -c COUNT, --count=COUNT
                        Number of Queries to be produced
  -t THREAD, --thread=THREAD
                        Number of Threads to be launched

さぁ、レッツトライ。

*ソースを見た人はテストデータのセンスに少し驚くでしょう。

without comments

Written by 中嶋 一樹

5月 31st, 2011 at 11:41 am

Posted in Uncategorized

Tagged with , , ,

pythonからOracleに接続するための拡張モジュール、cx_Oracleの基本的な使い方

cx_Oracleはそこそこ本格的な機能を提供してくれるOracle Database接続用のpythonモジュールです。phpのoci8と比較してもデータベースインスタンスを停止/起動するためのPRELIM AUTHモードをサポートしていたり、マルチスレッドで動かすためのTHREADEDモードをサポートしていたりとかゆいところに手が届きます。

このエントリではごく一般的な操作を解説します。データベース及びInstant Clientのバージョンは11g Release 2 x86_64とします。

インストールについてはこちらのエントリを。pythonからOracleに接続するための拡張モジュール、cx_Oracleのインストール方法

cx_Oracleをpythonスクリプト中で使うにはまずcx_Oracleをインポートします。

#!/usr/bin/python

import cx_Oracle

実行時に下記のエラーが出る場合は$LD_LIBRARY_PATHが通っていない可能性があります。

ImportError: libclntsh.so.11.1: cannot open shared object file: No such file or directory

Oracle Instant Clientを利用している場合は/usr/lib/oracle/11.2/client64/libにライブラリがありますので下記のように$LD_LIBRARY_PATHを通します。

[oracle@~]$ export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/client64/lib

まずは接続。個人的にはこれが一番難解なのではと思っています(マジでか)。僕がいつも使っている接続はこの形式です。

conn = cx_Oracle.connect('scott', 'tiger', '172.22.0.54/orcl.kawasaki.nkjmkzk.com')

* scott => ユーザ名
* tiger => パスワード
* 172.22.0.54 => データベースのIPアドレスまたはホスト名 RACの場合にインスタンスを指定する必要がなければSCANを指定
* orcl.kawasaki.nkjmkzk.com => データベースのサービス

ややこしいのが3つ目の172.22.0.54/orcl.kawasaki.nkjmkzk.comの部分。この引数はいろいろなフォーマットがありますが、僕はこのEasy Connectと呼ばれるフォーマットを好んでいます。一般にはtnsnames.oraに定義したエントリ名を使用する方がポピュラーでスクリプト自体は簡素にはなりますが、事前にtnsnames.oraを定義しなければいけないですし、tnsnames.oraがサーチパス上に配置されていなくてはならないのでその部分が汎用的でない気がして僕はあまり使いません。

データベースのIPアドレスまたはホスト名にSCANを使用する場合はデータベースノード上でsrvctlで確認できます。

[oracle@~]$ srvctl config scan
SCAN name: orcl-scan, Network: 1/172.22.0.0/255.255.252.0/eth0
SCAN VIP name: scan1, IP: /orcl-scan.kawasaki.nkjmkzk.com/172.22.0.56

サービスもsrvctlコマンドで確認できます。unique nameとdomainを合わせたものがデフォルトのサービスとなります。

[oracle@~]$srvctl config database -d orcl | grep -e 'Database unique name:' -e 'Domain:'
Database unique name: orcl
Domain: kawasaki.nkjmkzk.com

* orcl.kawasaki.nkjmkzk.comがサービス名となる

明示的に作成したサービスは下記のsrvctlコマンドで確認できます。

[oracle@~]$ srvctl config service

また、上記はノーマルユーザでの接続でしたが、管理作業を行うためにSYSDBAとして接続する場合は次のようにcx_Oracle.SYSDBAフラグを立てます。

conn = cx_Oracle.connect('sys', 'secret', '172.22.0.54/orcl.kawasaki.nkjmkzk.com', cx_Oracle.SYSDBA)

さらに例外処理をきちんと行う場合は下記のようにtry:配下に置き、cx_Oracle.DatabaseErrorの例外を拾うようにします。

try:
    conn = cx_Oracle.connect('scott', 'tiger', '172.22.0.54/orcl.kawasaki.nkjmkzk.com')
except cx_Oracle.DatabaseError,cx_msg:
    print "[ERROR] Failed to connect to Database."
    print "[ERROR cx_Oracle] %s" % cx_msg

* エラーメッセージがcx_msgに代入される

これでデータベースへのセッションが確立されました。次にデータベースに命令を発行しています。
まずはテーブルを作成してみましょう。

先ほど作成したコネクションオブジェクトからカーソルオブジェクトを作成します。これは呪文だと思って実行してください。

cur = conn.cursor()

SQL文を定義してexecute()を発行すればSQL文がデータベースで実行されます。ちなみにSQL文は末尾にセミコロンを入れてはいけません。

sql = "CREATE TABLE TEST_TABLE (COL1 NUMBER)"
cur.execute(sql)

こちらも例外処理を行うには下記のようにtry:配下に置きます。

sql = "CREATE TABLE TEST_TABLE (COL1 NUMBER, COL2 VARCHAR(64))"
try:
    cur.execute(sql)
except cx_Oracle.DatabaseError,cx_msg:
    print "[ERROR] Failed to execute SQL: " + sql
    print "[ERROR cx_Oracle] %s" % cx_msg

データを3件ほどインサートします。デフォルトでは自動でコミットされません。明示的にconn.commit()でコミットする必要があります。

sql = "INSERT INTO TEST_TABLE VALUES (1, 'apple')"
cur.execute(sql)
sql = "INSERT INTO TEST_TABLE VALUES (2, 'orange')"
cur.execute(sql)
sql = "INSERT INTO TEST_TABLE VALUES (2, 'lemon')"
cur.execute(sql)
conn.commit()

データを取得します。データの取得には主にfetchall(), fetchmany(), fetchone()のいずれかを使うことになると思いますが、ここではfetchallを使用しています。fetchallは全検索結果を行を一つのタプルとしてその配列を返します。

sql = "SELECT * FROM TEST TABLE"
cur.execute(sql)
rows = cur.fetchall()
for row in rows:
    print row[0],
    print row[1]

とりあえずここで紹介したメソッドが使えればアプリケーションで求められる基本的な操作はカバーできてしまうかも。

without comments

Written by 中嶋 一樹

5月 29th, 2011 at 1:11 pm

Posted in Uncategorized

Tagged with , ,

pythonからOracleに接続するための拡張モジュール、cx_Oracleのインストール方法

*太古の昔に書いたエントリをリバイスしました。

pythonスクリプトからOracle Databaseに接続するための実装(モジュール)はいくつかあるようですが、いわゆるデファクトっぽいのがcx_Oracleというモジュール。ドキュメント、ダウンロード先等は下記を参照ください。

僕はソースをとってきてインストールすることにしました。OSはOracle Linux 5.6 x86_64。Redhat EnterpriseLinux, CentOS, Scientific Linux等でも確認はしてませんが同じ手順でいけるはずです。コンパイルにはソフトウェア要件としてpython-develとOracle Databaseのクライアントライブラリがインストールされている必要があります。python-develはup2dateやyumコマンドでレポジトリが引っ張ってこれます。

[root@~]# yum install python-devel

レポジトリが登録されていない!という人は下記のコマンドでpublic-yumを登録してください。

[root@~]# cd /etc/yum.repos.d
[root@~]# wget http://public-yum.oracle.com/public-yum-el5.repo
[root@~]# vi public-yum.el5.repo
[ol5_u6_base]
name=Oracle Linux $releasever - U6 - $basearch - base
baseurl=http://public-yum.oracle.com/repo/OracleLinux/OL5/6/base/$basearch/
gpgkey=http://public-yum.oracle.com/RPM-GPG-KEY-oracle-el5
gpgcheck=1
enabled=1
[root@~]# yum install python-devel

Oracle DatabaseのクライアントライブラリはすでにそのOS上にOracle Databaseがインストールされていれば$ORACLE_HOME/libに存在します。クライアント側にOracle Databaseなんてインストールしねぇよ!、という場合はOracle Instant Clientをインストールします。これはフリーで利用可能です。RPMをダウンロードしてインストールしてください。

ダウンロード:http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html

[roo@~]# rpm -ivh oracle-instantclient11.2-basic-11.2.0.2.0.x86_64.rpm oracle-instantclient11.2-devel-11.2.0.2.0.x86_64.rpm

そして上記ライブラリが$ORACLE_HOMEと$LD_LIBRARY_PATHに含まれていることが必要です。Oracle Instant Clientの場合は/usr/lib/oracle/11.2/client64が$ORACLE_HOMEとなり、その下の/usr/lib/oracle/11.2/client64/libを$LD_LIBRARY_PATHに含めます。

[root@~]# export ORACLE_HOME=/usr/lib/oracle/11.2/client64
[root@~]# export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/client64/lib:$LD_LIBRARY_PATH

まずtarボールを/var/opt等に保存して展開。

# tar xvfz cx_Oracle-5.1.tar.gz
# cd cx_Oracle-5.1/

そしてビルド&インストール。

[root@~]# python setup.py build
[root@~]# python setup.py install

これだけでOK。cx_Oracle.soが/usr/lib64/python2.4/site-packages/にインストールされています。

あとはpythonスクリプトの中で、

import cx_Oracle

とすればcx_Oracleのモジュールがロードできるはずです。

$LD_LIBRARY_PATHは忘れないうちにoracleユーザあたりの.bash_profileに登録しておきましょう。

with 3 comments

Written by 中嶋 一樹

5月 29th, 2011 at 1:07 pm

Posted in Uncategorized

Tagged with , ,