本文主要介绍Apache Cassandra的入门级用法。学习NoSQL最重要的就是要忘记常规原理和关系型数据库的结构。关系型数据库被设计为由常规数据组成,并且没有重复数据。因此,NoSQL数据库的一个主要改变是需要思考或设计查询,并按需创建一个不变的结构。
许多网页、书籍与论文都在讨论什么是Cassandra、Hazelcast、Hadoop、MemcacheDB和MongoDB等等,但没有一个讨论如何将关系型数据库中的数据转换为这些NoSQL数据中的一种。
本文对Turmeric SOA Monitoring与Turmeric SOA Rate Limiting两个模块的数据进行转换,使用关系数据库MySQL,并且对一些NoSQL数据库进行了为期一周的阅读与分析后,决定使用Cassandra。
从关系表到Keyspaces
(注:keyspace是Cassandra 中最顶层的命名空间。)
现在要考虑的问题是如何转换它们,可按以下方法进行:
根据敏捷开发的相关经验,如果某事件很难或很复杂,最好将其分成多个部分,因为毕竟与MMF(Minimal Marketable Feature,最小市场化功能)之间还有一定的差距。步骤如下:
步骤1:将关系数据库中的表转移到Cassandra列族(Column Families)中
步骤2:创建新的列族使所有数据无需进行JOIN等操作。
步骤3:根据搜索器与查询方法的需要扩展列族。通常情况下一个搜索器或一个查询方法使用一个列族。
步骤4:根据之前的步骤修改Creators与Updater函数。不要担心保存重复数据,只要记住一点:只需考虑数据查询,忘记以前关系型数据库相关的法则。
步骤5:判断,如果没有完成,继续做步骤3与步骤4。
Cassandra DAO
在上面步骤中,最难的是第一步。不过不用担心,本文为数据转移开发了一个通用的Cassandra DAO(实际上是使用的Java泛型)。由于本例来源于实际项目,你可能发现它是作为TurmericSOA的子模块,不过根据Apache许可,用户可以在自己Maven依赖文件中使用它们。
<dependency>
<groupId>org.ebayopensource.turmeric.utils</groupId>
<artifactId>turmeric-utils-cassandra</artifactId>
<version>1.2.0.0-SNAPSHOT</version>
<type>jar</type>
</dependency>
特性
· 100%Java代码
· 可以作为嵌入式Cassandra服务使用,也可以作为外部Cassandra服务使用
· 使用Hector库作为Java Cassandra客户端
· 动态创建列族(Column Family)
· 关键字类型与数据类型在运行时使用泛型创建
· 支持主要的CRUD方法:
boolean containsKey(KeyType key);
void delete(KeyType key);
T find(KeyType key);
Map> findItems(final List keys, final Long rangeFrom, final Long rangeTo);
Set findItems(final List keys, final String rangeFrom, final String rangeTo);
Set getKeys();
void save(KeyType key, T model);
主要的类
该功能包包含以下包和类:
1. org.ebayopensource.turmeric.utils.cassandra.service
· CassandraManager: 根据yaml配置文件初始化静态EmbeddedCassandraService实例
2. org.ebayopensource.turmeric.utils.cassandra.hector
· HectorManager: 管理keyspace与列族的创建与读取,使用Hector API。
· HectorHelper: 包含一些基于Java Reflection与Java Generics的实用方法。IE: 从在cassandra keyspaces中作为列名的POJO中检索字段名。
3. org.ebayopensource.turmeric.utils.cassandra.dao
· AbstractColumnFamilyDao: 如其名称,是每个dao都要扩展的基类,利用Dector Api定义并实现了基本的DAO操作。
配置文件
· log4j.properties: Log4j属性文件
· cassandra.yaml: 存储配置文件。更多信息可参考storage configuration setup。
以下为配置文件的目录结构:
META-INF/
security/
config/
cassandra/
cassandra.properties
属性文件的一个示例:
cassandra-cluster-name=TurmericCluster
cassandra-host-ip=127.0.0.1
cassandra-rpc-port=9160
cassandra-my-keyspace=My-keyspace
#column families
cassandra-foo-column-family=foo
cassandra-bar-column-family=bar
使用方法
假定关系数据库MySQL中有一个名为Foo的表。则:
1. 创建BaseDao接口
public interface BaseDao {
public void delete(String key);
public Set getKeys();
public boolean containsKey(String key);
public void save(String key, FooPojoClass fooPojo);
public FooPojoClass find(String key);
}
2. 创建FooDao接口
public interface FooDao extends BaseDao {
}
3. 创建FooDao implementation
public class FooDaoImpl extends AbstractColumnFamilyDao
implements FooDao {
public FooDaoImpl(final String clusterName, final String host, final String keySpace, final String cf, final Class kTypeClass) {
super(clusterName, host, keySpace, kTypeClass, FooPojo.class, cf);
}
}
自定义的代码
//initiates an embedded Cassandra Service
CassandraManager.initialize();
//creates our Foo Column Family
FooDao fooDao = new FooDaoImpl("myCluster", "127.0.0.1", "myKeyspace",
"myColumnFamilyName", String.class);
至此,已经成功将一个关系表转换为一个Cassandra列族!
用户可以参考UT类来查看它们具体是如何实现的。