DevVeri.com

Boğulacaksan büyük veride boğul!

Apache Cassandra Astyanax

Astyanax, Java ile geliştirilmiş bir Apache Cassandra istemci kütüphanesidir. Netflix tarafından geliştirilmiş ve halen kullanılmaya devam etmektedir. Bu sebeple sık sık yeni geliştirmeler yapılmakta ve problemleri hızlıca çözülmektedir.

Astyanax’ın öne çıkan özelliklerini Thrift API’si ile uğraşmadan daha yüksek seviyeden, arayüz (interface) tabanlı, nesne yönelimli tasarıma sahip bir yapı ile Cassandra erişimi, istemci tarafında hata kontrolü ve otomatik olarak yeniden deneme (retry) mekanizması ve bağlantı havuzu (connection pool) desteği olarak sayabiliriz. Bunun dışında yeterli bir dökümantasyona sahip olduğunu ve ilham aldığı Hector projesinden çok daha düzgün bir tasarıma sahip olduğunu söyleyebiliriz. Sık sık güncelleniyor olması da gerçekten önemli bir ayrıntı.

Devam etmeden önce, eğer Cassandra kurulumu ile ilgili bilgi almak isterseniz Apache Cassandra Kurulumu yazımıza göz atabilirsiniz.

Astyanax’ı maven desteği ile kullanmak için aşağıdaki paketlere ihtiyacımız var:

<dependency>
  <groupId>com.netflix.astyanax</groupId>
  <artifactId>astyanax</artifactId>
  <version>1.0.1</version>
</dependency>
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>11.0.2</version>
</dependency>

 

Paketleri ekledikten sonra örnek amacıyla Cassandra’daki verileri Map objesi ile taşıyan çok basit bir DAO sınıfı yazalım:

import java.util.HashMap;
import java.util.Map;

import com.netflix.astyanax.AstyanaxContext;
import com.netflix.astyanax.ColumnListMutation;
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.MutationBatch;
import com.netflix.astyanax.connectionpool.NodeDiscoveryType;
import com.netflix.astyanax.connectionpool.OperationResult;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.connectionpool.impl.ConnectionPoolConfigurationImpl;
import com.netflix.astyanax.connectionpool.impl.CountingConnectionPoolMonitor;
import com.netflix.astyanax.impl.AstyanaxConfigurationImpl;
import com.netflix.astyanax.model.Column;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.ColumnList;
import com.netflix.astyanax.serializers.StringSerializer;
import com.netflix.astyanax.thrift.ThriftFamilyFactory;

public class BasicCassandraAstyanaxDao 
{
	private static final StringSerializer SS = StringSerializer.get();

	private String hosts;
	private String clusterName;
	private String keyspaceName;

	private AstyanaxContext<Keyspace> context;
	private Keyspace keyspace;
	private ColumnFamily<String, String> columnFamily;

	public BasicCassandraAstyanaxDao(String hosts, String clusterName, String keyspaceName, String columnFamilyName)
	{
		this.hosts = hosts;
		this.clusterName = clusterName;
		this.keyspaceName = keyspaceName;
		this.columnFamily = ColumnFamily.newColumnFamily(columnFamilyName, SS, SS);
	}

	public Keyspace getKeyspace()
	{
		if (keyspace == null) {
			context = new AstyanaxContext.Builder()
				.forCluster(clusterName)
				.forKeyspace(keyspaceName)
				.withAstyanaxConfiguration(new AstyanaxConfigurationImpl()      
				.setDiscoveryType(NodeDiscoveryType.NONE)
			)
				.withConnectionPoolConfiguration(new ConnectionPoolConfigurationImpl(keyspaceName + "Pool")
				.setMaxConnsPerHost(1)
				.setSeeds(hosts)
			)
			.withConnectionPoolMonitor(new CountingConnectionPoolMonitor())
			.buildKeyspace(ThriftFamilyFactory.getInstance());
			context.start();
			keyspace = context.getEntity();
		}
		return keyspace;
	}

	public void put(String key, Map<String, String> map) throws ConnectionException 
	{
		MutationBatch mutation = getKeyspace().prepareMutationBatch();
		ColumnListMutation<String> clm = mutation.withRow(columnFamily, key);
		for (Map.Entry<String, String> entry : map.entrySet()) {
			if (entry.getValue() != null) {
				clm.putColumn(entry.getKey(), entry.getValue(), null);	
			}
		}
		mutation.execute();
	}

