Cassandra: Cassanra のセットアップ

The Apache Cassandra Project

openSUSE 11.3 に Cassandra 0.6.4 をセットアップしてみたのでメモ。
Debian は既にパッケージングされていて、apt-get で入れる事ができるみたい。

自分はまだ、sun の java を使う人なので、sun に入れ替えて環境構築。
openSUSE 11.3 だと、デフォルトでは、OpenJDK にPATHが通っているので、/usr/lib64/jvm 以下のシンボリックリンクを自分で調節するか、アンインストールして、sun の jdk を入れればいいかな。
もっとスマートな設定ファイルがどっかにありそうだけれど・・・su -

yast --remove java-1_6_0-openjdk
yast -i java-1_6_0-sun

最初に、binary を公式からダウンロード。

wget ftp://ftp.kddilabs.jp/infosystems/apache/cassandra/0.6.4/apache-cassandra-0.6.4-bin.tar.gz
tar zxf apache-cassandra-0.6.4-bin.tar.gz
su -
mv apache-cassandra-0.6.4-bin.tar.gz /usr/local/
ln -s /usr/local/apache-cassandra-0.6.4-bin.tar.gz /usr/local/cassandra

# 起動
/usr/local/cassandra/bin/cassandra -p /var/run/cassandra.pid

# 停止
kill -KILL `cat /var/run/cassandra.pid`

デフォルトでは、bin/cassandra.in.sh を読み込む設定になっているので、独自の設定を読み込ませたい場合には、このファイルをコピーして、そちらを読むように指定するのも可能。

cp bin/cassandra.in.sh /tmp/new.in.sh
vim /tmp/new.in.sh
$CASSANDRA_INCLUDE=/tmp/new.in.sh bin/cassandra -p [pid_file]

終了するとき、killコマンドを使うしか無いようだ。まあ、いいんだけれど。pidファイルがあると、cat

でプロセスIDを表示して、kill コマンドを発行できるので、そこは楽だね。

デフォルトでは 8080 port で起動するようになっているので、これが嫌な人は、bin/cassandra.in.sh を編集すればいい。
-Dcom.sun.management.jmxremote.port=8080
が、portを指定している部分。

JVM_OPTS=" \
        -ea \
        -Xms256M \
        -Xmx1G \
        -XX:+UseParNewGC \
        -XX:+UseConcMarkSweepGC \
        -XX:+CMSParallelRemarkEnabled \
        -XX:SurvivorRatio=8 \
        -XX:MaxTenuringThreshold=1 \
        -XX:+HeapDumpOnOutOfMemoryError \
        -Dcom.sun.management.jmxremote.port=8080 \
        -Dcom.sun.management.jmxremote.ssl=false \
        -Dcom.sun.management.jmxremote.authenticate=false"

Java なだけあって、単純に起動するだけなら簡単。

log : /var/log/cassandra
data : /var/lib/cassandra/data

起動時にログを吐き出すので、それで構成を確認すればいいかな。

後は、ちょっと接続テスト。

/usr/local/cassandra/bin/cassandra-cli

# サーバに接続
cassandra> connect localhost/9160
# Keyspaceを確認
cassandra> show keyspaces
# Keyspaceの構成を確認
cassandra> describe keyspace Keyspace1

# データセット
cassandra> set Keyspace1.Standard2['jsmith']['first'] = 'John'
Value inserted.
cassandra> set Keyspace1.Standard2['jsmith']['last'] = 'Smith'
Value inserted.
cassandra> set Keyspace1.Standard2['jsmith']['age'] = '42'
Value inserted.

# データ取得
cassandra> get Keyspace1.Standard2['jsmith']
=> (column=last, value=Smith, timestamp=1271921526614000)
=> (column=first, value=John, timestamp=1271921521923000)
=> (column=age, value=42, timestamp=1271921532713000)
Returned 3 results.

1つの Key に対して、複数の Column を関連付けていくので、RDBMS に慣れていると最初戸惑いが・・・まあ、カラムを動的に追加していく。ってことだね。住所が必要なら、 set keyspace1.Standard2['jsmith']['address'] = ‘New York City’ とでも入れればいいし。

Java: java.lang.String.split() or java.util.StoringTokenizer

Androidのアプリを作っていて、テキストフォーマットのデータを読み込むのに、java.lang.String.split() を使っていたらやたら遅かった。
で、java.util.StringTokenizerに切り替えたら早かった。

