SELECT
  relname,
  relkind,
  to_char(reltuples, '999,999,999') as rows,
  to_char(pg_relation_size(relname), '999,999,999,999') as bytes
FROM pg_class
WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname='public')
order by bytes desc;

参考

PostgreSQLでテーブルサイズを確認する by y-kawaz

概要

StringBuider で append() を使い1文字を追加するとき、
sb.append('\t');
のように char 型を追加するときと
sb.append("\t");
のように文字列型で追加するときに性能差を調査した。

結果

追加データ実行時間 [s]
'\t' 2.165
"\t" 7.788

1つの文字を追加する場合は、 char 型で追加したほうが文字列で追加するより 3.6 倍高速だった。

概要

PostgreSQL 上に作成したテーブルに対し、Java で時刻を timestamp 型ではなくミリ秒(long 値)のまま格納した場合、それを select で timestamp 型として取り出すには以下のように SQL を記述する。
SELECT
    (lastaccess / 1000) :: text :: interval + '1970-01-01' :: timestamp
FROM
    table1;
lastaccess は bigint 型のカラム。これを1000分の1して秒単位にし、 epoch 秒(グリニッジ標準時間1970年1月1日00:00:00からの経過秒数) に足している。

例: DB に格納された tomcat のセッションでサイズの大きいものを見つける

次のような SQL を実行する。
SELECT
	length(data) as len,
	session_id,
	(lastaccess / 1000) :: text :: interval + '1970-01-01' :: timestamp
FROM
	tomcat_sessions
ORDER BY len desc
LIMIT 20;

概要

Windows7で Eclipse 3.3 を動作したときに「パッケージ・エクスプローラ」ビューが自動的に横スクロールするのを停止する方法について説明。
32bit, 64 bit 環境の違いなく簡単に解決できるので便利。
多分 Vista でも同じ方法で解決する。

背景

Windows7(と Vista)でEclipseを利用時、イライラする現象がある。

画面左側の「パッケージ・エクスプローラ」ツリービューにおいて、深いパッケージ階層にアクセスしている時に、勝手に横スクロールする



十分な横幅の画面で作業していれば、このビューを横に広げてこの問題を回避できるが...。

この新たな機能は Windows Vista からツリービューに搭載されたものらしい。。。
せめて挙動を選択できるようにして欲しかった。

32bit ユーザなら Explorer Construction で!

Explorer Constructionというツールを使うことで、この横スクロールを無効化できるらしい。

ソフト起動後、「水平方向の自動スクロールを無効にする(A) 」にチェックを入れるだけ。
残念ながら 64bit 環境では動作しない。本当に残念...。

Windows 互換モードで実行することで 64bit でも解決!

しばらく探しまわって、やっと解決法を見つけた。 ⇒disable dynamic horizontal scrolling in Vista

内容は簡単。「Eclipse を Windows XP 互換モードで動かすだけ」でした。

Eclipse のショートカットを作成し、プロパティを表示。 「互換性」タブで「互換モードでこのプログラムを実行する」にチェックを入れ、 「Windows XP (Service Pack 3)」を選択するだけでよい。



この方法は Eclipse だけでなく他のアプリケーションでも適用できる。

概要

PostgreSQLの各プロセスがどのテーブルでどの種類のロックを行っているか調べる方法について説明。

さらに、そのプロセスを下記手順で終了することで、ロックしていた処理を強制的に中断できる。

手順

プロセスIDの確認

コマンドラインなどで、次のSQLを実行する。
SELECT l.pid, db.datname, c.relname, l.locktype, l.mode
FROM pg_locks l
        LEFT JOIN pg_class c ON l.relation=c.relfilenode
        LEFT JOIN pg_database db ON l.database = db.oid
ORDER BY l.pid;
pid がプロセスIDを意味する。

プロセスの停止

プロセスIDが分かったら、次のSQLでプロセスを停止できる。
SELECT pg_cancel_backend(プロセスID);

