Cassandra是一套分布式数据库,设计思想比较接近Big Table和Amazon Dynamo。从08年开源到现在,经历了Digg的悲剧,Twitter的调教,最新版本1.1版,已经开始进入平稳发展期了。我们现在有很多结构简单但读写频繁的数据,基于性能(跑分王)扩展性(多Cluster)等方面的考虑,用Cassandra搭了一个ring,目前为止运作正常。本文介绍在Ubuntu中安装Cassandra,用两台服务器做为两个节点搭建出一个ring,最后用pycassa把MySQL中的数据导入Cassandra。
Install
在Ubuntu中用官方提供的Debian源安装,版本是1.1.4,进行以下操作前建议先切换到root帐号。
在/etc/apt/source.list中增加cassandra的源:
deb-src http://www.apache.org/dist/cassandra/debian 11x main
增加相关的PUBLIK_KEY:
gpg –export –armor F758CE318D77295D | apt-key add –
gpg –keyserver pgp.mit.edu –recv-keys 2B5C1B00
gpg –export –armor 2B5C1B00 | apt-key add –
打印出OK说明key添加成功,执行apt-get update更新列表,更新完成后从源进行安装
apt-get install cassandra
/etc/init.d/cassandra start
/etc/init.d/cassandra status
* Cassandra is running
可能会输出一些提示: -XX:+HeapDumpOnOutOfMemoryError -Xss128 ,不会影响使用.如果启动失败,在/var/log/cassandra/output.log 有相关日志。64位的Ubuntu系统会找不到 /usr/lib/libcap.so ,建立一个软链,把/lib/x86_64-linux-gnu/libcap.so.* 链到/usr/lib。
如果安装前系统中没有java,apt安装时会安装openjdk。如果安装了sun-java6-jdk,会自动使用sun的java。
Configure
现在已经在192.168.1.1, 192.168.1.2上部署了Canssandra,都是用源安装,配置文件位于/etc/cassandra,编辑cassandra.yaml,有4处修改(左侧数字是行号):
180 – seeds: “192.168.1.1,192.168.1.2”
271 listen_address: 192.168.1.1
271 rpc_address: 192.168.1.1
seeds设置种子节点地址,以逗号分割。rpc_address只用于客户端到节点的直接连接,默认的cassandra-cli是thrift方式,也可以用avro操作。配置完成后重启cassandra,用nodetool检测是否已经成功建立了ring:
Address DC Rack Status State Load Effective-Ownership Token
192.168.1.1 datacenter1 rack1 Up Normal 43.92 KB 100.00%
192.168.1.2 datacenter1 rack1 Up Normal 66.24 KB 100.00%
Keyspace
组建ring就是为了提升服务的稳定性,如果一个节点故障,服务本身也不受影响。Cassandra创建Keyspace时可以指定副本因子(replication_factor)数,这个值决定了数据在整个集群中存放多少个副本,所以副本因子至少得是2才能保证稳定性。如果是1,数据只存在一个节点上,如果这个节点掉线整个服务就中断了。副本因子数会影响性能,而且不能超过集群中的节点数。比如有10个节点,副本因子数就不能设置成11,也最好不要设置成10,这会导致性能急剧下降。
在某个节点上运行cassandra-cli,添加一个副本因子数为2的keyspace,之前修改了listen/rpc的地址,所以要指定host:
[default@unknown] create keyspace KEYSPACE名字 with placement_strategy = ‘org.apache.cassandra.locator.SimpleStrategy’ and strategy_options = {replication_factor:2};
Pycassa
建议先部署Cassandra-Cluster-Admin(PHP),可以很方便的查看Cassandra中的数据。
现在MySQL里有一张new_users表,主键是uid,导入Cassandra时,将uid作为key,其他字段以key-value的形式写入:
# -*- coding: utf-8 -*-
from pycassa.pool import ConnectionPool
from pycassa.columnfamily import ColumnFamily
from pycassa.cassandra.ttypes import NotFoundException, ConsistencyLevel
import MySQLdb
import sys
import datetime
reload(sys)
sys.setdefaultencoding('utf-8')
class MysqlImport():
def __init__(self):
self.conn = MySQLdb.connect(host="MYSQL数据库地址",user="MYSQL用户名",passwd="密码",db="数据库名",charset="utf8")
self.pool = ConnectionPool(keyspace='dmyz', server_list=['192.168.1.1:9160', '192.168.1.2:9160'], prefill=False)
self.columnfamily = ''
def table(self, table_name):
self.columnfamily = ColumnFamily(self.pool, 'NewUsers')
cursor = self.conn.cursor(MySQLdb.cursors.DictCursor)
statement = cursor.execute('SELECT * FROM %s' % table_name)
result = cursor.fetchallDict()
for user in result:
self.insert(user)
def insert(self, data):
user = {}
for key in data.keys():
if key != 'uid' : user[key] = unicode(data[key])
self.columnfamily.insert(str(data['uid']), user)
if __name__ == '__main__':
c = MysqlImport()
c.table('new_users')
解释一下ConsistencyLevel。这是Cassandra的一致性级别,默认是ONE,当数据写入任意一个节点的的commit log时,写入命令被视为执行成功。本例中设置的是ANY,就是说不管数据有没有真正写入,都视为成功。0.7版还有ZERO这种级别,现在已经被取消了。其他可选的一致性级别参考官方文档:http://wiki.apache.org/cassandra/API。在只有两个正常运作的节点时,使用ANY或是ONE,写入速度并没有明显的提升。