ん~ C言語なら、strtokとか、ポインタを使っての実装になっているから早いのは分かるんだけれど、Javaの文字列分割でそんなに違いが出るとは思わなかった。
って事で、知り合いに相談してみたら、正規表現のせいじゃない?という話だった。
確かに・・・
String.split() は正規表現が使えるんだよね。

後、考えられるのはメモリの使い方かな。
StringTokenizer はnextToken() を呼び出したときに、メモリを確保して、文字列分割して返してもいいけれど、String.split() は配列を返すからそれが出来ない。

javaの道だと、StringTokenizerは推奨されていない。と書かれていたけれど、SunのJavaDocでは特にそういう記述は見られなかったから、StringTokenizerを使おうかな。

文字列関係では、apache.commons.StringUtil とか、結構使ったりするねー
http://commons.apache.org/

しかし、高速化を図るならやっぱり、C++がいいいね。自分が余りJavaのライブラリを知らないだけなのかなぁ
C++で組んであるプログラムを、今Javaに置き換えているんだけれど、Javaでどうやって書けば・・・ってのがたまーにある。
ifstreamが使いやすいってのもあるんだけれどね。

とりあえず、Javaで殆ど組んでしまって、高速化したいところはJNIで組むかな。
フォーマット解析なんか、JNIで組めるところだし。

ってか、今はテキストフォーマットを分かりやすいから使っているけれど、最終的にはバイナリファイルから読み込むから、あんま変わらなくなるのか~

nginx: java: nginx + tomcat

nginx(えんじんえっくす)使ってみた。

この辺りに設定例が転がっているね。
Using Nginx As Reverse-Proxy Server On High-Loaded Sites

設定例:
# 動作確認していないけれどこんな感じ。
# 時間が出来たら同じ設定での動作確認しておきます。

worker_processes  4;
worker_cpu_affinity 0001 0010 0100 1000;

events {
    worker_connections  32768;
    use epoll;
}

http {
    include proxy.conf;
    include mime.types;

    # JavaServlet
    upstream tomcat{
        server 192.168.1.21:8080 wight=5;
        server 192.168.1.22:8080 wight=5;
    }

    server {
        listen    redhawk.jp:80 default;

        location /javaservlet {
            proxy_pass http://tomcat/javaservlet;
        }
    }
}

実際使ってみたんだけれど、リバースプロキシとしての機能部分しか使わないのでApache + mod_jk を使うよりも負荷は軽い。

使い方は、tomcatを起動してその後に、location なり、サブドメインなりで判定して、tomcat にリクエストを投げてあげるだけ。

プロセスに HUP を投げると、設定ファイルを再読み込みするので、再起動の必要もない。
# HUPはバグがあるから多用しない方がいい。と職場の人が言っておりましたが。

upstream 設定を使うと、weight を設定して、ロードバランサーの機能を持たせる事も出来るので
Django や、 Passenger との連携も出来るらしいので、Java, Python, Ruby を使う時には便利だと思う。

PHP は、まあ、どうでもいいです。
fastCGIで使ってみたけれど、処理負荷が高すぎて、アクセスが本当に多いサイトだと持たない。
nginxというより、PHPの問題だし。
それに、fastCGI使うくらいなら、apache module で動かした方が設定も楽だしで PHP メインなら、nginx は不要かと。

JPAとかSeasarとか

JPAの問題点
というブログ記事を発見。

確かに、JPAの問題点はたくさんあるよね。

でも、Spring も Hibernate もドキュメントが揃っているので、楽です。
Seasar は昔使っていたんだけれど、ドキュメントが無さ過ぎて、調べてもでてこないというのが辛かった。

MLで聞けばいいんだろうけれど、自分はそれよりも、多少扱いづらい部分があっても
ドキュメントが最初からある方を選ぶかな。

そこは人それぞれだからなんとも言えないけれどね。

まあ、これから段々使いやすくなっていくでしょう。
JavaはWebシステム構築としてこれからも使うだろうし。