	public Map<String, String> get(String key) throws ConnectionException
	{
		Map<String, String> map = null;

		OperationResult<ColumnList<String>> result = getKeyspace().prepareQuery(columnFamily).getKey(key).execute();
		if (result != null) {
			map = new HashMap<String, String>();
			for (Column<String> column : result.getResult()) {
				map.put(column.getName(), column.getStringValue());
			}							
		}

		if (map != null && map.size() == 0) {
			map = null;
		}
		return map;
	}

	public void delete(String key) throws ConnectionException 
	{
		MutationBatch mutation = getKeyspace().prepareMutationBatch();
		mutation.withRow(columnFamily, key).delete();
		mutation.execute();
	}

	public void destroy()
	{
		if (context != null) {
			context.shutdown();
			context = null;
			keyspace = null;
		}
	}

 

Bu sınıfı kullanan basit bir main metodu yazalım:

	public static void main(String[] args) throws ConnectionException 
	{
		final String HOSTS = "127.0.0.1:9160";
		final String CLUSTER_NAME = "Test";
		final String KEYSPACE_NAME = "Test";
		final String COLUMN_FAMILY_NAME = "Test1";

		// create dao instance 
		BasicCassandraAstyanaxDao dao = new BasicCassandraAstyanaxDao(HOSTS, CLUSTER_NAME, KEYSPACE_NAME, COLUMN_FAMILY_NAME);

		// save
		Map<String, String> saved = new HashMap<String, String>();
		saved.put("name", "Cassandra");
		saved.put("email", "cassandra@apache.org");
		dao.put("1", saved);
		System.out.println("saved object: " + saved);

		// get
		Map<String, String> loaded = dao.get("1");
		Assert.assertNotNull(loaded);
		Assert.assertEquals(saved.get("name"), loaded.get("name"));
		Assert.assertEquals(saved.get("email"), loaded.get("email"));
		System.out.println("loaded object: " + loaded);

		// delete
		dao.delete("1");
		Map<String, String> deleted = dao.get("1");
		Assert.assertNull(deleted);
		System.out.println("deleted object: " + deleted);

		// destroy dao instance
		dao.destroy();
	}

 

Yazdığımız kodu çalıştırmadan önce Cassandra’yı çalıştırdıktan sonra örnekte kullanacağımız Keyspace ve Column Family nesnelerini oluşturmak için cassandra-cli kullanalım:

$ /usr/java/cassandra/bin/cassandra-cli
Connected to: "Test Cluster" on 127.0.0.1/9160
Welcome to Cassandra CLI version 1.1.1

Type 'help;' or '?' for help.
Type 'quit;' or 'exit;' to quit.

[default@unknown] create keyspace Test;
174196b6-d45d-34e5-b051-659f933c2012
Waiting for schema agreement...
... schemas agree across the cluster
[default@unknown] use Test;
Authenticated to keyspace: Test
[default@Test] create column family Test1 with comparator = UTF8Type;
bc69772c-169e-3d20-bb86-fbb478d8d771
Waiting for schema agreement...
... schemas agree across the cluster
[default@Test]

 

Artık test kodumuzu çalıştırabiliriz, test kodumuzu çalıştığında Cassandra’ya bağlanıyor, email ve name alanlarını içeren anahtar değeri 1 olan kaydı yapıyor, daha sonra bu kaydı Cassandra’dan çekiyor. Çektiği kaydı kaydettiği kayıt ile karşılaştırdıktan sonra silip, sildiğinden de emin oluyor.

2012-07-04 23:02:31,731 INFO  [com.netflix.astyanax.connectionpool.impl.ConnectionPoolMBeanManager] Registering mbean: com.netflix.MonitoredResources:type=ASTYANAX,name=TestPool,ServiceType=connectionpool
saved object: {email=cassandra@apache.org, name=Cassandra}
loaded object: {email=cassandra@apache.org, name=Cassandra}
deleted object: null

Bu basit örneğin işinize yarayacağını umarım, daha detaylı bilgiye Astyanax dökümantasyonundan ulaşabilirsiniz.

, ,

8 thoughts on “Apache Cassandra Astyanax

  • ümit dedi ki:

    Çok teşekkürler gerçekten baya faydalı oldu bu yazınız.. Ancak bi konuya takıldım yine! Maven kullanmadım hiç ve googledan araştırdığımda da pek bişey anlamadım. ben sadece söylediğiniz dosyaların jar olanlarını indirdim 2 tane ama beceremedm. Maven konusunu da açıklar mısınız? Ne olduğundan çok ne şekilde eklemem gerekiyor projeye. Teşekkürler…

