Java+Thriftで簡単なKVSを作る例
Thriftとは
詳しいことはググればわかる。半年ぐらい前には「もうメンテされないかも」とか言われていたのに、Cassandraで使われてるせいか開発が活発化しており、気が付いたら0.5.0までバージョンアップしてきている。
Java用のThriftモジュールのインストール
- Apache Thriftから最新版(0.5.0)のtar.gzをダウンロードしてきて、アーカイブを展開
- cd lib/java
- ant
これでビルドされているはず。Thriftアプリを作る際には以下のjarを使う。
Thriftコンパイラのインストール
Windows版のバイナリはApache Thriftで配布されている。
ソースからビルドする場合は、compiler/cppに入ってるものをビルドする。私はWindowsで作業してるのでビルドしなかったが、READMEにビルド手順が書いてあるので、詳しくはそれを参照。
Thrift IDLからRPCコード生成(コンパイル)
とりあえずKVS的なIDLを作成。名前は適当にexample.thriftとでもしておく。
namespace java example exception AlreadyExistException { 1: string message } service SimpleKVS { // set だとThrift組み込みデータ型とバッティングする void put(1:string key, 2:string value), string get(1:string key) throws (1:AlreadyExistException error) }
IDLをコンパイル。コンパイルすると、gen-javaにソースコードが生成される。
$ thrift-0.5.0 --gen java example.thrift
プログラムの実装
ビルドしたThriftのjarをビルドパスに登録したり、IDLから生成したソースコードをコピーしたら、サーバサイド、クライアントサイドを実装する。
socketのopen/close処理が怪しいので、後でコードを修正するかも。
サーバサイドプログラム
package example; import java.util.HashMap; import org.apache.thrift.TException; import org.apache.thrift.server.TServer; import org.apache.thrift.server.TThreadPoolServer; import org.apache.thrift.transport.TServerSocket; import org.apache.thrift.transport.TServerTransport; import org.apache.thrift.transport.TTransportException; public class Server { static class SimpleKVSHandler implements SimpleKVS.Iface { private HashMap<String, String> data = new HashMap<String, String>(); @Override public void put(String key, String value) throws AlreadyExistException, TException { if (data.containsKey(key)) throw new AlreadyExistException(key); data.put(key, value); } @Override public String get(String key) throws TException { return (data.containsKey(key)) ? data.get(key) : ""; } }; public static void main(String[] args) { try { SimpleKVSHandler handler = new SimpleKVSHandler(); SimpleKVS.Processor processor = new SimpleKVS.Processor(handler); TServerTransport transport = new TServerSocket(9090); TServer server = new TThreadPoolServer(processor, transport); server.serve(); } catch (TTransportException e) { e.printStackTrace(); } } }
クライアントサイドプログラム
package example; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; public class Client { public static void main(String[] args) { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); try { transport.open(); SimpleKVS.Client client = new SimpleKVS.Client(protocol); // set System.out.println("set(foo, bar)"); client.put("foo", "bar"); // get String result1 = client.get("foo"); System.out.println("get(foo): " + result1); // 既に存在するkeyにset System.out.println("set(foo, bar)"); client.put("foo", "bar"); } catch (AlreadyExistException e) { e.printStackTrace(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } finally { transport.close(); } } }
動作確認
サーバを起動してからクライアントを起動すると以下のように出力されるはず。
set(foo, bar) get(foo): bar set(foo, bar) AlreadyExistException(message:foo) at example.SimpleKVS$put_result.read(SimpleKVS.java:942) at example.SimpleKVS$Client.recv_put(SimpleKVS.java:113) at example.SimpleKVS$Client.put(SimpleKVS.java:87) at example.Client.main(Client.java:25)