概要

前回 は、Windows 上で起動した Java プロセスを snmp で監視する方法を説明した。

今回は Linux 上で起動した Tomcat プロセスのメモリを監視する方法について説明する。

動作環境

項目
OS CentOS 5
Java JDK 6 update 10
Tomcat 6.0.20

tomcat 起動時の設定

Tomcat を起動する時の CATALINA_OPTS 変数に次の記述を追加する。
例えば、/etc/tomcat6/tomcat6.conf で次のように記述する。
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.snmp.port=1161 -Dcom.sun.management.snmp.acl.file=/etc/tomcat6/snmp.acl"

/etc/tomcat6/snmp.acl 作成

ファイルを作成する。
acl = {
 {
   communities = public
   access = read-only
   managers = localhost
 }
}
さらに、snmp.acl のパーミッションを 600 に変更する。
# chown roo:root snmp.acl
# chmod 600 snmp.acl
ここまで設定が終わったら、Tomcat を起動する。
# service tomcat6 start

MIB ファイルを置く

/usr/share/snmp/mibs/JVM-MANAGEMENT-MIB.mib を作成する。
# cd /usr/share/snmp/mibs/
# lftpget http://java.sun.com/j2se/1.5.0/docs/guide/management/JVM-MANAGEMENT-MIB.mib

/etc/snmp/snmp.conf 設定

次に snmpd の設定。このファイルの最後へ記述を追加する。
proxy -m /usr/share/snmp/mibs/JVM-MANAGEMENT-MIB.txt -v 2c -c public localhost:1161 .1.3.6.1.4.1.42.2.145
記述を追加したら、snmpd を再起動する。
# service snmpd restart

動作確認

$ snmpwalk -v 2c -c public localhost .1.3.6.1.4.1.42.2.145

出力結果をカスタマイズ

数字で構成される OID 値を文字列に変更できる。
上記の手順で mib ファイルを snmpwalk を実行するホストに置いた後、次のように環境変数を設定する。
.bashrc などに書いておくとよい。
$ export MIBS=ALL
$ snmpwalk -v 2c -c public localhost .1.3.6.1.4.1.42.2.145

参考

概要

Javaでwebサイトを運用し、ある程度規模が大きくなってくるとメモリ管理で悩まされる。
安定、高速なwebサイトを目指すためにはメモリ関連のモニタリングとチューニングが必要になってくる。

ガベージ・コレクション関連のログ出力設定を行う方法は簡単だが、nagios などで監視を行い、閾値に達したらアラート・メールで通知してくれると便利である。

今回は Java の snmp 監視を有効にする設定手順について説明する。

開発環境

項目
OS Windows XP Pro SP3
IDE 環境 Eclipse 3.4.1(Preiades All in One)
Java JDK 6 update 10

Windows 環境での設定手順

概要

Windows 上で起動中の Eclipse から Java プログラムを起動し、そのプロセスを snmp で監視できるよう、設定を行う。

プログラム例

次のようなプログラムを作成した。
public class Test {
	public static void main(String[] args) throws InterruptedException {
		int count = 0;
		
		for (;;) {
			Thread.sleep(1000);
		
			count++;
			System.out.println(count);
		}
	}
}
とりあえず1回実行してみる。
[実行] メニュー ⇒ 実行 ⇒ Java アプリケーション

起動オプション設定

1回実行した後、今度は実行構成を開く。
[実行] メニュー ⇒ 実行構成


[引数] タブを選択し、「VM引数」のところに次の文字列を入力する。
-Dcom.sun.management.snmp.port=161 -Dcom.sun.management.snmp.acl.file=c:/snmp.acl -Dcom.sun.management.config.file=c:/management.properties

設定ファイルのコピー

次に、C:\Program Files\Java\jre6\lib\management の下にある、次の2つのファイルを C:\ にコピーする。
  • management.properties
  • snmp.acl.template