パフォーマンス必要ないときは、Pythonを使うけれどね(・・

Java: Struts2: SessionToken 二重送信防止機能

Struts2 には二重送信防止機能も付いている。
トークンを発行してセッションに保存した後、一度だけそのトークンでのActionの実行を許可する。という内容。

tokenとtokenSessionの二つがあって、tokenSessionの方は、二重送信後にも一度目の送信結果画面を表示してくれる。
今のところ、tokenSessionしか使っていないので、そっちの設定例を。

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
  <constant name="struts.objectFactory" value="spring" />
  <constant name="struts.devMode" value="false" />

  <package name="mypackage" extends="struts-default">
    <interceptors>
      <interceptor-stack name="myStack">
        <interceptor-ref name="tokenSession">
          <param name="includeMethods">add</param>
        </interceptor-ref>
        <interceptor-ref name="defaultStack" />
      </interceptor-stack>
    </interceptors>
    <default-interceptor-ref name="myStack" />
    <action name="act" class="Action">
      <result name="invalid.token" type="redirectAction">/hoge</result>
    </action>
  </package>
</struts>

JSP側

<s:form action="user_add">
 <s:token/>
   :
</s:form>

Action単位でも設定できるので、詳しくはこちらを。
TokenInterceptorの使い方
Token Session Store Interceptorの使い方

Java: JPA: specified twice エラー

JPAで
@OneToOne
@JoinColumn
を使って、JOINを張ったら、そのモデルを使って INSERT文を走らせる時に、specified twice っていうエラーが出るようになった。
SQLを見てみると、確かに同じColumnを二回指定している。

http://72.5.124.55/javaee/5/docs/api/javax/persistence/JoinColumn.html

ここを見ると、
@JoinColumn(insertable = false)
というのがあるので、それを指定したら解決。

updatable

public abstract boolean updatable
(Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider.
Default:
true

ってあるように、Modelの中身を更新すると、勝手に UPDATE文が走るので、それが嫌な人は false にしておこう。

このオプションは
@Column
にもあるので、別にJOIN限定の処理ではない。

JPAはアノテーションをモデルにいくつくっつけるかの設定次第だなぁ

Djangoも結局、キーワード引数でいくつオプション付けるか。
っていう部分は当然あるし。
まあ、そうなるよなーって思う。
そう思うから、Annotation で Model いじればなんとかなるんじゃね?って思って調べるきっかけになるし。

JPAでこれだけ色々やれるってなると、本気のHIBERNATEを使ってみたくなるなぁ
どんだけ凄いんだろう。

Java: JPA: JPA でリレーション

最近のJavaは、LLに対応してか、LLで簡単に出来る事を、Javaも簡単に出来る様になってきている。
Javaの方が早いので、自分の仕事の場合、Javaを使う機会が多い。
という訳で、JPAでリレーションってどうやるんだろ。と調べてみたら、JPA + Oracle の記事があった。しかも、結構古いしw

JPAの試用

ん~ Djangoとかとやる事は一緒だなぁ
Model 部分で関連付け登録をしてあげて、後はお任せ!
ってやつですな。

はまるポイントが一箇所あって
JPAの規約では、外部キーは、REG_ID の様に、大文字_IDと変換されます。

CREATE TABLE category
(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(255) UNIQUE,
  PRIMARY KEY(id)
)
ENGINE=MyISAM
;

CREATE TABLE book
(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  book_category_id INT UNSIGNED NOT NULL,
  name VARCHAR(255),
  PRIMARY KEY(id)
)
ENGINE=MyISAM
;

というテーブルがあった場合

@Entity
@Table(name = "book_category")
public class BookCategory {

	@Id
	@GeneratedValue
	@OneToOne(mappedBy = "book_category")
	private Integer id;

	private String name;

}

@Entity
@Table(name = "book")
public class Book{

	@Id
	@GeneratedValue
	private Integer id;

	@Column(name = "book_category_id")
	private Integer bookCategoryId;

	@OneToOne
	@JoinColumn(name = "BOOK_CATEGORY_ID")
	private BookCategory bookCategory;
}

こんな感じになる。
# Getter, Setterとか、テーブル定義とかは省略。

ログを追ってみると、どうにもSQLを二回発行しているっぽい。
InnoDBで作ると違う結果かもしれないし、MyISAMの場合、二回SELECTしてもそれほど遅くないのでいいかな。
それが気になるなら、O/R Mapper使うなーって思うし。

JPAのQueryの書き方とかちょっとキモイけれど、慣れればそんなものかなーって思わなくもないかも。
まだ余り使い込んでいないので、無駄に変な取得の仕方をしている部分があるだろうけれど・・・

とりあえず、必ずListでしか取れないってのはおかしいと思うんだよね。
何か方法があるはず・・・

count取る時は、Longできちんと取れているし・・・
まあ、まだまだ慣れていないからなー

Struts2 + Spring + JPA で作業しているけれど、結構使いやすいとは思う。
struts.xml が凄い量になってきているけれど。
まあ、そんなものかなぁ・・・と思わないでもない。
パフォーマンスも気にならないので、暫くこれで様子を見てみよう。
LL使うのに比べたら、ちょっと変な処理入っていても早いからなぁ~

Struts2: Java: interceptor でハマったよ

Struts2 でアプリを作っていて、Interceptor を使おうとしたら、めちゃはまった・・・

public class AuthenticationInterceptor extends AbstractInterceptor {

	private static final long serialVersionUID = 1L;

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		Map<String, Object> session = ActionContext.getContext().getSession();
		Boolean auth = (Boolean)session.get(AuthenticationAction.AUTH_KEY);
		if (null == auth || !auth.booleanValue()) {
			return "auth-error";
		} else {
			// 次のインターセプター処理
			return invocation.invoke();
		}
	}

}

というのが正解のソースコード。

じゃあ、何がダメなやつはどこがおかしかったのかと言うと
この Interceptor 独自の戻り値を struts.xml で定義した、global-results の値にマッチングさせたい時
次のインターセプター処理を呼び出してはいけない!!
って事ですな・・・

インターセプターが戻り値を持っている時点でもっと早く気がつけよ。って気がしないでもないです。はい。

ちなみに、 struts.xml はこんな感じ。




  
  

    
      
      
        
        
      
    
    
    
    
      auth/login
    
    
      /WEB-INF/pages/admin/index.jsp
      auth/login
    
  

    
      admin/index
      /WEB-INF/pages/auth/login.jsp
    
  

JavaでShift_JISの漢字コードチェック(第一水準、第二水準)

Javaで、Shift_JISの漢字コードをチェックしてくれ。とかいう話があって、えー 面倒くせぇ・・・
とか思いつつも、自分なりのライブラリがあったほうが将来的に便利だな。と思ったので作成。
JUnitでTestCase作ってはいるんだけれど、これ、全部の文字テストするのは時間がかかるので、ちまちまとアップデートしていきます。
今のところ、チェック数が少ないのでバグがあるかもしれないです。
環境は、Java6.0だけれど、バージョン依存しそうなのは特に使ってないかなぁ
コードはこちら。

CharacterUtil
CharacterUtilTest

あー 今度Python使って、漢字一覧表を ‘漢’, ‘字’, フォーマットに変換して、テストケース作るかなぁ
手動で書くなんてありえない!!w
それと、Javaだと確か、EndianはBig-Endianに揃えてくれるんだよね?
って事で調べた。
http://java.sun.com/javase/ja/6/docs/ja/api/java/nio/ByteBuffer.html
ほんで、更に調べたら、Java1.4から実装されたライブラリでnativeなendianを調べるAPIがあるらしい。
http://java.sun.com/javase/ja/6/docs/ja/api/java/nio/ByteOrder.html
ま、とりあえず、今回自分が作ったライブラリの場合、Big-Endian前提だけれど、問題ないということで。
あ~ 今日は、DirectXで遊ぼうと思ったのになぁ・・・何でJavaやってんだろw
== 追記 ==
JavaでShift_JISの漢字コードチェック(第一水準、第二水準) その後
で、コード修正。

配列のリテラルはどう書く?

久しぶりにプログラミングネタ。
まあ、大した内容でもないんだけれどさ。
配列のリテラル(literal)を書くときって、なるべく最後の要素の後ろにも ,(カンマ)を付ける様な癖が付いていたりする。
なぜかというと、配列の要素は後で増やす事がありえるし、その時に ,(カンマ)を入れ忘れてしまう事が多いからだ。
そんなのは、コンパイルすれば直ぐにエラーが出て気がつく事だけれど、動的な言語だったりすると、その部分が処理されるまで分からない潜在的なバグに繋がる。
コンパイル言語にしても、コード量が増えてくると一回のコンパイルに凄い時間がかかるし、当たり前にコード記述でそういうエラーやバグの元は排除するべきだと思う。
って、一々くどい前置きがあるのは、自分の配列の書き方にこの間けちを付けられたからだw
そういえば、if文の書き方もおかしいとか言われた事があるな。ま、それは違うエントリーにするか。あれ、前に書いたか・・・?
C言語でも書ける。gcc4.3でコンパイルエラーは出なかった。

int a[] = {1, 2, 3, 4, };

Javaでも書ける。JavaSE6.0でコンパイルエラーは出なかった。

int[] a = {1, 2, 3, 4, };

大抵の言語はこの記述を許可しているんだよね。
ただ、JavaScriptでJQueryのAJaxAPIでこの書き方をしたら、IEで構文エラーが出たことがあるね。
一番最後に要素を追加する時の、ミスを無くすための小さな対策でした。
というか、この書き方をしていて突っ込まれたの初めてだな。
今まで一度も見たこと無かったのかな・・・?