ヒマをみつけてWeb開発
その場の思い付きを、ヒマをみつけてWebサイトにしてみるブログ

Cassandraemon 1.0.6をリリースしました

Friday, 23 December 2011 21:01 by sabro

0.8.7をリリースしたときに1.0はしばらく先になりますと書いたのですが、Cassandra1.0はThrift APIのインターフェースにほとんど変更がなかったことと、メンバーの@kojiishiさんが頑張って新機能を作ってくれたこともあって、早くもリリースすることになりました( ̄∇  ̄ )

Cassandraemon - Download: Cassandraemon 1.0.6

オブジェクトマッピングの高速化

Cassandraemonでは、オブジェクトを登録するとき、1プロパティを1カラムに格納するのですが、これまではリフレクションを使っていました。しかし、これでは遅いのでReflection.Emitで動的に変換用のアセンブリを作る方針に変更。パフォーマンスが大幅にアップしました。他にも、値型をByte配列に変換するロジックなどにも手を入れて、細かな高速化を行っています。

Serialize方法をカスタム可能に

オブジェクトをプロパティごとにシリアライズして格納する際、たとえば特定のプロパティを格納しないなどのカスタマイズが可能になりました。

// IgnoreDataMemberAttributeがついていないプロパティを取得
var properties = type.GetProperties()
     .Where(p => !p.GetCustomAttributes(
         typeof(IgnoreDataMemberAttribute), true).Any());

// Reflection.Emitを内部で使用するCompiledCassandraSerializerFactoryを使う
var factory = CompiledCassandraSerializerFactory.Default;

// 型とシリアライズするプロパティを渡してシリアライザを作る
var serializer = factory.CreateSerializer(type, properties);

// シリアライザをセット
factory.SetSerializer(type, serializer);

より詳しくは、公式のドキュメントをお読みください。