snmp.acl.template は snmp.acl に名前を変える。

設定ファイルの修正

c:\snmp.acl
ホスト 172.16.1.2 からコミュニティ名「public」で snmp 読み込みを受け付ける場合は、次のように記述する。
   acl = {
     {
       communities = public
       access = read-only
       managers = 172.16.1.2
     }
    }
 
c:\management.properties
Java 起動時、デフォルト設定では localhost で 161 ポートを listen する。別のホストから snmp を受け付けるには、次のように Java プログラムを起動するホストの IP アドレスを設定する。
com.sun.management.snmp.interface=172.16.1.3

アクセス権の修正

エクスプローラで c:\snmp.acl 上で右クリック、[プロパティ] を選択する。


[セキュリティ] タブを開き、[詳細設定] ボタンを押す。

「子オブジェクトに適用するアクセス許可エントリを親から継承し、それらをここで明示的に定義されているものに含める」についているチェックを外す。

「アクセス許可エントリ」から、自分の名前以外を全て削除する。
Administrator や他のユーザからのアクセス権が残っていると、Java プログラム起動時に次のようなエラーメッセージが出てしまう。
エラー: パスワードファイルの読み取りアクセスは制限する必要があります。: c:/snmp.acl

これで準備完了。
サンプルプログラムを起動したあと、snmp アクセスを許可したホスト(上記の例だと 172.16.1.2) から次のようにアクセスしてみる。
$ snmpwalk -v 2c -c public 172.16.1.3 .1 -On | less
次のような内容が出力される。
.1.3.6.1.4.1.42.2.145.3.163.1.1.1.1.0 = Gauge32: 729
.1.3.6.1.4.1.42.2.145.3.163.1.1.1.4.0 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.1.0 = Gauge32: 0
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.2.0 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.3.0 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.100.1.2.1 = STRING: "CodeCacheManager"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.100.1.2.2 = STRING: "Copy"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.100.1.2.3 = STRING: "MarkSweepCompact"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.100.1.3.1 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.100.1.3.2 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.100.1.3.3 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2.1 = STRING: "Code Cache"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2.2 = STRING: "Eden Space"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2.3 = STRING: "Survivor Space"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2.4 = STRING: "Tenured Gen"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2.5 = STRING: "Perm Gen"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2.6 = STRING: "Perm Gen [shared-ro]"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2.7 = STRING: "Perm Gen [shared-rw]"
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.3.1 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.3.2 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.3.3 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.3.4 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.3.5 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.3.6 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.3.7 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.4.1 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.4.2 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.4.3 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.4.4 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.4.5 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.4.6 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.4.7 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.112.1 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.112.2 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.112.3 = INTEGER: 1
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.112.4 = INTEGER: 2
.1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.112.5 = INTEGER: 2
...
なお、-v で指定する SNMP バージョンは 2c を指定する必要がある。
1 だと、heap 値を取得できない。

参考情報

Sun から提供されている以下のドキュメントを参考。

概要

BIG-IP + Linux 2台(CentOS 5) で DSR(Direct Server Retrun) 構成を行ったときの設定メモ。

DSRとは

こちらの記事が分かりやすい。
この記事にあるように、このままだと mac アドレスがあちこちにキャッシュされてしまい、いろいろ問題が出て少々やっかいだった。

次のように iptables と組み合わることで、簡単にこの問題を解決できる。

バックエンド設定

Linux サーバの /etc/sysconfig/iptables に対し、次の設定を行う。
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

COMMIT

# =================================================================
*nat

-A PREROUTING -p tcp -d 172.16.100.1 -j REDIRECT

COMMIT
172.16.100.1 はロードバランサで設定した VIP アドレス。

背景 - ロック手法について

データベース更新時のロックの方法として、次の2種類が存在する。
  • 悲観的ロック (Pessimistic lock)
  • 楽観的ロック (Optimistic lock)