  • ümit dedi ki:

    googledan araştırdm baya ancak o dosyaları projeye nasıl ekleyebilirim anlayamadım lütfen yardımcı olun..

    • Servet Deniz dedi ki:

      Aslında maven teknolojisini kullanmanın birden çok yolu var. Ben size en kolay yollardan biri olduğunu düşündüğüm m2e eklentisi vasıtasıyla kullanmaktan bahsetmek istiyorum. m2e bir Eclipse IDE eklentisidir.

      Eklenti kurulumu :
      1)Araç çubuğunda yer alan “Help” sekmesinden “Install New Software” seçeneğini seçiyorsunuz.

      2) Karşınıza çıkan ekranın sağ tarafında yer alan “Add” tuşuna tıklıyorsunuz.
      Sizden “Name” ve “Location” bilgisi girmeniz istenecek. “Name” kısmına istediğinizi yazabilirsiniz. “Location” kısmına “http://download.eclipse.org/technology/m2e/releases ” yi girmek zorundasınız. Bu url eklentinin indirileceği adresi belirtiyor. Bu bilgileri girdikten sonra “OK” tuşuna basınız.

      3)Alt tarafda “Maven Integration for Eclipse” yazısı cıkacak yanındaki kutucuğa tik işareti koyup. “Next” tuşuna basınız.

      4)Tekrar “Next” tuşuna basarak devam ediniz.

      Not: Sözelşmeyi kabul etmenizi isteyecektir kabul edip devam ediniz. Eğer bilinmeyen kaynaktan bir dosya indirilecek indirilsin mi diye sorarsa tamam deyip devam ediniz.

      5) Eclipse’i yeniden başlatmanızı isteyecek “Restart Now” seçeneğini seçiniz.

      Proje oluşturma ve maven teknolojisini kullanma :

      1) Yeni bir Java projesi oluşturunuz.

      2)Projeye sağ tılayıp “Configure” kısmından “Convert to Maven Project” seçeneğini seçiniz.

      Aşağıda belirteceğim şekilde bir pom.xml dosyası oluşacak.
      ———————————————————————————-
      {project xmlns=”http://maven.apache.org/POM/4.0.0″ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd“}
      {modelVersion}4.0.0{/modelVersion}
      {groupId}*****{/groupId}
      {artifactId}*****{/artifactId}
      {version}0.0.1-SNAPSHOT{/version}

      {/project}
      ——————————————————————————————–
      {project} taglerinin arasına {dependecies} tag’ini yazınız. Bu tag içinde projenin bağımlılıklarını belirtiyorsunuz.

      Projenin bağımlılıklarını “mvnrepository.com” adresinden aratabilirsiniz. Karşınıza çıkan ekrandaki {dependency} taglerini ve içeriğini kopyalayıp {dependencies} taginin içine yerleştiriniz.

      Burdan sonrası bildiğimiz java projesi. Umarım yardımcı olabilmişimdir. İyi çalışmalar.

      Not : “{” ların yerine “” işaretlerini koymanız gerekiyor.
      : Arzu ederseniz size örnek bir proje gönderebilirim.

      • Servet Deniz dedi ki:

        Maven’ın kullanımı bunlarla sınırlı değildir. Bu sadece en temel halidir. Bilgilerinize.

  • Servet Deniz dedi ki:

    Hakan Bey tekrarlı cevap için özür dilerim. Tagleri kendiliğnden silmiş.

    Blog’unuz çok güzel olmuş elinize sağlık. Anlatımlarınızı devam ettirmeniz dileğiyle iyi çalışmalar.

  • ümit dedi ki:

    Servet Deniz, çok teşekkürler, çok faydalı oldu..

  • ümit dedi ki:

    tekrar merhabalar, Astyanax da normal relational DB nin karşılığı olan sorguları yapamıyorum. mesela adı ve soyadı olarak iki kolonum var select yapmaya çalıştığımda sadece en alttaki satırlar geliyor. Tüm satırların veya sadece istenen satırların gelmesini nasıl sağlayabiliriz. Cevabınız için şimdiden teşekkürler

  • ümit dedi ki:

    Hakan Bey bişey daha sormak istiyorum. Cassandrada her satır için bir key değeri gerekiyo mu? Yani ad soyad diye iki kolon oluşturduğumuz zaman veri girerken bir key değeri gerekiyor. Her veri girişinde bu key değişiyor mu hep sabit mi?

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.