さて、次回のリリースは本当に先になるはず。気長にお待ちください( ̄□  ̄ ||

Tags:   , , , ,
Categories:   NoSQL
Actions:   Permalink | Comments (4) | Comment RSSRSS comment feed

Cassandraemon0.8.7をリリースしました

Saturday, 3 December 2011 20:44 by sabro

Cassandraemonの初の0.8系対応バージョンをリリースしました。

Cassandraemon - Download: Cassandraemon 0.8.7

Thrift APIが0.8.7バージョンのものを使っているからこんなバージョンになってますが、実質的にCassandra0.8に対応する初のリリースです。新機能は、New Feature - ver 0.8に書いてありますが、英語なので、簡単に日本語で説明しときます。

CQL

Cassandra0.8のウリであるCQLに対応しました。

using(var context = new CassandraContext("localhost", 9160, "Keyspace1"))
{
	// insert
	string insertCql = "insert into ColumnFamily1 (KEY, name1, name2) values ('key1', 'value1', 'value2')"; 
	CqlResult insertResult = context.ExecuteCqlQuery(insertCql);
	
	// get count
	string countCql = "select count(*) from ColumnFamily1 where KEY = 'key1'";
	CqlResult countResult = context.ExecuteCqlQuery(countCql);
	Console.WriteLine(countResult.Num);	// 2
	
	// get data
	string retrieveCql = "select * from ColumnFamily1 where KEY = 'key1'";
	CqlResult retrieveResult = context.ExecuteCqlQuery(retrieveCql);
	
	var dictionary = retrieveResult.ToFlatDictionary<string, string>();
	dictionary.ToList().ForEach(kv => Console.WriteLine(kv.Key + " = " + kv.Value));
	// name1 = value1
	// name2 = value2
}

CQLの結果は、Thriftで生成したコードで定義されているCqlResultで受け取るのですが、そのままだと扱いにくいので、Object、List、Dictionaryに変換できる拡張メソッドを用意してあります。

ToCassandraEntiry ()
ToFlatNameList<T> ()
ToFlatValueList<T> ()
ToFlatDictionary<TKey, TValue> ()
ToFlatValueKeyDictionary<TKey, TValue> ()
ToNameListDictionary<TKey, TListItem> ()
ToValueListDictionary<TKey, TListItem> ()
ToObjectList<T> ()
ToObjectDictionary<TKey, TValue> ()

Counter

Cassandra0.8の、もうひとつのウリであるCounterです。普通のColumnと同様の感覚で使えます。

// insert 
var cc1 = new CounterColumn().SetNameValue("one", 1);
var cc2 = new CounterColumn().SetNameValue("two", 2);
var cc3 = new CounterColumn().SetNameValue("three", 3);

context.InsertOnSubmit("CounterColumnFamily1", "key1", new[]{cc1, cc2, cc3});
context.SubmitChanges();


// get data
var query = from x in context.CounterColumnList	// <- attention "CounterColumnList"
	    where x.ColumnFamily == "CounterColumnFamily1" &&
		  x.Key == "key1"
	    select x.ToFlatDictionary<string, long>();

query.First()
     .ToList()
     .ForEach(kv => Console.WriteLine(kv.Key + " = " + kv.Value));
// one = 1
// three = 3
// two = 2

Eventを追加

Eventをいくつか追加しました。サーバに接続したタイミング、切断したタイミングなどで処理を実行できます。

ConnectionPool.Connected += (sender, e) => Console.WriteLine("Connected");
ConnectionPool.ConnectionFailed += (sender, e) => Console.WriteLine("ConnectionFailed");

CassandraContext.Created += (sender, e) => Console.WriteLine("Created");

using(var context = new CassandraContext("localhost", 9160, "Keyspace1"))
{
	context.Executed += (sender, e) => Console.WriteLine("Executed");
	context.Disposed += (sender, e) => Console.WriteLine("Disposed");
	
	var column = new Column().SetNameValue("name1", "value1"); 
	context.InsertOnSubmit("ColumnFamily1", "event", column);
	context.SubmitChanges();
	
	Console.WriteLine("Submitted");
}
// Connected
// Created
// Executed
// Submitted
// Disposed

新しいInsert API

Insertするとき、今まではCassandraEntityオブジェクトを作成しないといけなかったのですが、ColumnFamily、Keyを別途指定できるメソッドを用意しました。いちいちCassandraEntityオブジェクトを作らなくても、Column、SuperColumnなどを直接登録できます。

using(var context = new CassandraContext("localhost", 9160, "Keyspace1"))
{
	// old version
	context.Column.InsertOnSubmit(cassandraEntity);
	context.SuperColumn.InsertOnSubmit(cassandraEntity);
	context.ColumnList.InsertOnSubmit(cassandraEntity);
	context.SuperColumnList.InsertOnSubmit(cassandraEntity);

	// new version
	context.InsertOnSubmit( "ColumnFamily1", "key1", column );
	context.InsertOnSubmit( "ColumnFamily2", "key2", superColumn );
	context.InsertOnSubmit( "ColumnFamily3", "key3", columnList );
	context.InsertOnSubmit( "ColumnFamily4", "key4", superColumnList );
}

CassandraConnectionConfig

設定項目が増えてきたので、CassandraConnectionConfigにまとめました。CassandraConnectionConfigBuildeクラスを使って生成できます。

var builder = new CassandraConnectionConfigBuilder
{
	Hosts = new [] { "localhost" }
	Port = 9160,
	ConsistencyLevel = ConsistencyLevel.QUORUM,
	Timeout = TimeSpan.FromSeconds(100),
};
var config = new CassandraConnectionConfig(builder);
using (var ctx = new CassandraContext(config)) { ... }

設定項目の一覧です

Name Description Default Value
Hosts 接続するホスト string[] { "localhost" }
Port Thriftのポート番号 9160
Keyspace 接続するKeyspace "system"
ConsistencyLevel デフォルトのConsistencyLevel ( 実行中にいつでも再設定できます ) ConsistencyLevel.One
RetryCount 接続エラー時のリトライ数 -1 ( this mean nodecount * 2 )
IsFramed フレーム転送使用 true
Timeout 接続待ちのタイムアウト値 10 seconds
MinPoolCountPerHost プールするコネクションの最小値 2
MaxPoolCountPerHost プールするコネクションの最大値 int.MaxValue
Node Node取得の方式 empty string

ConnectionPoolの修正

コネクションプーリングが不安定だったのですが、地道にバグを取り、テストコードも追加して、安定性が向上しました。

今回のリリースでは、新たにメンバーに加わった@kojiishiさんに、コネクションプーリングを中心に色々手伝って頂きました。さて、やっと0.8系をリリースできましたが、セカンドライフ向けWebサービスの開発が忙しいので、1.0系はまだ少し先になりそうな感じです( ̄□  ̄ ||

Tags:   , , , ,
Categories:   NoSQL
Actions:   Permalink | Comments (0) | Comment RSSRSS comment feed