悲観的ロックは、更新対象を更新完了までロックし、他の人が更新を行ったり、場合によっては参照も禁止する方法。
データをより安全に更新・参照できるメリットがあるが、ロック待ちによるアプリケーションの性能低下要因となりやすい。

楽観的ロックは「自分が操作している情報は他人が同時に更新する可能性が低い」更新を行うのに向いたロック方法。
更新対象を本当に更新する段階までぎりぎりまでロックしない。

例えば、「一旦データを取得したあと、内容を変更して実際に変更しようとしたら、データ取得後に誰かが同じレコードを更新していた」というケースの場合、悲観的ロックであれば「データ取得時に行ロックを行い、誰も更新できない状況」を作ってから更新を行う。その間、他の更新処理は自分の処理が完了するまで待ち状態となる。
一方、楽観的ロックであれば、自分がデータ取得後に他人がデータを更新できてしまう。自分がその後に更新しようとすると JPA 利用時、 OptimisticLockException が発生する。

概要

JPA(Java Persistence API) 1.0では楽観的ロックのみサポートしている。2.0 からは悲観的ロックもサポートするらしい。

Seasar2 + Hibernate + JPA 1.0 の構成において悲観的ロックでデータを更新したいと思い試行錯誤したが、意外とつまづいた。
EntityManager に lock() というメソッドがあって、write lock もできそうだが、うまくいかない。seasar がサポートしていないのか、設定がうまくいっていないのか...

結局、以下の方法で実現できた。

悲観的ロックによる更新方法

次のようなコードになる。
package jp.trasis.sample.service;

import javax.persistence.EntityManager;

import jp.trasis.sample.entity.User;

import org.seasar.extension.tx.annotation.RequiresNewTx;
import org.seasar.framework.container.annotation.tiger.Binding;

public class TestService {
	@Binding
	private EntityManager entityManager;
	
	@RequiresNewTx
	public void test(Long userId, String name) {
		User user = (User) entityManager.createNativeQuery(
				"select * from User_ where id=:userId for update", User.class)
			.setParameter("userId", userId)
			.getSingleResult();
		
		user.setName(name);

		entityManager.persist(user);
	}
}

解説

@RequiresNewTx アノテーションにより、新たなトランザクションの中で更新処理を行う。

まず、更新対象のエンティティを select ... for update により、行ロックを行いながら取得する。
この SQL は createNativeQuery() メソッドで実行する必要がある。crateQuery() で使用する HQL では、 for update 文は利用できない。

そしてエンティティに対して修正を行い、 persist() でコミットを行う。メソッドを抜けるときに実際に DB へのコミット処理が行われ、トランザクションが終了し、ロックも開放される。

概要

Eclispe 上で JavaScript(.js) ファイルに日本語を使うと、保存できなかったり、再度開くと文字化けしたりする。
こちらのブログ記事 に、その対策方法が記載されている。

このブログによると、Eclipse に次の設定を行うことで解決できる。

動作確認環境

項目内容
Eclipse バージョン3.3.2
3.4.1

設定手順

エクスプローラで、次のファイルを編集する。
workspace\.metadata\.plugins\org.eclipse.core.runtime\.settings\org.eclipse.core.runtime.prefs

次の内容を記述して Eclipse を再起動。
content-types/org.eclipse.wst.javascript.core.javascriptsource/charset=

プロジェクトごとに設定できるか?

複数人で開発しているときは、全員にこの設定をしてもらわないといけないし、Eclipse を新たなPCにインストールしたときも、この設定を行わないといけないので面倒...

ということで、プロジェクトにこの設定を行うことができるかどうかを試した。
結論は、残念ながらできない

プロジェクト直下にある .setting フォルダに org.eclipse.core.runtime.prefs ファイルを作成し、上記の記述を行ってみたが、反映されなかった。

Eclipse Pleiades All-in-one で対応してくれたらいいな...

2010年8月

1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31