■Jasper内で使うイメージのファイルパス
JasperReportで、静的イメージファイルを貼り付けたときに注意することとして
そのイメージのパスの問題がある。
通常、JasperReportをデザインするのは、iReportというツールを使う。
iReportで、静的イメージを貼り付けるには、パレットからImageオブジェクトを選択して
デザイン中のレポートへドラッグすることで貼り付けることができる。
このときに、ダイアログが出て、静的ファイルを選択することとなる。
しかし、この動作によって、設定されるファイルパスは、使用中のiReportがある環境でのファイルパスとなる。
つまり、このJasperReportとImageファイルをサーバなどへ配置した場合、ここで設定されたパスでは、Imageファイルが見つからないことになってしまうことも多く、最終的な実行環境を想定したパスをここで設定しておかなければならない。
■ADempiereでのJasperイメージパスの設定方法
ADempiereでは、AP辞書で登録したJasperファイルやイメージファイルをReportStarterというクラスが処理して、JasperReportのアウトプットを作成する。
このときに、使用されるパスは、以下のようになる。
System.getProperty("java.io.tmpdir") + System.getProperty("file.separator")+"ABCDEFG.png"
つまり、システムプロパティの「java.io.tmpdir」に、Jasper関連のファイルが一時保存されて使用されている。
(C:\Users\ユーザ名\AppData\Local\Temp)
なので、iReportでデザインするときに、ImageオブジェクトのImageExpressionプロパティにも、上記のパスを設定しておけば、ADempiereでうまく表示することができる。
2017年10月17日火曜日
2017年7月26日水曜日
ADempiereのIEブラウザ対応
ADempiereは、FireFoxやChromeには対応しており問題なく動作するが
IEとなると少し問題がある。
グリッド表示やテキストボックスの表示がおかしくなったり、画面が真っ白になってしまうことがある。
ただし、これは、コミュニティ版のADempiereの場合で、SMBアソシエイツ社では、IEでも問題なく正常動作するように修正を加えている。
ADempiereをIEで正常動作させるためには、以下の対応が必要となる。
■Compatible対応のヘッダー出力をしない
WebUIプロジェクトのindex.zulで、IE8へのCompatible対応タグが記述されているので、これを削除する。
具体的には、index.zulの7行目あたりの以下の部分を削除する。
<?meta http-equiv="X-UA-Compatible" content="IE=8" ?>
■拡大、縮小時のエラー対応
上記の対応をすれば、IEでもほぼほぼ正常動作が可能になるが
Ctrl+マウスホイールを使った拡大縮小時にエラーが発生してしまう。
これに対応するには、以下のソースの修正が必要である。
zk.jarの中にある「MouseCommand.java」に以下の修正をおこなう。
processメソッドの中で、NumberForamtExceptionが発生しないように対処をおこなっている。
// SMBA_CHG IE対応(NumberFormatExceptionの回避)
MouseEvent event = null;
if( data == null || data.length == 0 )
{
event = new MouseEvent(getId(), comp); //no area, no coord
}
else if( data.length == 1 )
{
event = new MouseEvent(getId(), comp, data[0]); //by area
}
else
{
BigDecimal bdVal1 = new BigDecimal(data[0]);
BigDecimal bdVal2 = new BigDecimal(data[1]);
event = new MouseEvent(getId(), comp, //by coord
bdVal1.intValue(), bdVal2.intValue(),
data.length < 3 ? 0: Commands.parseKeys(data[2]));
}
// final MouseEvent event =
// data == null || data.length == 0 ?
// new MouseEvent(getId(), comp): //no area, no coord
// data.length == 1 ?
// new MouseEvent(getId(), comp, data[0]): //by area
// new MouseEvent(getId(), comp, //by coord
// Integer.parseInt(data[0]), Integer.parseInt(data[1]),
// data.length < 3 ? 0: Commands.parseKeys(data[2]));
// CHG_END
ちなみに、zk.jarは、通常はjarとして参照していることが多いが、ZK関連のjarもEclipseプロジェクト化しておくと、デバッグができるので便利である。
■メッセージの非表示
最後に、ログインページで表示されるメッセージを非表示にする。
IEでログインページにアクセスすると、「一部機能が正常に動作しない可能性がある」という旨のメッセージが表示されてしまう。
これを表示しないようにしておくには、webuiプロジェクトのWLogin.javaを修正する。
81行目あたりでメッセージを表示している部分を削除しておく。
/*
if (!AEnv.isBrowserSupported())
{
// String msg = "You might experience slow performance and user interface anomalies using your current browser to access the application. We recommend the use of Firefox, Google Chrome or Apple Safari.";
String msg = "You might experience slow performance and user interface anomalies using your current browser to access the application. We recommend the use of Firefox, Google Chrome or Apple Safari."
+ "<BR>現在のブラウザはADempiereの一部機能が正常に動作しない可能性があります。ADempiereのすべての機能を使用するにはFirefoxやGoogle ChromeまたはSafariなどのブラウザをお勧めします。";
browserWarningWindow = new Window();
Div div = new Div();
div.setStyle("background-color:#FFFFCC; font-size: " + (AEnv.getFontSize() - 1) + "pt");
div.appendChild(new Text(msg));
browserWarningWindow.appendChild(div);
browserWarningWindow.setPosition("top,right");
browserWarningWindow.setWidth("550px");
browserWarningWindow.setPage(page);
browserWarningWindow.doOverlapped();
}
*/
これらの対応をしておけば、ADempiereにInternet Explorerでアクセスしても、正常に動作させることが可能である。
2017年7月25日火曜日
ADempiereのトランザクションとコネクション
ADempiereでは、基本的には、プロセスクラスがひとつのトランザクションクラスを保持し、
トランザクションクラスがひとつのコネクションを保持するという関係になっている。
プロセスクラスでひとつだけのトランザクションを使用する場合においては
プロセスクラスがトランザクションとコネクションを管理してくれるようになっている。
例外的には、スレッドなどを使うために、プロセスクラスで複数のトランザクションを使用する場合がある。この場合は、プロセスクラスに依存せず、トランザクションやコネクションの管理を適切におこなう必要がある。
プロセスクラスでひとつのトランザクションを使用する場合においては
プロセスクラスがトランザクションとコネクションを管理してくれるので
(プロセス開始時にトランザクション開始して、プロセス終了時にトランザクションを終了)
複数のトランザクションを使用しない限り、コミット漏れなどを気にする必要はないように見える。
注意が必要なのは、以下に説明するModelクラスを使用する場合とDB.javaのstaticメソッドを使用する場合である。
■Modelクラスとトランザクション
Modelクラスでのトランザクション管理は、少し複雑であるが
大きく分類すると
Modelクラスでトランザクションを作成してクローズするのか、
Modelクラスにトランザクションを外から渡し、トランザクション管理は呼び出し側でおこなうという2通りがある。
<Modelクラスにトランザクションを外から渡す場合>
まず、Modelクラスにトランザクションを外から渡す場合である。
ADempiereでは、通常このパターンでModelクラスを運用することが多いと思われる。
これは、Modelクラスをインスタンス化するときに、以下のようにトランザクション名を渡すことで、
Modelクラスに外からトランザクションを渡せるようになる。
MPPOrder ppOrder = new MPPOrder(getCtx(), 0, get_TrxName());
通常は、Processクラスのget_TrxName()メソッドを使用して、プロセスクラスが保持しているトランザクションをそのまま渡すことで、ProcessクラスとModelクラスとのトランザクションを統一している。
この場合、Modelクラスのsave()メソッドを呼び出しても、コミットやトランザクションのクローズはされず、これらは呼出元に任されることになる。
つまり、呼出元で必ずコミットやクローズをするようにしないとトランザクションが残ってしまう。
☆呼出元でトランザクション管理をすることが必須となるので注意が必要。(プロセスクラスからの呼び出しであればプロセスクラスがやってくれる。)
また、この場合、エラーがおこったとき、ロールバックはされないが、SavePointを使用して、このModelクラスでおこなった更新処理だけを元に戻すようになっている。
<Modelクラスにトランザクションを外から渡さない場合>
Modelクラスにトランザクションを渡さない場合は、Modelクラス内部で新しいトランザクションが作成される。また、トランザクションは、Modelクラス内でコミットまたはロールバックがおこなわれ、クローズまでされる。Modelクラスないだけで利用されるいわゆるローカルトランザクションとなる。
■DB.javaのStaticメソッドとトランザクション
DB.javaでは、SQLを単発的に実行できるStaticメソッドがたくさん定義されている。
これらのメソッドでも、トランザクション名を外から渡せるようになっており
Modelクラスと同様に、トランザクションを外から渡すか、内部で作成するかを選ぶことができる。
ただ、コミュニティ版のDB.javaでは、コネクションのクローズ漏れがあり
これらのメソッドに、トランザクション名をNullで渡すと、コネクションが残ってしまう。
SMBアソシエイツ社では、これらのDB.javaのStaticメソッドのコネクション漏れを修正している。
また、さらに、SMBアソシエイツ社では、複数トランザクションの実装やコネクションプールを使わない選択ができるようにプロセスクラスを改造している。
トランザクションクラスがひとつのコネクションを保持するという関係になっている。
プロセスクラスでひとつだけのトランザクションを使用する場合においては
プロセスクラスがトランザクションとコネクションを管理してくれるようになっている。
例外的には、スレッドなどを使うために、プロセスクラスで複数のトランザクションを使用する場合がある。この場合は、プロセスクラスに依存せず、トランザクションやコネクションの管理を適切におこなう必要がある。
プロセスクラスでひとつのトランザクションを使用する場合においては
プロセスクラスがトランザクションとコネクションを管理してくれるので
(プロセス開始時にトランザクション開始して、プロセス終了時にトランザクションを終了)
複数のトランザクションを使用しない限り、コミット漏れなどを気にする必要はないように見える。
注意が必要なのは、以下に説明するModelクラスを使用する場合とDB.javaのstaticメソッドを使用する場合である。
■Modelクラスとトランザクション
Modelクラスでのトランザクション管理は、少し複雑であるが
大きく分類すると
Modelクラスでトランザクションを作成してクローズするのか、
Modelクラスにトランザクションを外から渡し、トランザクション管理は呼び出し側でおこなうという2通りがある。
<Modelクラスにトランザクションを外から渡す場合>
まず、Modelクラスにトランザクションを外から渡す場合である。
ADempiereでは、通常このパターンでModelクラスを運用することが多いと思われる。
これは、Modelクラスをインスタンス化するときに、以下のようにトランザクション名を渡すことで、
Modelクラスに外からトランザクションを渡せるようになる。
MPPOrder ppOrder = new MPPOrder(getCtx(), 0, get_TrxName());
通常は、Processクラスのget_TrxName()メソッドを使用して、プロセスクラスが保持しているトランザクションをそのまま渡すことで、ProcessクラスとModelクラスとのトランザクションを統一している。
この場合、Modelクラスのsave()メソッドを呼び出しても、コミットやトランザクションのクローズはされず、これらは呼出元に任されることになる。
つまり、呼出元で必ずコミットやクローズをするようにしないとトランザクションが残ってしまう。
☆呼出元でトランザクション管理をすることが必須となるので注意が必要。(プロセスクラスからの呼び出しであればプロセスクラスがやってくれる。)
また、この場合、エラーがおこったとき、ロールバックはされないが、SavePointを使用して、このModelクラスでおこなった更新処理だけを元に戻すようになっている。
<Modelクラスにトランザクションを外から渡さない場合>
Modelクラスにトランザクションを渡さない場合は、Modelクラス内部で新しいトランザクションが作成される。また、トランザクションは、Modelクラス内でコミットまたはロールバックがおこなわれ、クローズまでされる。Modelクラスないだけで利用されるいわゆるローカルトランザクションとなる。
■DB.javaのStaticメソッドとトランザクション
DB.javaでは、SQLを単発的に実行できるStaticメソッドがたくさん定義されている。
これらのメソッドでも、トランザクション名を外から渡せるようになっており
Modelクラスと同様に、トランザクションを外から渡すか、内部で作成するかを選ぶことができる。
ただ、コミュニティ版のDB.javaでは、コネクションのクローズ漏れがあり
これらのメソッドに、トランザクション名をNullで渡すと、コネクションが残ってしまう。
SMBアソシエイツ社では、これらのDB.javaのStaticメソッドのコネクション漏れを修正している。
また、さらに、SMBアソシエイツ社では、複数トランザクションの実装やコネクションプールを使わない選択ができるようにプロセスクラスを改造している。
ADempiereのヒープメモリの設定
ADempiereのヒープメモリの設定について、どのくらいが適切なのか
もちろん、潤沢なメモリ環境であれば、できるだけ多く設定しておいたほうが間違いないが
弊社で把握しているヒープメモリの設定状況について記述したい。
まず、ヒープ全体について、特にMRPなどの負荷の高い処理を行う場合は、最低4GB、できれば6GB以上あったほうがベターである。
Javaの起動オプションは以下で指定する。
-Xms6144M -Xmx6144M
次にヒープメモリの内訳について、
■Permanent領域
まず指定しやすいのは、Permanentメモリサイズである。
これは、クラス定義のような一度メモリ登録すれば書き換わることのないであろうデータを登録する領域である。
ADempiereの場合、クラスが多いので通常のアプリケーションよりもこのサイズは、大きいほうがベターであるが、それでも256MBもあれば十分である。これでも、使用率が30%を超えることはないと考えられる。
Javaの起動オプションは以下で指定する。
-XX:PermSize=256M -XX:MaxPermSize=256M
■New領域
New領域とは、クラスをNewしたときに格納される領域である。クラスがNewされると、まずはEden領域というところに格納され、YoungGCまたはFullGCによって、Eden領域からSurvivor領域に移動されるか解放される。
このNew領域が小さければ、YoungGCが頻繁に走ってしまい、処理落ちを起こす原因となってしまう。
また、ADempiereの場合、Newされるオブジェクトが多いが、すぐに解放されることが多いので
New領域を多めにとって、Old領域を少なめにしても、よほど下手なプログラムを記述しない限り、FullGCが頻発することは考えにくい。
よって、7割から8割をNew領域に割り当てて問題ないといえる。
この設定でも、ある案件で実運用と同様のオーダー数のMRPを回した後でも、Old領域は1割程度の使用率である。
Javaの起動オプションは以下で指定する。
-XX:NewSize=4096M -XX:MaxNewSize=4096M
<Survivor領域>
Survivor領域とは、Eden領域のうち、GCによって解放されなかったオブジェクトが格納される領域である。
このSurvivor領域とEden領域の割合を起動オプションで設定できるが、これを変えても大きな変化は見られなかった。
理由の推測としては、この割合を変えても、New領域全体が変わるわけではないので、YGCの頻度も変わらないから当然と思われる。
よって、これは、デフォルトでいいと考えられる。
もし、設定する場合、Javaの起動オプションは以下で指定する。
-XX:SurvivorRatio=2
■Old領域
Old領域は、Survivor領域で、何度も解放されなかったオブジェクトおよび、Survivor領域がいっぱいになったときのオブジェクトが移動される領域である。
この領域がいっぱいになると、FullGCが発生し、何度もいっぱいになると、FullGCが頻発することになるのが、上記でも説明したとおり、ADempiereでは、Old領域に大きなサイズが必要ということにはなりにくいため、ヒープ全体の2割から3割でいいと考えられる。
Javaの起動オプションは特に指定しない。(NewRatioで設定もできるが、全体から、パーマネントとNew領域をひいたサイズとなるため。)
■ヒープ設定例(全体を6GBとしたとき)
-Xms6144M -Xmx6144M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:NewSize=4096M -XX:MaxNewSize=4096M
※もう少し、New領域を増やしてもよいが、ちまたのベストプラクティス(New:Old=1:2)と乖離しすぎるので・・・。
※32ビットOSでは、2GBまでなので注意。
※起動オプションのgcInterval指定について不要という人もいるが、個人的にはあったほうがいいと思っている。1時間に1回ぐらいは、FullGCされてもいいかなと思うし、逆にこれをせずにメモリオーバーフローになるほうが怖いと思う。(gcInterval=3600000)
もちろん、潤沢なメモリ環境であれば、できるだけ多く設定しておいたほうが間違いないが
弊社で把握しているヒープメモリの設定状況について記述したい。
まず、ヒープ全体について、特にMRPなどの負荷の高い処理を行う場合は、最低4GB、できれば6GB以上あったほうがベターである。
Javaの起動オプションは以下で指定する。
-Xms6144M -Xmx6144M
次にヒープメモリの内訳について、
■Permanent領域
まず指定しやすいのは、Permanentメモリサイズである。
これは、クラス定義のような一度メモリ登録すれば書き換わることのないであろうデータを登録する領域である。
ADempiereの場合、クラスが多いので通常のアプリケーションよりもこのサイズは、大きいほうがベターであるが、それでも256MBもあれば十分である。これでも、使用率が30%を超えることはないと考えられる。
Javaの起動オプションは以下で指定する。
-XX:PermSize=256M -XX:MaxPermSize=256M
■New領域
New領域とは、クラスをNewしたときに格納される領域である。クラスがNewされると、まずはEden領域というところに格納され、YoungGCまたはFullGCによって、Eden領域からSurvivor領域に移動されるか解放される。
このNew領域が小さければ、YoungGCが頻繁に走ってしまい、処理落ちを起こす原因となってしまう。
また、ADempiereの場合、Newされるオブジェクトが多いが、すぐに解放されることが多いので
New領域を多めにとって、Old領域を少なめにしても、よほど下手なプログラムを記述しない限り、FullGCが頻発することは考えにくい。
よって、7割から8割をNew領域に割り当てて問題ないといえる。
この設定でも、ある案件で実運用と同様のオーダー数のMRPを回した後でも、Old領域は1割程度の使用率である。
Javaの起動オプションは以下で指定する。
-XX:NewSize=4096M -XX:MaxNewSize=4096M
<Survivor領域>
Survivor領域とは、Eden領域のうち、GCによって解放されなかったオブジェクトが格納される領域である。
このSurvivor領域とEden領域の割合を起動オプションで設定できるが、これを変えても大きな変化は見られなかった。
理由の推測としては、この割合を変えても、New領域全体が変わるわけではないので、YGCの頻度も変わらないから当然と思われる。
よって、これは、デフォルトでいいと考えられる。
もし、設定する場合、Javaの起動オプションは以下で指定する。
-XX:SurvivorRatio=2
■Old領域
Old領域は、Survivor領域で、何度も解放されなかったオブジェクトおよび、Survivor領域がいっぱいになったときのオブジェクトが移動される領域である。
この領域がいっぱいになると、FullGCが発生し、何度もいっぱいになると、FullGCが頻発することになるのが、上記でも説明したとおり、ADempiereでは、Old領域に大きなサイズが必要ということにはなりにくいため、ヒープ全体の2割から3割でいいと考えられる。
Javaの起動オプションは特に指定しない。(NewRatioで設定もできるが、全体から、パーマネントとNew領域をひいたサイズとなるため。)
■ヒープ設定例(全体を6GBとしたとき)
-Xms6144M -Xmx6144M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:NewSize=4096M -XX:MaxNewSize=4096M
※もう少し、New領域を増やしてもよいが、ちまたのベストプラクティス(New:Old=1:2)と乖離しすぎるので・・・。
※32ビットOSでは、2GBまでなので注意。
※起動オプションのgcInterval指定について不要という人もいるが、個人的にはあったほうがいいと思っている。1時間に1回ぐらいは、FullGCされてもいいかなと思うし、逆にこれをせずにメモリオーバーフローになるほうが怖いと思う。(gcInterval=3600000)
Postgresで現在の接続数を確認する
■現在、接続されているConnectionを確認するには
「pg_stat_activity」というテーブルを確認するとよい。
SELECT * FROM pg_stat_activity
ここに登録されているレコード1件ずつが現在接続されているConnectionである。
レコードが100件あったら、現在接続されているConnection数は、100ということになる。
■実行中のトランザクションを確認するには
上記「pg_stat_activity」テーブルの「xact_start」列が入っている場合は、そのコネクションでトランザクションが実行されている状態。
もし、実行プログラムが終了しているのに、この列に値が入っているような場合は、コミット漏れのトランザクションがある可能性があるので注意が必要。
特に、コミット漏れが原因で、他のトランザクションのレスポンスが著しく遅くなる場合があるのでコミット漏れがないかは、確実にチェックしておいたほうがいいと思われる。
ちなみに、上記のQuery列に「SHOW TRANSACTION ISOLATION LEVEL」で表示されるのは、コネクションプールを使って接続した場合のコネクションであることが多い。
■強制的に、コネクションを切断するには
以下のコマンドを実行すればよい。
SELECT pg_terminate_backend(PID)
※PIDは、上記「pg_stat_activity」テーブルの「pid」列値を使うとよい。
※ただし、コネクションプールなどで保持されているコネクションを強制的に切断した場合は
再度、コネクションプールのコネクションでプログラムが実行された場合、当然のことながらエラーになるので注意が必要。 (このコマンドの使用は開発中の作業に限定されると思われる)
「pg_stat_activity」というテーブルを確認するとよい。
SELECT * FROM pg_stat_activity
ここに登録されているレコード1件ずつが現在接続されているConnectionである。
レコードが100件あったら、現在接続されているConnection数は、100ということになる。
■実行中のトランザクションを確認するには
上記「pg_stat_activity」テーブルの「xact_start」列が入っている場合は、そのコネクションでトランザクションが実行されている状態。
もし、実行プログラムが終了しているのに、この列に値が入っているような場合は、コミット漏れのトランザクションがある可能性があるので注意が必要。
特に、コミット漏れが原因で、他のトランザクションのレスポンスが著しく遅くなる場合があるのでコミット漏れがないかは、確実にチェックしておいたほうがいいと思われる。
ちなみに、上記のQuery列に「SHOW TRANSACTION ISOLATION LEVEL」で表示されるのは、コネクションプールを使って接続した場合のコネクションであることが多い。
■強制的に、コネクションを切断するには
以下のコマンドを実行すればよい。
SELECT pg_terminate_backend(PID)
※PIDは、上記「pg_stat_activity」テーブルの「pid」列値を使うとよい。
※ただし、コネクションプールなどで保持されているコネクションを強制的に切断した場合は
再度、コネクションプールのコネクションでプログラムが実行された場合、当然のことながらエラーになるので注意が必要。 (このコマンドの使用は開発中の作業に限定されると思われる)
2017年7月21日金曜日
ヒープの状態とGCの実行回数を表示する(備忘録)
ヒープメモリの状態とGCの実行回数を表示するコマンド
jstat -gcutil -h3 <ProcessID> <表示頻度(ms)>
ex.
jstat -gcutil -h3 4716 5000
S0 S1 E O P YGC YGCT FGC FGCT GCT
92.74 0.00 76.22 9.29 7.27 188 23.448 0 0.000 23.448
92.74 0.00 98.90 9.29 7.27 188 23.448 0 0.000 23.448
0.00 92.31 23.16 9.29 7.27 189 23.630 0 0.000 23.630
<各列の説明>
S0:S0領域の使用率(Young領域)
S1:S1領域の使用率(Young領域)
E :Eden領域の使用率(Young領域)
O :Old領域の使用率(Old領域)
P :Permanent領域の使用率(永続領域)
YGC:YoungGCの発生回数
YGCT:YoungGCの処理時間(秒)
FGC:FullGCの発生回数
FGCT:FullGCの処理時間(秒)
GCT:YoungGCとFullGCの処理時間(秒)
<ヒープの世代>
■Young領域
S0,S1,EdenがYoung領域(Newされてからまだ若いヒープ)
Eden: Newがおこなわれるとまずここにたまる。
S0: Edenから少し年をとったヒープ
S1: Edenから少し年をとったヒープ
■Old領域
Young領域にある間に、解放されることがなかったヒープ。
Young領域から、Old領域に移動するタイミングは、YoungGCの回数やS0,S1領域が満杯になったときなどGCアルゴリズムによる。
■Permanent領域
基本的には永続的に保持するメモリ。主にクラス定義など
<ヒープの容量を表示する>
上記のオプションの「-gcutil」を「-gc」に変えるだけでよい。
jstat -gc -h3 <ProcessID> <表示頻度(ms)>
ex.
jstat -gc -h3 4716 5000
S0C Survivor 領域 0 の現在の容量 (KB)
S1C Survivor 領域 1 の現在の容量 (KB)
S0U Survivor 領域 0 の使用量 (KB)
S1U Survivor 領域 1 の使用量 (KB)
EC Eden 領域の現在の容量 (KB)
EU Eden 領域の使用量 (KB)
OC Old 領域の現在の容量 (KB)
OU Old 領域の使用量 (KB)
PC Permanent 領域の現在の容量 (KB)
PU Permanent 領域の使用量 (KB)
YGC 若い世代の GC イベント数
YGCT 若い世代のガベージコレクション時間
FGC フル GC イベント数
FGCT フルガベージコレクション時間
GCT ガベージコレクション総時間
※S0CやS0U、ECやEUの「C」はCapacity、「U」はUsageと思われる。
http://docs.oracle.com/javase/jp/7/technotes/tools/share/jstat.html
jstat -gcutil -h3 <ProcessID> <表示頻度(ms)>
ex.
jstat -gcutil -h3 4716 5000
S0 S1 E O P YGC YGCT FGC FGCT GCT
92.74 0.00 76.22 9.29 7.27 188 23.448 0 0.000 23.448
92.74 0.00 98.90 9.29 7.27 188 23.448 0 0.000 23.448
0.00 92.31 23.16 9.29 7.27 189 23.630 0 0.000 23.630
<各列の説明>
S0:S0領域の使用率(Young領域)
S1:S1領域の使用率(Young領域)
E :Eden領域の使用率(Young領域)
O :Old領域の使用率(Old領域)
P :Permanent領域の使用率(永続領域)
YGC:YoungGCの発生回数
YGCT:YoungGCの処理時間(秒)
FGC:FullGCの発生回数
FGCT:FullGCの処理時間(秒)
GCT:YoungGCとFullGCの処理時間(秒)
<ヒープの世代>
■Young領域
S0,S1,EdenがYoung領域(Newされてからまだ若いヒープ)
Eden: Newがおこなわれるとまずここにたまる。
S0: Edenから少し年をとったヒープ
S1: Edenから少し年をとったヒープ
■Old領域
Young領域にある間に、解放されることがなかったヒープ。
Young領域から、Old領域に移動するタイミングは、YoungGCの回数やS0,S1領域が満杯になったときなどGCアルゴリズムによる。
■Permanent領域
基本的には永続的に保持するメモリ。主にクラス定義など
<ヒープの容量を表示する>
上記のオプションの「-gcutil」を「-gc」に変えるだけでよい。
jstat -gc -h3 <ProcessID> <表示頻度(ms)>
ex.
jstat -gc -h3 4716 5000
S0C Survivor 領域 0 の現在の容量 (KB)
S1C Survivor 領域 1 の現在の容量 (KB)
S0U Survivor 領域 0 の使用量 (KB)
S1U Survivor 領域 1 の使用量 (KB)
EC Eden 領域の現在の容量 (KB)
EU Eden 領域の使用量 (KB)
OC Old 領域の現在の容量 (KB)
OU Old 領域の使用量 (KB)
PC Permanent 領域の現在の容量 (KB)
PU Permanent 領域の使用量 (KB)
YGC 若い世代の GC イベント数
YGCT 若い世代のガベージコレクション時間
FGC フル GC イベント数
FGCT フルガベージコレクション時間
GCT ガベージコレクション総時間
※S0CやS0U、ECやEUの「C」はCapacity、「U」はUsageと思われる。
http://docs.oracle.com/javase/jp/7/technotes/tools/share/jstat.html
2017年7月20日木曜日
ADempiereのMRPの処理速度改善メモ
MRPの処理速度改善のために、いろいろ実装したが、スレッド化がかなり効果的だった。
1スレッドごとに16%程度の処理改善がみられたようだ。
ただし、コア数以上のスレッドでは改善率が極端に下がる。
試験環境は、6コアで、1.16の6乗=2.4363
実際には、6スレッド以上を起動しているので、2.4倍以上の速さになることを確認。
そこそこの部品構成と需要件数でも、30分で処理が終わるMRPになった。
技術的には、スレッドごとにレコードロックが競合しないように設計すること、こまめにコミットしてレコードロックを長時間保持しないこと、Wait、Notifyを巧みに使用すること、トランザクションのコミット漏れや長時間トランザクション、コネクション数のケア、Postgresのデッドタプル、オートバキューム実行ログのチェックなどがポイントだったように思う。
1スレッドごとに16%程度の処理改善がみられたようだ。
ただし、コア数以上のスレッドでは改善率が極端に下がる。
試験環境は、6コアで、1.16の6乗=2.4363
実際には、6スレッド以上を起動しているので、2.4倍以上の速さになることを確認。
そこそこの部品構成と需要件数でも、30分で処理が終わるMRPになった。
技術的には、スレッドごとにレコードロックが競合しないように設計すること、こまめにコミットしてレコードロックを長時間保持しないこと、Wait、Notifyを巧みに使用すること、トランザクションのコミット漏れや長時間トランザクション、コネクション数のケア、Postgresのデッドタプル、オートバキューム実行ログのチェックなどがポイントだったように思う。
2017年1月11日水曜日
Postgresチューニングパラメータ(主なもの)
Postgresのチューニングパラメータの備忘録。(9.3ベースの設定ファイル)
postgres.confで設定される。
多くのPostgresのチューニングパラメータは、一昔前のPCを意識したような設定値であり、
最近のPCスペックにあった設定をしておいたほうがいい。
■メモリ関連
☆shared_buffers = 2048MB # min 128kB
# (change requires restart)
表領域をキャッシュする領域。
たとえば、SELECTを実行するときに、この領域にデータがあれば
ディスクアクセスせずここのデータを読み書きする。
ディスクアクセス回数を減らすことができれば、処理が速くなる。
OSキャッシュとの兼ね合いもあるので、あまり大きくすることは推奨されない。
実メモリの25%がいいといわれている。
また、指定方法は古いバージョンではバッファ指定だったが、
最近のバージョンでは、バッファ指定できないようだ。
GB、MB、kBの単位で設定するようにする。
☆work_mem = 1MB # min 64kB
Postgresが処理に使うワーキングメモリ。
(実メモリ-shared_buffers)/max_connectionsを超えるとスワップするので注意。
☆maintenance_work_mem = 16MB # min 1MB
バキュームなどのメンテナンス処理に使われるワーキングメモリ。
少なすぎると、バキュームされないことがあるという人もいるが詳細不明。
■コネクション関連
☆max_connections = 300
work_memとの関係に注意。
work_memは接続ごとに発生するので、work_mem*max_connectionsのメモリを確保しておかないと、スワップ発生の危険性がある。
(実メモリ-shared_buffers)/max_connectionsを超えるとだめ。
☆tcp_keepalives_idle = 60 # TCP_KEEPIDLE, in seconds;
# 0 selects the system default
コネクションを完全に接続するまでの待ち時間。
デフォルトが大きいので、確実な値を設定しておくのがベター。
tcp_keepalives_interval = 5 # TCP_KEEPINTVL, in seconds;
# 0 selects the system default
■BackGround Writer
BackGround Writerは、CheckPointが発生するまでに、
ディスク書き込みを少しでもしておくことで負荷の分散を計るもの。
負荷の分散が目的であり、処理量を減らすものではない。
アプリケーションで画面を表示するなどの場合、極端に遅いタイミングがあっては困るが
チェックポイントの書き込み量が多いときには、処理が極端に遅くなる可能性がある。
そういった場合に、BackGroundWriterによって、チェックポイントの書き込みが減るように
少しずつ書き込みをおこない、チェックポイント処理を軽減して、極端な処理落ちを防ぐことができる。(処理を分散するだけで、処理量を減らすものではない。)
逆に、大量データ処理の場合などは、負荷の分散よりも最終処理時間が大事なので、
チェックポイントに任せておいても問題ないと思われる。
(1回にたくさん書き込みしたほうがディスクアクセスを減らせるため)
その場合、チェックポイントとバキュームの発生タイミングなどのチューニングがむしろ重要だと考えられる。
☆bgwriter_delay = 5000ms # 10-10000ms between rounds
BackGroundWriterの実行間隔。
☆bgwriter_lru_maxpages = 1000 # 0-1000 max buffers written/round
BackGroundWriterが書込むサイズの最大値。
1バッファは8KB。
0にすると、BackGroundWriterを発生させない。
☆bgwriter_lru_multiplier = 10.0 # 0-10.0 multipler on buffers scanned/round
最近の周期で書き込んだ平均とこの値が掛け合わされて、BackGroundWriterが書込むサイズの最大値とする。なお、ここで算出した最大値とbgwriter_lru_maxpagesの小さいほうが採用される。
■WAL
☆wal_buffers = 64MB # min 32kB, -1 sets based on shared_buffers
# (change requires restart)
WAL=いわゆるトランザクションログをバッファリングしておく領域。
基本的には、コミットのときに、WALログファイルに書き込まれる。
その他、WALバッファがあふれたとき、Checkpoint、Vacuum実行時、WALライター実行時などにWALログファイルに書き込まれる。
多くの更新を実行するトランザクションがある場合は、WAL_Buffersは大きい目に設定しておいたほうが
ディスク書き込みを減らすことができる。
デフォルトの-1で、SharedBufferの1/32を割り当てる。
ただし、64KBから16MBの範囲内であり、それより大きい値を設定する場合は変えたほうがいい。
8.1まではバッファ指定だが、それ以降は、サイズ指定する。
☆wal_writer_delay = 200ms # 1-10000 milliseconds
WAL Writerの実行周期。
postgres.confで設定される。
多くのPostgresのチューニングパラメータは、一昔前のPCを意識したような設定値であり、
最近のPCスペックにあった設定をしておいたほうがいい。
■メモリ関連
☆shared_buffers = 2048MB # min 128kB
# (change requires restart)
表領域をキャッシュする領域。
たとえば、SELECTを実行するときに、この領域にデータがあれば
ディスクアクセスせずここのデータを読み書きする。
ディスクアクセス回数を減らすことができれば、処理が速くなる。
OSキャッシュとの兼ね合いもあるので、あまり大きくすることは推奨されない。
実メモリの25%がいいといわれている。
また、指定方法は古いバージョンではバッファ指定だったが、
最近のバージョンでは、バッファ指定できないようだ。
GB、MB、kBの単位で設定するようにする。
☆work_mem = 1MB # min 64kB
Postgresが処理に使うワーキングメモリ。
(実メモリ-shared_buffers)/max_connectionsを超えるとスワップするので注意。
☆maintenance_work_mem = 16MB # min 1MB
バキュームなどのメンテナンス処理に使われるワーキングメモリ。
少なすぎると、バキュームされないことがあるという人もいるが詳細不明。
■コネクション関連
☆max_connections = 300
work_memとの関係に注意。
work_memは接続ごとに発生するので、work_mem*max_connectionsのメモリを確保しておかないと、スワップ発生の危険性がある。
(実メモリ-shared_buffers)/max_connectionsを超えるとだめ。
☆tcp_keepalives_idle = 60 # TCP_KEEPIDLE, in seconds;
# 0 selects the system default
コネクションを完全に接続するまでの待ち時間。
デフォルトが大きいので、確実な値を設定しておくのがベター。
tcp_keepalives_interval = 5 # TCP_KEEPINTVL, in seconds;
# 0 selects the system default
■BackGround Writer
BackGround Writerは、CheckPointが発生するまでに、
ディスク書き込みを少しでもしておくことで負荷の分散を計るもの。
負荷の分散が目的であり、処理量を減らすものではない。
アプリケーションで画面を表示するなどの場合、極端に遅いタイミングがあっては困るが
チェックポイントの書き込み量が多いときには、処理が極端に遅くなる可能性がある。
そういった場合に、BackGroundWriterによって、チェックポイントの書き込みが減るように
少しずつ書き込みをおこない、チェックポイント処理を軽減して、極端な処理落ちを防ぐことができる。(処理を分散するだけで、処理量を減らすものではない。)
逆に、大量データ処理の場合などは、負荷の分散よりも最終処理時間が大事なので、
チェックポイントに任せておいても問題ないと思われる。
(1回にたくさん書き込みしたほうがディスクアクセスを減らせるため)
その場合、チェックポイントとバキュームの発生タイミングなどのチューニングがむしろ重要だと考えられる。
☆bgwriter_delay = 5000ms # 10-10000ms between rounds
BackGroundWriterの実行間隔。
☆bgwriter_lru_maxpages = 1000 # 0-1000 max buffers written/round
BackGroundWriterが書込むサイズの最大値。
1バッファは8KB。
0にすると、BackGroundWriterを発生させない。
☆bgwriter_lru_multiplier = 10.0 # 0-10.0 multipler on buffers scanned/round
最近の周期で書き込んだ平均とこの値が掛け合わされて、BackGroundWriterが書込むサイズの最大値とする。なお、ここで算出した最大値とbgwriter_lru_maxpagesの小さいほうが採用される。
■WAL
☆wal_buffers = 64MB # min 32kB, -1 sets based on shared_buffers
# (change requires restart)
WAL=いわゆるトランザクションログをバッファリングしておく領域。
基本的には、コミットのときに、WALログファイルに書き込まれる。
その他、WALバッファがあふれたとき、Checkpoint、Vacuum実行時、WALライター実行時などにWALログファイルに書き込まれる。
多くの更新を実行するトランザクションがある場合は、WAL_Buffersは大きい目に設定しておいたほうが
ディスク書き込みを減らすことができる。
デフォルトの-1で、SharedBufferの1/32を割り当てる。
ただし、64KBから16MBの範囲内であり、それより大きい値を設定する場合は変えたほうがいい。
8.1まではバッファ指定だが、それ以降は、サイズ指定する。
☆wal_writer_delay = 200ms # 1-10000 milliseconds
WAL Writerの実行周期。
登録:
投稿 (Atom)