Apache Cassandra 的初步使用及一些简单的操作

akingde

贡献于2012-07-07

字数:26643 关键词: NoSQL数据库 Apache

Apache Cassandra   Apache Cassandra是一套开源分布式数据库管理系统。它最初由Facebook开发,用于储存特别大的数据。 主要特性:   ● 分布式   ● 于column的结构化  ● 高伸展性   Cassandra是一个混合型的非关系的数据库,类似于Google的BigTable。Cassandra的主要特点就是它不是一个数据库,而是由一堆数据库节点共同构成的一个分布式网络服务,对Cassandra 的一个写操作,会被复制到其它节点上去,对Cassandra的读操作,也会被路由到某个节点上面去读取。对于一个Cassandra群集来说,扩展性能是比较简单的事情,只管在群集里面添加节点就可以了。   Cassandra的主要功能比 Dynamo(分布式的Key-Value存 储系统)更丰富,但支持度却不如文档存储MongoDB(介于关系数据库和非关系数据库之间的开源产品,是非关系数据库当中功能最丰富,最像关系数据库的。支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。) Cassandra最初由Facebook开发,后转变成了开源项目。它是一个网络社交云计算方面理想的数据库。以Amazon专有的完全分布式的Dynamo为基础,结合了Google BigTable基于列族(Column Family)的数据模型。P2P去中心化的存储。很多方面都可以称之为Dynamo 2.0。   和其它数据库比较,Cassandra有三个突出特点:   ■  模式灵活 :使用Cassandra,像文档存储,你不必提前解决记录中的字段。你可以在系统运行时随意的添加或移除字段。这是一个惊人的效率提升,特别是在大型部署上。   ■  真正的可扩展性 :Cassandra是纯粹意义上的水平扩展。为给集群添加更多容量,可以指向另一台计算机。你不必重启任何进程,改变应用查询,或手动迁移任何数据。   ■  多数据中心识别 :你可以调整你的节点布局来避免某一个数据中心起火,一个备用的数据中心将至少有每条记录的完全复制。   一些使Cassandra提高竞争力的其它功能:   ■  范围查询 :如果你不喜欢全部的键值查询,则可以设置键的范围来查询。   ■  列表数据结构 :在混合模式可以将超级列添加到5维。对于每个用户的索引,这是非常方便的。   ■  分布式写操作 :有可以在任何地方任何时间集中读或写任何数据。并且不会有任何单点失败。 Cassandra分布式节点服务器的简单部署 文章分类:数据库 Cassandra作为目前很热门的一个NOSQL型数据库,引起了很多的关注。对NOSQL感兴趣的我,也来作了一次简单的测试。 废话不多说,下面就来介绍下Cassandra多节点的部署。 部署要求: 1. JDK1.6 2. OS:linux,我在windows上实验过,不知道为啥一直没通(7000端口上只有windows的发包,双方不互相通信) 3. cassandra 0.6 OK,基本的东西都有了,进入到cassandra的目录,首先需要修改一些相关的文件路径: 1. log4j.properties     文件输出路径修改 2. storage-conf.xml    CommitLogDirectory和DataFileDirectory路径修改 接着进行分布式节点的配置,还是修改torage-conf.xml : 1.  Test Cluster       这个要求所有节点的名字都相同,如果不相同,则报类似 AName != BName 的错误 2.       配置ColumnFamily 的一些属性,其中name是所要使用的ColumnFamily 名称,可以多个,客户端做CRUD操作时需要指定。注意所有的节点配置都需要一样(我就曾因配置不一致出过ClassCastException的异常) 3. 2       配置数据需要复制的数量,复制的策略分RackUnawareStrategy和RackAwareStrategy两种方式(策略没细看不再描述) 4.        10.10.13.220   10.10.13.181   10.10.13.232         这个是所有分布式服务器节点的IP地址,如上面配置了3个IP即3个Cassandra节点 5. 10.10.13.220     10.10.13.220     本节点监听客户端数据和与其他服务器节点通信的IP地址,只能为本机IP,且不能为127.0.0.1或localhost,否则与其他服务器不能建立正确交互     此处的IP地址也可以不填,即值为空,则所有的节点配置都一样,更方便部署。 搞定storage-conf.xml !下面的工作就是将所有的Cassandra服务器节点依次启动,通过日志就可以看到相关的节点连接上了,日志为: Log4j代码 1. INFO 13:04:52,098 Node /10.10.13.232 is now part of the cluster   INFO 13:04:52,098 Node /10.10.13.232 is now part of the cluster 到这里,Cassandra分布式节点服务器的搭建就完成了。使用官网提供的客户端代码进行测试,发现数据已经提交到服务器并且在多个节点间进行复制了 在这里抱怨一下:之前由于没有足够的服务器,使用windowsXP+solaris双节点进行测试,发现怎么也建立不起来。。。后来加入linux后,solaris+linux的方式却能正常走通,配置也都是一样的。 有空研究下为何在我的windows上不支持。。。。 参考地址: http://cassandra.apache.org/ 如何安装和配置Cassandra 文章分类:数据库 Cassandra属于最近比较流行的一款NoSQL数据库,http://nosql-database.org/中给NoSQL的定义如下: 下一代的数据库产品应该具备这几点:非关系型的,分布式的,开源的,可以线性扩展的。这类数据库最初的目的在于提供现代网站可扩展的数据库解决方案。这个运动开始于2009年初,目前正在迅速的发展。这种类型的数据库具有:自由的schema,数据多处备份,简单的编程API,数据的最终一致性保证等等。所以我们将这种类型的数据库称为NoSQL(不仅仅是SQL,全称为“not only sql”)。 下面我们一起来看看如果分别在Windows和Linux环境下安装和部署Cassandra。 在Windows上单机运行Cassandra 大多数人使用的OS都是Windows,所以如果只是想简单地测试一下Cassandra,我们可以直接在安装好JDK1.6的Windows系统上安装Cassandra,并进行简单的测试。 1 下载Cassandra 去http://cassandra.apache.org/下载即可。目前最新的beta版本是0.6.0 b3,但是我们安装使用的最新的Release版本0.5.1。 2 安装Cassandra 将下载的压缩包解压,假设解压的位置是D:\apache-cassandra-0.5.1。 1 修改conf目录下的log4j.properties文件: log4j.appender.R.File=D:\apache-cassandra-0.5.1\logs 2 修改conf目录下的storage-conf.xml文件: D:\apache-cassandra-0.5.1\commitlog                  D:\apache-cassandra-0.5.1\data             D:\apache-cassandra-0.5.1\callouts D:\apache-cassandra-0.5.1\staging 3 设置系统的环境变量: CASSANDRA_HOME=D:\apache-cassandra-0.5.1 3 启动Cassandra 运行bin目录下的cassandra.bat。如果看到:INFO - Starting up server gossip,那么恭喜你,Cassandra已经在你的本机启动起来了。 4 使用命令行进行简单的测试 运行bin目录下的cassandra-cli.bat。输入:connect localhost 9160,连接成功后可以看到下面的提示。 cassandra> connect localhost 9160 line 1:18 missing SLASH at '9160' Connected to localhost/9160 然后,我们可以参考README.txt文件中提供的范例进行测试: cassandra> set Keyspace1.Standard1['jsmith']['first'] = 'John' Value inserted. cassandra> set Keyspace1.Standard1['jsmith']['last'] = 'Smith' Value inserted. cassandra> set Keyspace1.Standard1['jsmith']['age'] = '42' Value inserted. cassandra> get Keyspace1.Standard1['jsmith']   (column=age, value=42; timestamp=1249930062801)   (column=first, value=John; timestamp=1249930053103)   (column=last, value=Smith; timestamp=1249930058345) Returned 3 rows. cassandra> 你也可以根据这篇文章《谈谈Cassandra的客户端》中的内容测试一下如何使用Java编写简单的程序和Cassandra交互。 在Linux上运行Cassandra集群 如果需要真正在生产环境中使用Cassandra,我们需要搭建一个Cassandra集群,这样才能真正发挥出它作为NoSQL数据所应该具备的特性。 在Linux部署Cassandra的步骤基本与Windows上部署的类似,我们需要在每一台机器上安装JDK1.6,然后下载Cassandra,并修改log4j.properties和storage-conf.xml的配置文件和设置环境变量。不同的是,我们需要在storage-conf.xml文件中配置集群的信息: 1 配置集群 1 配置集群节点信息       hadoop2       hadoop3       hadoop4       hadoop5       hadoop6       hadoop7       hadoop8       hadoop9       hadoop10   2 配置集群节点之间交互的监听地址 直接留空即可: 3 配置Thrift Server监听的地址 直接留空即可: 4 配置集群的名称 每一个集群的名称都应该是不用的 gpcuster.cnblogs.com 5 开启节点自动加入集群的功能 true 6 配置数据的备份数 3 7 调节Memory和Disk的性能 需要根据实际的情况来配置,可以参考Wiki。 2 运行Cassandra 在每一台节点上,运行bin/cassandra。如果看到:INFO - Starting up server gossip,说明启动成功。 3 查看集群运行情况 当所有的节点都运行起来以后,我们可以通过JMX查看运行状况: 总结 在Windows环境和Linux环境下部署Cassandra基本都是类似的。只不过在Linux环境下bin目录中的脚本都能在Linux环境下运行,而Windows环境下只有2个脚本可以运行。 谈谈Cassandra的客户端 最近试用了一段时间Cassandra,将Oracle中的数据导入进来,遇到了问题然后解决问题,收获挺大。在这个过程中,除了设计一个合理的数据模型,再就是使用Cassandra API进行交互了。 Cassandra在设计的时候,就是支持Thrift的,这意味着我们可以使用多种语言开发。 对于Cassandra的开发本身而言,这是使用Thrift的好处:支持多语言。坏处也是显而易见的:Thrift API功能过于简单,不具备在生产环境使用的条件。 在Cassandra Wiki页面上,也有基于Thrift API开发的更加高级的API,各个语言都有,具体信息可以参考:http://wiki.apache.org/cassandra/ClientExamples。 这次只谈谈下面两类Java的客户端: 1 Thrift Java API 2 hector Thrift Java API 这个是Cassandra自带的最简单的一类API,这个文件在apache-cassandra-0.5.1.jar中包含了。可以直接使用。我们也可以自己安装一个Thrift,然后通过cassandra.thrift文件自动生成。 如果你要使用Cassandra,那么我们必须要了解Thrift API,毕竟所有的其他更加高级的API都是基于这个来包装的。 提供的功能 插入数据 插入数据需要指定keyspace,ColumnFamily, Column,Key,Value,timestamp和数据同步级别。(如何需要了Cassandra的解数据模型,可以参考《大话Cassandra数据模型》) /** * Insert a Column consisting of (column_path.column, value, timestamp) at the given column_path.column_family and optional * column_path.super_column. Note that column_path.column is here required, since a SuperColumn cannot directly contain binary * values -- it can only contain sub-Columns. * * @param keyspace * @param key * @param column_path * @param value * @param timestamp * @param consistency_level */ public void insert(String keyspace, String key, ColumnPath column_path, byte[] value, long timestamp, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException;   /** * Insert Columns or SuperColumns across different Column Families for the same row key. batch_mutation is a * map> -- a map which pairs column family names with the relevant ColumnOrSuperColumn * objects to insert. * * @param keyspace * @param key * @param cfmap * @param consistency_level */ public void batch_insert(String keyspace, String key, Map> cfmap, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException; 读取数据 获取一个查询条件精确的值。 /** * Get the Column or SuperColumn at the given column_path. If no value is present, NotFoundException is thrown. (This is * the only method that can throw an exception under non-failure conditions.) * * @param keyspace * @param key * @param column_path * @param consistency_level */ public ColumnOrSuperColumn get(String keyspace, String key, ColumnPath column_path, int consistency_level) throws InvalidRequestException, NotFoundException, UnavailableException, TimedOutException, TException;   /** * Perform a get for column_path in parallel on the given list keys. The return value maps keys to the * ColumnOrSuperColumn found. If no value corresponding to a key is present, the key will still be in the map, but both * the column and super_column references of the ColumnOrSuperColumn object it maps to will be null. * * @param keyspace * @param keys * @param column_path * @param consistency_level */ public Map multiget(String keyspace, List keys, ColumnPath column_path, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException; 获取某一个keyspace,Key,ColumnFamily,SuperColumn(如果有的话需要指定)下面的相关数据:只查询Column的name符合条件的相关数据(SlicePredicate)。 /** * Get the group of columns contained by column_parent (either a ColumnFamily name or a ColumnFamily/SuperColumn name * pair) specified by the given SlicePredicate. If no matching values are found, an empty list is returned. * * @param keyspace * @param key * @param column_parent * @param predicate * @param consistency_level */ public List get_slice(String keyspace, String key, ColumnParent column_parent, SlicePredicate predicate, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException;   /** * Performs a get_slice for column_parent and predicate for the given keys in parallel. * * @param keyspace * @param keys * @param column_parent * @param predicate * @param consistency_level */ public Map> multiget_slice(String keyspace, List keys, ColumnParent column_parent, SlicePredicate predicate, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException; 查询Key的取值范围(使用这个功能需要使用order-preserving partitioner)。 /** * @deprecated; use get_range_slice instead * * @param keyspace * @param column_family * @param start * @param finish * @param count * @param consistency_level */ public List get_key_range(String keyspace, String column_family, String start, String finish, int count, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException;   /** * returns a subset of columns for a range of keys. * * @param keyspace * @param column_parent * @param predicate * @param start_key * @param finish_key * @param row_count * @param consistency_level */ public List get_range_slice(String keyspace, ColumnParent column_parent, SlicePredicate predicate, String start_key, String finish_key, int row_count, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException; 查询系统的信息。 /** * get property whose value is of type string. * * @param property */ public String get_string_property(String property) throws TException;   /** * get property whose value is list of strings. * * @param property */ public List get_string_list_property(String property) throws TException;   /** * describe specified keyspace * * @param keyspace */ public Map> describe_keyspace(String keyspace) throws NotFoundException, TException; 通过这些操作,我们可以了解到系统的信息。 其中一个比较有意思的查询信息是:token map,通过这个我们可以知道哪些Cassandra Service是可以提供服务的。 删除数据 /** * Remove data from the row specified by key at the granularity specified by column_path, and the given timestamp. Note * that all the values in column_path besides column_path.column_family are truly optional: you can remove the entire * row by just specifying the ColumnFamily, or you can remove a SuperColumn or a single Column by specifying those levels too. * * @param keyspace * @param key * @param column_path * @param timestamp * @param consistency_level */ public void remove(String keyspace, String key, ColumnPath column_path, long timestamp, int consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException, TException; 这里需要注意的是,由于一致性的问题。这里的删除操作不会立即删除所有机器上的该数据,但是最终会一致。 程序范例 import java.util.List; import java.io.UnsupportedEncodingException;   import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.TException; import org.apache.cassandra.service.*;   public class CClient { public static void main(String[] args) throws TException, InvalidRequestException, UnavailableException, UnsupportedEncodingException, NotFoundException { TTransport tr = new TSocket("localhost", 9160); TProtocol proto = new TBinaryProtocol(tr); Cassandra.Client client = new Cassandra.Client(proto); tr.open();   String key_user_id = "逖靖寒的世界";   // insert data long timestamp = System.currentTimeMillis(); client.insert("Keyspace1", key_user_id, new ColumnPath("Standard1", null, "网址".getBytes("UTF-8")), "http://gpcuster.cnblogs.com".getBytes("UTF-8"), timestamp, ConsistencyLevel.ONE); client.insert("Keyspace1", key_user_id, new ColumnPath("Standard1", null, "作者".getBytes("UTF-8")), "逖靖寒".getBytes("UTF-8"), timestamp, ConsistencyLevel.ONE);   // read single column ColumnPath path = new ColumnPath("Standard1", null, "name".getBytes("UTF-8")); System.out.println(client.get("Keyspace1", key_user_id, path, ConsistencyLevel.ONE));   // read entire row SlicePredicate predicate = new SlicePredicate(null, new SliceRange(new byte[0], new byte[0], false, 10)); ColumnParent parent = new ColumnParent("Standard1", null); List results = client.get_slice("Keyspace1", key_user_id, parent, predicate, ConsistencyLevel.ONE); for (ColumnOrSuperColumn result : results) { Column column = result.column; System.out.println(new String(column.name, "UTF-8") + " -> " + new String(column.value, "UTF-8")); }   tr.close(); } } 优点与缺点 优点:简单高效 缺点:功能简单,无法提供连接池,错误处理等功能,不适合直接在生产环境使用。 Hector Hector是基于Thrift Java API包装的一个Java客户端,提供一个更加高级的一个抽象。 程序范例 package me.prettyprint.cassandra.service;   import static me.prettyprint.cassandra.utils.StringUtils.bytes; import static me.prettyprint.cassandra.utils.StringUtils.string;   import org.apache.cassandra.service.Column; import org.apache.cassandra.service.ColumnPath;   public class ExampleClient {   public static void main(String[] args) throws IllegalStateException, PoolExhaustedException, Exception { CassandraClientPool pool = CassandraClientPoolFactory.INSTANCE.get(); CassandraClient client = pool.borrowClient("localhost", 9160); // A load balanced version would look like this: // CassandraClient client = pool.borrowClient(new String[] {"cas1:9160", "cas2:9160", "cas3:9160"});   try { Keyspace keyspace = client.getKeyspace("Keyspace1"); ColumnPath columnPath = new ColumnPath("Standard1", null, bytes("网址"));   // insert keyspace.insert("逖靖寒的世界", columnPath, bytes("http://gpcuster.cnblogs.com"));   // read Column col = keyspace.getColumn("逖靖寒的世界", columnPath);   System.out.println("Read from cassandra: " + string(col.getValue()));   } finally { // return client to pool. do it in a finally block to make sure it's executed pool.releaseClient(client); } } } 优点 1 提供连接池。 2 提供错误处理:当操作失败的时候,Hector会根据系统信息(token map)自动连接另一个Cassandra Service。 3 编程接口容易使用。 4 支持JMX。 缺点 1 不支持多线程的环境。 2 keyspace封装过多(数据校验和数据重新封装),如果进行大量的数据操作,这里的消耗需要考虑。 3 错误处理不够人性化:如果所有的Cassandra Service都非常繁忙,那么经过多次操作失败后,最终的结果失败。 总结 Hector已经是一个基本足够使用的Java客户端了,但是还是缺乏一些相关的功能,比如: 1 线程安全。 2 支持自动的多线程查询和插入,提高操作效率。 3 人性化的错误处理机制。 4 避免过多的封装。 Linux下如何设置环境变量,今天总结了一下,发出来和大家分享一下,希望对大家的学习有所帮助,不多说了,看具体怎么操作了... 1、总结背景 在linux系统下,下载并安装了应用程序,很有可能在键入它的名称时出现“command not found”的提示内容。每次都到安装目标文件夹内,找到可执行文件来进行操作就太繁琐了。这涉及到环境变量PATH的设置问题,而PATH的设置也是在linux下定制环境变量的一个组成部分。案例基于RedHat AS4讲解环境变量定制的问题。 2、变量简介 Linux是一个多用户的操作系统。每个用户登录系统后,都会有一个专用的运行环境。通常每个用户默认的环境都是相同的,这个默认环境实际上就是一组环境变量的定义。用户可以对自己的运行环境进行定制,其方法就是修改相应的系统环境变量。 3、定制环境变量 环境变量是和Shell紧密相关的,用户登录系统后就启动了一个Shell。对于Linux来说一般是bash,但也可以重新设定或切换到其它的Shell(使用chsh命令)。 根据发行版本的情况,bash有两个基本的系统级配置文件:/etc/bashrc和/etc/profile。这些配置文件包含两组不同的变量:shell变量和环境变量。前者只是在特定的shell中固定(如bash),后者在不同shell中固定。很明显,shell变量是局部的,而环境变量是全局的。环境变量是通过Shell命令来设置的,设置好的环境变量又可以被所有当前用户所运行的程序所使用。对于bash这个Shell程序来说,可以通过变量名来访问相应的环境变量,通过export来设置环境变量。 注:Linux的环境变量名称一般使用大写字母 4、环境变量设置实例 1.使用命令echo显示环境变量 本例使用echo显示常见的变量HOME $ echo $HOME /home/kevin 2.设置一个新的环境变量 $ export MYNAME=”my name is kevin” $ echo $ MYNAME my name is Kevin 3.修改已存在的环境变量 接上个示例 $ MYNAME=”change name to jack” $ echo $MYNAME change name to jack 4.使用env命令显示所有的环境变量 $ env HOSTNAME=localhost.localdomain SHELL=/bin/bash TERM=xterm HISTSIZE=1000 SSH_CLIENT=192.168.136.151 1740 22 QTDIR=/usr/lib/qt-3.1 SSH_TTY=/dev/pts/0 …… 5.使用set命令显示所有本地定义的Shell变量 $ set BASH=/bin/bash BASH_ENV=/root/.bashrc …… 6.使用unset命令来清除环境变量 $ export TEMP_KEVIN=”kevin”     #增加一个环境变量TEMP_KEVIN $ env | grep TEMP_KEVIN          #查看环境变量TEMP_KEVIN是否生效(存在即生效) TEMP_KEVIN=kevin #证明环境变量TEMP_KEVIN已经存在 $ unset TEMP_KEVIN            #删除环境变量TEMP_KEVIN $ env | grep TEMP_KEVIN       #查看环境变量TEMP_KEVIN是否被删除,没有输出显示,证明TEMP_KEVIN被清除了。 7.使用readonly命令设置只读变量 注:如果使用了readonly命令的话,变量就不可以被修改或清除了。 $ export TEMP_KEVIN ="kevin"      #增加一个环境变量TEMP_KEVIN $ readonly TEMP_KEVIN                  #将环境变量TEMP_KEVIN设为只读 $ env | grep TEMP_KEVIN          #查看环境变量TEMP_KEVIN是否生效 TEMP_KEVIN=kevin        #证明环境变量TEMP_KEVIN已经存在 $ unset TEMP_KEVIN          #会提示此变量只读不能被删除 -bash: unset: TEMP_KEVIN: cannot unset: readonly variable $ TEMP_KEVIN ="tom"        #修改变量值为tom会提示此变量只读不能被修改 -bash: TEMP_KEVIN: readonly variable 8.通过修改环境变量定义文件来修改环境变量。 需要注意的是,一般情况下,仅修改普通用户环境变量配置文件,避免修改根用户的环境定义文件,因为那样可能会造成潜在的危险。 $ cd ~                                  #到用户根目录下 $ ls -a                                 #查看所有文件,包含隐藏的文件 $ vi .bash_profile                #修改用户环境变量文件 例如: 编辑你的PATH声明,其格式为: PATH=$PATH::::------: 你可以自己加上指定的路径,中间用冒号隔开。 环境变量更改后,在用户下次登陆时生效。 如果想立刻生效,则可执行下面的语句:$sourc e .bash_profile 需要注意的是,最好不要把当前路径”./”放到PATH里,这样可能会受到意想不到的攻击。 完成后,可以通过$ echo $PATH查看当前的搜索路径。这样定制后,就可以避免频繁的启动位于shell搜索的路径之外的程序了。 5、学习总结 1.Linux的变量种类 按变量的生存周期来划分,Linux变量可分为两类: 1.     永久的:需要修改配置文件,变量永久生效。 2.     临时的:使用export命令行声明即可,变量在关闭shell时失效。 2.设置变量的三种方法 1.     在/etc/profile文件中添加变量【对所有用户生效(永久的)】 用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久的”。 例如:编辑/etc/profile文件,添加CLASSPATH变量 # vi /etc/profile export CLASSPATH=./ Java_HOME/lib;$JAVA_HOME/jre/lib 注:修改文件后要想马上生效还要运行# source /etc/profile不然只能在下次重进此用户时生效。 2.     在用户目录下的.bash_profile文件中增加变量【对单一用户生效(永久的)】 用VI在用户目录下的.bash_profile文件中增加变量,改变量仅会对当前用户有效,并且是“永久的”。 例如:编辑guok用户目录(/home/guok)下的.bash_profile $ vi /home/guok/.bash.profile 添加如下内容: export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib 注:修改文件后要想马上生效还要运行$ source /home/guok/.bash_profile不然只能在下次重进此用户时生效。 3.     直接运行export命令定义变量【只对当前shell(BASH)有效(临时的)】 在shell的命令行下直接使用[export变量名=变量值]定义变量,该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。 Cassandra 文章分类:数据库 Cassandra 下载 http://www.apache.org/dyn/closer.cgi?path=/cassandra/0.5.1/apache-cassandra-0.5.1-bin.tar.gz   apache-cassandra-0.5.1自带的hector-0.5.0-7.jar有严重的性能问题,需要修改成hector-0.5.1-9.jar   资源 http://cassandra.apache.org/ http://wiki.apache.org/cassandra/FrontPage     部署 http://kauu.net/2010/02/27/cassandra%E5%88%9D%E4%BD%93%E9%AA%8C/   192.168.2.79 /home/bmb/apache-cassandra-0.5.1     DataModal设计 l  对同一行的所有列,可以定义根据列名的排序规则(即保存规则)。当保存某个用户相对应的朋友的时候,可以用朋友的加入时间作为一个一个的列名,列按照时间倒序拍。这样很容易获得用户最新的朋友。 测试,Keyspace1的Standard1的列按照BytesType进行排序,不管按照什么set顺序,get_slice都会获得,a,b,c的顺序 set Keyspace1.Standard1['jsmith']['c'] = 'c' set Keyspace1.Standard1['jsmith']['a'] = 'a' set Keyspace1.Standard1['jsmith']['b'] = 'b'   l  Super columns Super columns are a great way to store one-to-many indexes to other records: make the sub column names TimeUUIDs (or whatever you'd like to use to sort the index), and have the values be the foreign key. 不如某个用户的好友,Sub column name是好友加入时间,Sub column value是好友的ID,可以作为外键关联好友的信息表。 l  复合Key可以等效Super Columns,列名为时间 Alternatively, we could preface the status keys with the user key, which has less temporal locality. If we used user_id:status_id as the status key, we could do range queries on the user fragment to get tweets-by-user, avoiding the need for a user_timeline super column. l  In column-orientation, the column names are the data l  列名TimeUUID,列值JSON格式,可以解决一些问题 l      http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/ Twitter怎样使用Cassandra,Twitter的Data Model,Blog的Data Model http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model Digg提供的一个完整例子 http://wiki.apache.org/cassandra/DataModel http://wiki.apache.org/cassandra/CassandraLimitations http://www.hellodba.net/2010/02/cassandra.html (中文翻译,有出入)介绍Twitter的Data Modal,有借鉴意义     修改Schema定义,2次重启 https://issues.apache.org/jira/browse/CASSANDRA-44 动态创建Column Falimy,在不重启服务器下 http://github.com/NZKoz/cassandra_object   启动单个节点的Cluster 安装JDK 6    tar -zxvf cassandra-$VERSION.tgz    cd cassandra-$VERSION    sudo mkdir -p /var/log/cassandra    sudo chown -R `whoami` /var/log/cassandra    sudo mkdir -p /var/lib/cassandra    sudo chown -R `whoami` /var/lib/cassandra 修改/bin/cassandra.in.sh里面的启动端口(-Dcom.sun.management.jmxremote.port=8080) bin/cassandra -f 查看日志 tail -f /var/log/cassandra/system.log 客户端连接 cd /home/bmb/apache-cassandra-0.5.1 bin/cassandra-cli --host 192.168.2.79  --port 9160     cassandra> set Keyspace1.Standard1['jsmith']['first'] = 'John'   Value inserted.   cassandra> set Keyspace1.Standard1['jsmith']['last'] = 'Smith'   Value inserted.   cassandra> set Keyspace1.Standard1['jsmith']['age'] = '42'   Value inserted.   cassandra> get Keyspace1.Standard1['jsmith']     (column=age, value=42; timestamp=1249930062801)     (column=first, value=John; timestamp=1249930053103)     (column=last, value=Smith; timestamp=1249930058345)   Returned 3 rows.   cassandra> Java 客户端 l  原始Thrift http://apache.freelamp.com/incubator/thrift/0.2.0-incubating/thrift-0.2.0-incubating.tar.gz 封装 http://github.com/charliem/OCM   手动编译Java  Thrift cd D:\7g\Personal\Resources\Architecture\Cassandra\thrift-0.2.0\lib\java ant   l  hector http://prettyprint.me/2010/02/23/hector-a-java-cassandra-client/ http://github.com/rantav/hector/downloads   l  OCM http://github.com/charliem/OCM/downloads       Git 下载Git http://kernel.org/pub/software/scm/git/git-1.7.0.3.tar.gz 安装 cd /home/bmb/apache-cassandra-0.5.1/git-1.7.0.3 ./configure make make install   Git客户端 http://msysgit.googlecode.com/files/msysGit-fullinstall-1.7.0.2-preview20100309.exe D:\7g\Personal\Resources\Architecture\Cassandra\msysgit\msysgit\ git-cmd.bat Check out OCM git clone http://github.com/charliem/OCM.git     http://tortoisegit.googlecode.com/files/TortoiseGit-1.3.6.0-32bit.msi       集群配置 http://pan-java.javaeye.com/blog/604672   192.168.5.11 /u/iic/bmb/apache-cassandra-0.5.1 修改conf下面的文件 /var/log/cassandra成/u/iic/bmb/apache-cassandra-0.5.1/log /var/lib/cassandra成/u/iic/bmb/apache-cassandra-0.5.1/log 修改bin/cassandra的Java_home export JAVA_HOME=/u/iic/bmb/jdk6     192.168.5.12 (目录配置同5.11,都以2.79为Seed) 注意:部署集群的时候,不能把5.11整个目录搬到5.12上,不然他们Token一样,会导致Ring路5.11和5.12重复。解决方法:删除data和commit目录。 还有所有的IP必须配置成绝对IP,如果配Localhost,会使Ring不完整   192.168.2.79 /home/bmb/apache-cassandra-0.5.1   bin/cassandra -f   OCM的使用 l  定义数据结构:D:\7g\Personal\Resources\Architecture\Cassandra\Client\OCM Compiler\OCMSpecSample.txt l  通过com.kissintellignetsystems.ocm.compiler.Compiler类,提供以下的命令行参数,生成Java对象:"OCMSpecSample.txt", "keyspace1", "Java",                 "mynamespace", "output/" l  测试例子:D:\7g\Personal\Resources\Architecture\Cassandra\Client\Output Languages\Java\TestHarness CreatTest.java     get keyspace1.Users['charlie'] bin/cassandra-cli --host 192.168.2.79  --port 9160 bin/cassandra-cli --host 192.168.5.11  --port 9160 bin/cassandra-cli --host 192.168.5.12  --port 9160         查看集群的节点信息 bin/nodeprobe -host localhost -port 8090 ring   Hadoop & Cassandra using Hadoop to Cassandra through Binary Memtable http://github.com/lenn0x/Cassandra-Hadoop-BMT/blob/master/src/java/org/digg/CassandraBulkLoader.java   http://blog.csdn.net/wdwbw/archive/2010/03/10/5366739.aspx http://www.roadtofailure.com/2009/10/29/hbase-vs-cassandra-nosql-battle/ Cassandra是一个开源的分布式数据库,结合了Dynamo的Key/Value与Bigtable的面向列的特点。 Cassandra的特点如下: 1.灵活的schema:不需要象数据库一样预先设计schema,增加或者删除字段非常方便(on the fly)。 2.支持range查询:可以对Key进行范围查询。 3.高可用,可扩展:单点故障不影响集群服务,可线性扩展。 我们可以将Cassandra的数据模型想象成一个四维或者五维的Hash。 Column Column是Cassandra中最小的数据单元。它是一个3元的数据类型,包含:name,value和timestamp。 将一个Column用JSON的形式表现出来如下: { // 这是一个column 2: name: "逖靖寒的世界", 3: value: "gpcuster@gmali.com", 4: timestamp: 123456789 5: } 为了简单起见,我们可以忽略timestamp。就把column想象成一个name/value即可。 注意,这里提到的name和value都是byte[]类型的,长度不限。 SuperColumn 我们可以将SuperColumn想象成Column的数组,它包含一个name,以及一系列相应的Column。 将一个SuperColumn用JSON的形式表现如下: 1: { // 这是一个SuperColumn 2: name: "逖靖寒的世界", 3: // 包含一系列的Columns 4: value: { 5: street: {name: "street", value: "1234 x street", timestamp: 123456789}, 6: city: {name: "city", value: "san francisco", timestamp: 123456789}, 7: zip: {name: "zip", value: "94107", timestamp: 123456789}, 8: } 9: } Columns和SuperColumns都是name与value的组合。最大的不同在于Column的value是一个“string”,而SuperColumn的value是Columns的Map。 还有一点需要注意的是:SuperColumn’本身是不包含timestamp的。 ColumnFamily ColumnFamily是一个包含了许多Row的结构,你可以将它想象成RDBMS中的Table。 每一个Row都包含有client提供的Key以及和该Key关联的一系列Column。 我们可以看看结构: 1: UserProfile = { // 这是一个ColumnFamily 2: phatduckk: { // 这是对应ColumnFamily的key 3: // 这是Key下对应的Column 4: username: "gpcuster", 5: email: "gpcuster@gmail.com", 6: phone: "6666" 7: }, // 第一个row结束 8: ieure: { // 这是ColumnFamily的另一个key 9: //这是另一个Key对应的column 10: username: "pengguo", 11: email: "pengguo@live.com", 12: phone: "888" 13: age: "66" 14: }, 15: } ColumnFamily的类型可以为Standard,也可以是Super类型。 我们刚刚看到的那个例子是一个Standard类型的ColumnFamily。Standard类型的ColumnFamily包含了一系列的Columns(不是SuperColumn)。 Super类型的ColumnFamily包含了一系列的SuperColumn,但是并不能像SuperColumn那样包含一系列Standard ColumnFamily。 这是一个简单的例子: 1: AddressBook = { // 这是一个Super类型的ColumnFamily 2: phatduckk: { // key 3: friend1: {street: "8th street", zip: "90210", city: "Beverley Hills", state: "CA"}, 4: John: {street: "Howard street", zip: "94404", city: "FC", state: "CA"}, 5: Kim: {street: "X street", zip: "87876", city: "Balls", state: "VA"}, 6: Tod: {street: "Jerry street", zip: "54556", city: "Cartoon", state: "CO"}, 7: Bob: {street: "Q Blvd", zip: "24252", city: "Nowhere", state: "MN"}, 8: ... 9: }, // row结束 10: ieure: { // key 11: joey: {street: "A ave", zip: "55485", city: "Hell", state: "NV"}, 12: William: {street: "Armpit Dr", zip: "93301", city: "Bakersfield", state: "CA"}, 13: }, 14: } Keyspace Keyspace是我们的数据最外层,你所有的ColumnFamily都属于某一个Keyspace。一般来说,我们的一个程序应用只会有一个Keyspace。 简单测试 我们将Cassandra运行起来以后,启动命令行,执行如下操作: cassandra> set Keyspace1.Standard1['jsmith']['first'] = 'John' Value inserted. cassandra> set Keyspace1.Standard1['jsmith']['last'] = 'Smith' Value inserted. cassandra> set Keyspace1.Standard1['jsmith']['age'] = '42' Value inserted. 这个时候,Cassandra中就已经有3条数据了。 其中插入数据的各个字段含义如下: 接下来,我们执行查询操作: cassandra> get Keyspace1.Standard1['jsmith']   (column=age, value=42; timestamp=1249930062801)   (column=first, value=John; timestamp=1249930053103)   (column=last, value=Smith; timestamp=1249930058345) Returned 3 rows. 这样,我们就可以将之前插入的数据查询出来了。 排序 有一点需要明确,我们使用Cassandra的时候,数据在写入的时候就已经排好顺序了。 在某一个Key内的所有Column都是按照它的Name来排序的。我们可以在storage-conf.xml文件中指定排序的类型。 目前Cassandra提供的排序类型有:BytesType, UTF8Type,LexicalUUIDType, TimeUUIDType, AsciiType,和LongType。 现在假设你的原始数据如下: {name: 123, value: "hello there"}, {name: 832416, value: "kjjkbcjkcbbd"}, {name: 3, value: "101010101010"}, {name: 976, value: "kjjkbcjkcbbd"} 当我们storage-conf.xml文件中指定排序的类型为LongType时: 排序后的数据就是这样的: {name: 3, value: "101010101010"},   {name: 123, value: "hello there"}, {name: 976, value: "kjjkbcjkcbbd"}, {name: 832416, value: "kjjkbcjkcbbd"} 如果我们指定排序的类型为UTF8Type 排序后的数据就是这样的: {name: 123, value: "hello there"},    {name: 3, value: "101010101010"}, {name: 832416, value: "kjjkbcjkcbbd"}, {name: 976, value: "kjjkbcjkcbbd"} 大家可以看到,指定的排序类型不一样,排序的结果也是完全不同的。 对于SuperColumn,我们有一个额外的排序维度,所以我们可以指定CompareSubcolumnsWith来进行另一个维度的排序类型。 假设我们的原始数据如下: { // first SuperColumn from a Row     name: "workAddress",     // and the columns within it     value: {         street: {name: "street", value: "1234 x street"},         city: {name: "city", value: "san francisco"},         zip: {name: "zip", value: "94107"}     } }, { // another SuperColumn from same Row     name: "homeAddress",     // and the columns within it     value: {         street: {name: "street", value: "1234 x street"},         city: {name: "city", value: "san francisco"},         zip: {name: "zip", value: "94107"}     } } 然后我们定义CompareSubcolumnsWith和CompareWith的排序类型都是UTF8Type,那么排序后的结果为: {     // this one's first b/c when treated as UTF8 strings     { // another SuperColumn from same Row         // This Row comes first b/c "homeAddress" is before "workAddress"                    name: "homeAddress",         // the columns within this SC are also sorted by their names too         value: {             // see, these are sorted by Column name too             city: {name: "city", value: "san francisco"},                            street: {name: "street", value: "1234 x street"},             zip: {name: "zip", value: "94107"}         }     },            name: "workAddress",     value: {         // the columns within this SC are also sorted by their names too         city: {name: "city", value: "san francisco"},                    street: {name: "street", value: "1234 x street"},         zip: {name: "zip", value: "94107"}     } } 再额外提一句,Cassandra的排序功能是允许我们自己实现的,只要你继承org.apache.cassandra.db.marshal.IType就可以了。 参考文档 WTF is a SuperColumn? An Intro to the Cassandra Data Model DataModel

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ]
2 人已下载

下载文档

相关文档