クリアフィルター
記事
Toshihiko Minamoto · 2021年7月8日
### 目的
このツールは、データベース内からランダム読み出し入力/出力(IO)を生成するために使用されます。 このツールの目的は、目標IOPSを達成し、許容範囲内のディスク応答時間の維持を確保するために、可能な限り多くのジョブを駆動することです。 IOテストから収集された結果は、IOサブシステムに基づいて構成ごとに異なります。 これらのテストを実行する前に、対応するオペレーティングシステムとストレージレベルの監視が、今後の分析のためにIOパフォーマンスの測定データーを保存するように設定されていることを確認してください。
### 方法論
少数のプロセスでプロセスごとに10,000回の反復から始めます。 オールフラッシュストレージアレイでは、プロセスごとに100,000回の反復を使用します。 次に、10ジョブから開始して、10、20、40など追加し、プロセスの数を増やしていきます。 応答時間が一貫して10ミリ秒を超えるか、計算されたIOPSが直線的に増加しなくなるまで、個々のテストを実行し続けます。
目安として、8KBおよび64KBのデータベースランダム読み出し(キャッシュされていない)の次の応答時間は、通常、オールフラッシュアレイで許容されます。
* 平均2ミリ秒以下
* 5ミリ秒を下回らない
このツールでは、事前に拡張された空のIRIS.DATデータベースが、サーバーのメモリサイズの少なくとも2倍であり、ストレージコントローラーのキャッシュサイズの少なくとも4倍である必要があります。 読み出しがファイルシステムキャッシュにキャッシュされてしまわないように、データベースをメモリ容量よりも大きくする必要があります。
このツールは、データベースブロックをメモリに読み込ませるObjectScript VIEWコマンドを使用するため、期待した結果が得られない場合は、恐らくすべてのデータベースブロックがすでにメモリ内にあるということになります。
### 仕様と目標
次の表に、環境の仕様と目標を記入してください。
| 仕様 | 例 |
| --------- | --------------------------------------------------------------------- |
| ストレージ | ストレージアレイの仕様 |
| 物理サーバー | CPU、メモリ仕様 |
| 仮想マシン | Red Hat Enterprise Linux 7 24 vCPU, 40GB vRAM |
| データベースサイズ | 200GB |
| 共有メモリ | Huge Pagesを使用して割り当てられた26956MBの共有メモリ:24000MBのグローバルバッファ、1000MBのルーチンバッファ |
| 目標IOPS | 2000 |
| 目標応答時間 | 5ミリ秒以下 |
### インストール
[こちら](https://github.com/intersystems/random-read-performance-tool)からGitHubで**PerfTools.RanRead.xml**ツールをダウンロードします。
**PerfTools.RanRead.xml**をUSERネームスペースにインポートします。
USER> do $system.OBJ.Load("/tmp/PerfTools.RanRead.xml","ckf")
Helpメソッドを実行して、すべてのエントリポイントを確認します。 すべてのコマンドが%SYSで実行されます。
USER> do ##class(PerfTools.RanRead).Help()
InterSystems Random Read IO Performance Tool
--------------------------------------------
do ##class(PerfTools.RanRead).Setup(Directory,DatabaseName,SizeGB,LogLevel)
- 同じ名前でデーターベースとネームスペースを作成します。 ログレベルは0〜3の範囲である必要があります。0は「なし」、3は「詳細」となります。
do ##class(PerfTools.RanRead).Run(Directory,Processes,Iterations)
- ランダム読み出しIOテストを実行します。
do ##class(PerfTools.RanRead).Stop()
- 全てのバックグラウンドジョブを終了します。
do ##class(PerfTools.RanRead).Reset()
- ^PerfTools.RanRead* に保管されているランダム読み出し履歴を削除します
do ##class(PerfTools.RanRead).Export(directory)
- 全てのランダム読み出しテストの履歴の概要をタブ区切りテキストファイルにエクスポートします。
### セットアップ
テストする物理ホストのメモリの約2倍のサイズのZRANREADという空の(事前に拡張された)データベースを作成します。 空のデータベースがストレージコントローラーのキャッシュサイズの少なくとも4倍であることを確認します。 手動で作成するか、次の方法を使用してネームスペースとデータベースを自動的に作成できます。
USER> do ##class(PerfTools.RanRead).Setup("/usr/iris/db/zranread","ZRANREAD",100,1)
Creating 100GB database in /usr/iris/db/zranread/
Database created in /usr/iris/db/zranread/
Run %Installer Manifest...
2016-05-23 13:33:59 0 PerfTools.RanRead: Installation starting at 2016-05-23 13:33:59, LogLevel=1
2016-05-23 13:33:59 1 CreateDatabase: Creating database ZRANREAD in /usr/iris/db/zranread// with resource
2016-05-23 13:33:59 1 CreateNamespace: Creating namespace ZRANREAD using ZRANREAD/ZRANREAD
2016-05-23 13:33:59 1 ActivateConfiguration: Activating Configuration
2016-05-23 13:34:00 1 EnableEnsemble: Enabling ZRANREAD
2016-05-23 13:34:00 1 ActivateConfiguration: Activating Configuration
2016-05-23 13:34:00 0 PerfTools.RanRead: Installation succeeded at 2016-05-23 13:34:00
2016-05-23 13:34:00 0 %Installer: Elapsed time 1.066633s
Database /usr/iris/db/zranread/ ready for testing.
do ##class(PerfTools.RanRead).Run(directory,processes,iterations) e.g.
do ##class(PerfTools.RanRead).Run("/usr/iris/db/zranread/",1,10000)
### 実行
プロセスの数を増やしながらRunメソッドを実行して、応答時間をメモします。
テストが速すぎる場合や結果が期待どおりでない場合は、反復回数を10000に増やします。
USER> do ##class(PerfTools.RanRead).Run("/usr/iris/db/zranread",20,10000)
InterSystems Random Read IO Performance Tool
--------------------------------------------
Starting 20 jobs in the background.
To terminate jobs run: do ##class(PerfTools.RanRead).Stop()
Waiting for jobs to finish.........................
Random read background jobs finished.
20 processes (1000 iterations) average response time = 7.18ms
Calculated IOPS = 2787
### 結果
各実行の結果は、USERのPerfTools.RanReadというSQLテーブルに保存されます。 次のSQLクエリを実行すると、結果の概要を確認できます。
SELECT RunDate,RunTime,Database,Iterations,Processes,
{fn ROUND(AVG(ResponseTime),2)} As ResponseTime,
{fn ROUND(AVG(IOPS),0)} As IOPS
FROM PerfTools.RanRead
GROUP BY Batch
結果セットをタブ区切りのテキストファイルにエクスポートするには、次の手順を実行します。
USER> do ##class(PerfTools.RanRead).Export("/usr/iris/db/zranread/")
Exporting summary of all random read statistics to /usr/iris/db/zranread/PerfToolsRanRead_20160523-1408.txt
Done.
### 分析
エクスポートしたテキストファイルをExcelで開いてコピーし、PerfToolsRandomRead \ _Analysis \ _Template.xlsxスプレッドシートに貼り付け、グラフ化します。

サンプルスプレッドシートは[こちら](https://github.com/intersystems/random-read-performance-tool)からGitHubでダウンロードすることができます。
### クリーンアップ
テストの実行が終了したら、次のコマンドを実行して履歴を削除します。
%SYS> do ##class(PerfTools.RanRead).Reset()
記事
Tomoko Furuzono · 2020年11月24日
最近、InterSystems 内で PHP から Caché ベースの Web サービスに接続が必要になる事例がいくつかありました。 これらの最初の事例とは、実はこの開発者コミュニティそのものであり、他の InterSystems サイト/アプリケーションとのシングルサインオンに Web サービスを使用しています。 次の例は、パスワード認証を使用して PHP から Caché ベースの Web サービス(具体的には SAMPLES ネームスペースの Web サービス)に接続する方法を示しています。
(注意: この例は、/csp/samples に対してパスワード認証が有効になっていることを前提としています。)
<?php// ユーザー名/パスワード用の標準 SOAP ヘッダー// 出典元: http://stackoverflow.com/questions/13465168/php-namespaces-in-soapheader-child-nodes class WSSESecurityHeader extends SoapHeader { public function __construct($username, $password) { $wsseNamespace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'; $security = new SoapVar( array(new SoapVar( array( new SoapVar($username, XSD_STRING, null, null, 'Username', $wsseNamespace), new SoapVar($password, XSD_STRING, null, null, 'Password', $wsseNamespace) ), SOAP_ENC_OBJECT, null, null, 'UsernameToken', $wsseNamespace )), SOAP_ENC_OBJECT ); parent::SoapHeader($wsseNamespace, 'Security', $security, false); }}// Web サービスに接続するための主要パラメーター:$location = "http://localhost:57772/csp/samples/SOAP.Demo.cls";$uri = "http://tempuri.org";$username = "_SYSTEM";$password = "SYS";// SOAP クライアントを WSDL から構築する場合、または(その目的のために存在するさまざまなツールを使用して)// WSDL を使用して PHP クラスを生成する場合、?WSDL=1 とユーザー名/パスワードは// URL の最後に追加する必要があります: $wsdl = $location . "?WSDL=1&CacheUserName=" . $username . "&CachePassword=" . $password;// 理論的に言えば、次のようなことができるようになります。 // $client = new SoapClient($wsdl, array("trace"=>1)); // 多くの場合はこれで十分です。// ただし、SAMPLES ネームスペース内の SOAP.Demo の WSDL は次のように他のクラスで// 定義されている追加のスキーマを参照します:// <s:import namespace="http://tempuri.org/QueryByName_DataSet" schemaLocation="http://localhost:57772/csp/samples/SOAP.Demo.QueryByName.DS.cls?XSD"/> // PHP の WSDL 処理で CSP セッション Cookie を使用させたり、これらを取得する際に URL 内で // 資格情報を渡す方法はないようですので、これは失敗します。 回避策は代わりに location/uri を使用し、// WSDL なしで SoapClient を作成することです。// SoapClient オブジェクトを作成 $client = new SoapClient(null, array( "trace" => 1, "location" => $location, "uri" => $uri, "style" => SOAP_DOCUMENT, "use" => SOAP_LITERAL)); // セキュリティヘッダーを追加します。$client->__setSoapHeaders(new WSSESecurityHeader($username, $password));// ID でPersonを取得します。ここでは URL から取得しますが、デフォルトでは ID 1であるため、常に何かが表示されます。$id = 1;if (isset($_GET["id"])) { $id = $_GET["id"];}// SOAP 呼び出しのパラメーター名と値を持つオブジェクト$request = new stdClass();$request->id = $id;// これは FindPersonSoapIn のキーを持つ連想配列になります(WSDL を参照)$params = array();$params['FindPersonSoapIn']=$request;// ソープコールのオプションの配列では、参照するWSDLがないので、 soapactionを指定しなければなりません。// PHP のデフォルト値 は <uri>#<method> ですが、これは正しくありません。$options = array('soapaction'=>$uri.'/SOAP.Demo.FindPerson');// 実際に Web サービスを呼び出します。$result = $client->__soapCall("FindPerson",$params,$options);// 応答をページにダンプします。var_dump($result);?>
記事
Toshihiko Minamoto · 2022年1月6日
キーワード: Python、JDBC、SQL、IRIS、Jupyterノートブック、Pandas、Numpy、および機械学習
## 1. 目的
これは、デモの目的で、Jupyterノートブック内でPython 3によってIRIS JDBCドライバーを呼び出し、SQL構文でIRISデータベースインスタンスにデータを読み書きする、5分程度の簡単なメモです。
昨年、私は[CacheデータベースへのPythonバインディング](https://jp.community.intersystems.com/node/505841)(セクション4.7)について簡単に触れました。 そこで、Pythonを使ってIRISデータベースに接続し、そのデータをPandasデータフレームとNumPy配列に読み込んで通常の分析を行ってから、事前処理済みまたは正規化されたデータをML/DLパイプラインに通すためにIRISに書き込む作業においてのオプションと議論について要約しましょう。
すぐに思い浮かぶ簡単な**オプション**がいくつかあります。
1. **ODBC**: Python 3とネイティブSQLを使ったPyODBCを使ってはどうでしょうか?
2. **JDBC**: Python 3とネイティブSQLを使ったJayDeBeApiはどうでしょうか?
3. **Spark**: PySparkとSQLを使ったら?
4. **IRIS用PythonネイティブAPI**: 前に使用したCache用Pythonバイディングを拡張してみたらどうでしょうか?
5. **IPtyhon Magic SQL %%sql**とした場合、 [それ](https://github.com/catherinedevlin/ipython-sql)はまだIRISで動作するでしょうか?
ここで見逃されたオプションがほかにありますか? それらも試してみたいですね。
## 2. 範囲
通常のJDBCアプローチからはじめましょう。 ODBC、Spark、PythonネイティブAPIについては、次回の簡易メモで要約することにします。
### 範囲内:
このクイックデモでは、以下の一般的なコンポーネントについて触れています。
Anaconda
Jupyterノートブック
Python 3
JayDeBeApi
JPyPe
Pandas
NumPy
IRIS 2019.xのインスタンス
### 範囲外:
この簡易メモでは、以下の項目には触れていません。重要な項目であり、具体的なサイトソリューション、デプロイ、およびサービスで個別に対処される可能性があります。
エンドツーエンドのセキュリティ
機能しないパフォーマンスなど
トラブルシューティングとサポート
ライセンス
## 3. デモ
### 3.1 IRISインスタンスを実行する
私は単にIRIS 2019.4コンテナーを「リモート」データベースサーバーとして実行しましたが、 適切な承認済みのアクセス権を持つIRISインスタンスであれば、どれでも使用できます。
zhongli@UKM5530ZHONGLI MINGW64 /c/Program Files/Docker Toolbox$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESd86be69a03ab quickml-demo "/iris-main" 3 days ago Up 3 days (healthy) 0.0.0.0:9091->51773/tcp, 0.0.0.0:9092->52773/tcp quickml
### 3.2 AnacondaとJupyterノートブック
Anacondaについては[こちら](https://jp.community.intersystems.com/node/505841)のセクション4.1に説明されたセットアップアプローチ、Jupyterノートブックについては[こちら](https://jp.community.intersystems.com/node/506626)に説明されたセットアップアプローチをノートパソコンで再利用します。 Python 3.xはこのステップでインストールされます。
### 3.3 JayDeBeApiとJPyPeをインストールする
私は自分のJupyterノートブックを起動してから、そのセルで以下を実行し、Python-to-JDBC/Javaブリッジをセットアップしました。
!conda install --yes -c conda-forge jaydebeapi
この記事の執筆時点(2020年1月)では、JeDeBeApiはJPype 0.7を使用していますが、既知のバグによって機能しないため、0.6.3にダウングレードする必要がありました。
!conda install --yes -c conda-forge JPype1=0.6.3 --force-reinstall
### 3.4 JDBC経由でIRISデータベースに接続する
公式の[JDBCからIRISへの接続に関するドキュメント](https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_jdbc)はこちらにあります。
JDBCでPyshon SQLを実行するには、以下のコードを例として使用しました。 このIRISインスタンスの「USER」ネームスペース内にある「`DataMining.IrisDataset`」というデータテーブルに接続します。
### 1. Set environment variables, if necessary#import os#os.environ['JAVA_HOME']='C:\Progra~1\Java\jdk1.8.0_241'#os.environ['CLASSPATH'] = 'C:\interSystems\IRIS20194\dev\java\lib\JDK18\intersystems-jdbc-3.0.0.jar'#os.environ['HADOOP_HOME']='C:\hadoop\bin' #winutil binary must be in Hadoop's Home
### 2. Get jdbc connection and cursorimport jaydebeapiurl = "jdbc:IRIS://192.168.99.101:9091/USER"driver = 'com.intersystems.jdbc.IRISDriver'user = "SUPERUSER"password = "SYS"#libx = "C:/InterSystems/IRIS20194/dev/java/lib/JDK18"jarfile = "C:/InterSystems/IRIS20194/dev/java/lib/JDK18/intersystems-jdbc-3.0.0.jar"
conn = jaydebeapi.connect(driver, url, [user, password], jarfile)curs = conn.cursor()
### 3. specify the source data tabledataTable = 'DataMining.IrisDataset'
### 4. Get the result and displaycurs.execute("select TOP 20 * from %s" % dataTable)result = curs.fetchall()print("Total records: " + str(len(result)))for i in range(len(result)): print(result[i])
### 5. CLose and clean - I keep them open for next accesses.#curs.close()#conn.close()
Total records: 150
(1, 1.4, 0.2, 5.1, 3.5, 'Iris-setosa')
(2, 1.4, 0.2, 4.9, 3.0, 'Iris-setosa')
(3, 1.3, 0.2, 4.7, 3.2, 'Iris-setosa')
... ...
(49, 1.5, 0.2, 5.3, 3.7, 'Iris-setosa')
(50, 1.4, 0.2, 5.0, 3.3, 'Iris-setosa')
(51, 4.7, 1.4, 7.0, 3.2, 'Iris-versicolor')
... ...
(145, 5.7, 2.5, 6.7, 3.3, 'Iris-virginica')
... ...
(148, 5.2, 2.0, 6.5, 3.0, 'Iris-virginica')
(149, 5.4, 2.3, 6.2, 3.4, 'Iris-virginica')
(150, 5.1, 1.8, 5.9, 3.0, 'Iris-virginica')
ここで、JDBCでPythonが機能していることをテストしました。 以下はちょっとした日常業務的なデータ分析と通常のMLパイプラインのプリプロセッシングであり、後のデモと比較で何度も触れる内容です。ここでは、利便的に添付しています。
### 3.5 SQL結果をPandasデータフレーム、そしてNumPy配列に変換する
PandasとNumPyパッケージがインストールされていない場合は、上記のセクション3.3と同様に、Condaを使ってインストールします。
次に、以下のコードを例として実行しました。
### transform SQL results "sqlData"to Pandas dataframe "df", then further to NumPy array "arrayN" for further ML pipelines import pandas as pdsqlData = "SELECT * from DataMining.IrisDataset"df= pd.io.sql.read_sql(sqlData, conn)df = df.drop('ID', 1)df = df[['SepalLength', 'SepalWidth', 'PetalLength', 'PetalWidth', 'Species']]
# set the labels to 0, 1, 2, for NumPy matrixdf.replace('Iris-setosa', 0, inplace=True)df.replace('Iris-versicolor', 1, inplace=True)df.replace('Iris-virginica', 2, inplace=True)
# turn dataframe into Numpy arrayarrayN = df.to_numpy()
### 6. CLose and clean - if connection is not needed anymore?#curs.close()#conn.close()
いつものように現在のデータを覗いてみましょう。
df.head(5)
df.describe()
データフレームと、ソースデータテーブルから正規化されたNumPy配列を取得して、使用できるようになりました。
もちろん、[こちらのリンクのように](http://www.lac.inpe.br/~rafael.santos/Docs/CAP394/WholeStory-Iris.html)、MLユーザーが以下のようにPython で行うような様々なルーチン分析を試して、Rを置き換えることができます。
データソースはこちらから引用されています。
### 3.6 SQLでデータを分割してIRISデータベースに書き込む
確かに、以降でIRISの刺激的なML機能で使用できるように、データを通常どおりトレーニングセットと検証またはテストセットに分割し、一時データベーステーブルに書き込むことができます。
import numpy as np from matplotlib import pyplotfrom sklearn.model_selection import train_test_split
# keep e.g. 20% = 30 rows as test data; trained on another e.g. 80% = 120 rowsX = arrayN[:,0:4]y = arrayN[:,4]X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1, shuffle=True)
# make 80% of random rows into a Train setlabels1 = np.reshape(Y_train,(120,1))train = np.concatenate([X_train, labels1],axis=-1)
# make 20% of left rows into Test setlTest1 = np.reshape(Y_validation,(30,1))test = np.concatenate([X_validation, lTest1],axis=-1)
# write the train data set into a Pandas framedfTrain = pd.DataFrame({'SepalLength':train[:, 0], 'SepalWidth':train[:, 1], 'PetalLength':train[:, 2], 'PetalWidth':train[:, 3], 'Species':train[:, 4]})dfTrain['Species'].replace(0, 'Iris-setosa', inplace=True)dfTrain['Species'].replace(1, 'Iris-versicolor', inplace=True)dfTrain['Species'].replace(2, 'Iris-virginica', inplace=True)
# write the test data into another Pandas framedfTest = pd.DataFrame({'SepalLength':test[:, 0], 'SepalWidth':test[:, 1], 'PetalLength':test[:, 2], 'PetalWidth':test[:, 3], 'Species':test[:, 4]})dfTest['Species'].replace(0, 'Iris-setosa', inplace=True)dfTest['Species'].replace(1, 'Iris-versicolor', inplace=True)dfTest['Species'].replace(2, 'Iris-virginica', inplace=True)
### 3. specify temp table names#dataTable = 'DataMining.IrisDataset'dtTrain = 'TRAIN02'dtTest = "TEST02"
### 4. Create 2 temporary tables - you can try drop tables then re-create them every timecurs.execute("Create Table %s (%s DOUBLE, %s DOUBLE, %s DOUBLE, %s DOUBLE, %s VARCHAR(100))" % (dtTrain, dfTrain.columns[0], dfTrain.columns[1], dfTrain.columns[2], dfTrain.columns[3], dfTrain.columns[4]))curs.execute("Create Table %s (%s DOUBLE, %s DOUBLE, %s DOUBLE, %s DOUBLE, %s VARCHAR(100))" % (dtTest, dfTest.columns[0], dfTest.columns[1], dfTest.columns[2], dfTest.columns[3], dfTest.columns[4]))
### 5. write Train set and Test set into the tales. You can try to delete old record then insert everytime. curs.fast_executemany = Truecurs.executemany( "INSERT INTO %s (SepalLength, SepalWidth, PetalLength, PetalWidth, Species) VALUES (?, ?, ?, ? ,?)" % dtTrain, list(dfTrain.itertuples(index=False, name=None)) )curs.executemany( "INSERT INTO %s (SepalLength, SepalWidth, PetalLength, PetalWidth, Species) VALUES (?, ?, ?, ? ,?)" % dtTest, list(dfTest.itertuples(index=False, name=None)) )
### 6. CLose and clean - if connection is not needed anymore?#curs.close()#conn.close()
ここで、IRIS管理コンソールまたはターミナルSQLコンソールに切り替えると、120行のTRAIN02と30行のTEST02という2つの一次テーブルが作成されているのがわかります。
この記事は非常に短い簡易メモを目的としているため、本内容はここまでとします。
## 4. 警告
* 上記のコンテンツは変更または改善される場合があります。
## 5. 今後の内容
簡易メモを貢献していただける方がいらっしゃらなければ、セクション3.3と3.4をPyODBC、PySPark、およびIRIS用PythonネイティブAPIに置き換えることにします。貢献していただけるのであれば、大感謝です。