使用Cassandra作为Rails后端
Cassandra是什么?
Cassandra 是一个分布式键值存储系统,由 Facebook 在2008年开源。它是由 Amazon Dynamo 的其中一位创作者 Avinash Lakshman 和 Facebook 的工程师 Prashant Malik 设计的。
Cassandra 能夠在商業硬體和雲端基礎架構上提供高可用性、線性擴展性和容錯能力。
-
- ノードに障害が発生してもサービスを提供し続けることができ、
-
- ノードを追加することで線形に性能が向上し、
- 通信障害などによってメッセージが損失しても継続してサービスを提供する
在分散计算中,有一个著名的定理叫做CAP定理,重点提及了AP。
Apache Cassandra is a powerful database management system that provides high availability and scalability for handling large amounts of data. To learn more about Apache Cassandra, visit their official website at http://cassandra.apache.org/.
列向的方法的优点和缺点
在以MySQL为代表的面向行的数据库中,适合处理由少数行组成的多列数据,但不适合对大量行进行对少数列的更改等操作。而列向数据库则具有相反的特性。
只需要一个选项。
比如说,如果要处理大量的服务器日志等数据,但实际上只使用2到3列的情况下,理论上可以说列向数据库更优秀。
相反,在处理服务器日志的情况下,如果需要同时使用多列的结果,列向数据库可能不是最佳选择(然而,对于时间序列数据来说,关系型数据库也不是特别擅长的领域)。
使用Cassandra的Rails
好的,我们来亲自尝试从Rails使用Cassandra。
这次我们将在MacBook上建立一个由1个节点组成的Cassandra集群并进行使用。
Cassandra 可以从 Apache Cassandra 官网下载,但对于 Mac 用户来说,只需通过 Homebrew 执行以下命令即可进行安装,因此我们将使用这种方式进行安装。
$ brew install cassandra
当安装完成后,输入以下命令,即可使Cassandra在前台运行。
如需在守护进程模式下启动,请删除-f选项。
$ cassandra -f
当以前台方式启动时,终端会占用整个屏幕。因此,请在新的终端中打开或使用tmux等方法在另一个窗口中进行启动。
接下来,我们将使用Rails创建一个新的应用程序。在这个过程中,我们将跳过使用ActiveRecord。
$ rails new CassandraRails --skip-active-record
为了使用类似于ActiveRecord的接口来操作Cassandra,您可以将cequel添加到Gemfile中。
gem 'cequel'
然后,按照惯例执行 bundle install 命令,安装所需的 gem。应该会安装 cequel 和 cassandra-driver。
完成安装后,进行设置操作。
$ rails g cequel:configuration
通过这个操作,将创建一个config/cequel.yml文件。
其内容大致是关于Cassandra集群的信息。
这次我们先在本地主机上搭建一个只有一个节点的Cassandra集群,作为开发环境,所以可以使用默认设置。
最后,我们将在Cassandra上创建一个keyspace。这类似于关系型数据库中的DB。
$ rake cequel:keyspace:create
这样设置就完成了。我们试着创建一个存储推文信息的Tweet模型。
class Tweet
include Cequel::Record
key :id, :text
column :username, :text
column :body, :text
column :retweeted, :int
column :favarited, :int
end
由于不会自动创建主键,所以需要明确指定。在这里,我们指定了键:id和text,并且假设tweet_id作为自然主键来创建。虽然本次未使用,但似乎可以使用belongs_to/has_many等。顺便提一下,在用于Cassandra的查询语言CQL中,有一个CQL数据类型的清单可供使用。要在cequel中使用集合类型(list,set,map),可以在模型中如下描述。
class Tweet
include Cequel::Record
(中略)
set :reply_to, :text
end
当模型描述完成后,执行迁移操作。
$ rake cequel:migrate
Synchronized schema for Tweet
进行迁移操作时,不会添加迁移文件。
我們已經準備好從Rails使用Cassandra了,現在讓我們嘗試從rails console輸入數據。
$ rails c
Loading development environment (Rails 4.2.1)
irb(main):001:0> t = Tweet.new(id: 't123')
=> #<Tweet id: "t123", username: nil, body: nil, retweeted: nil, favarited: nil, reply_to: #<Set: {}>>
irb(main):002:0> t.username = '_c_hase'
=> "_c_hase"
irb(main):003:0> t.reply_to << 't122'
=> #<Set: {"t122"}>
irb(main):004:0> t.save
=> true
以类似使用 ActiveRecord 的方式,我们可以访问 Cassandra(为了易读性,这里加了换行符)。
find 方法可以对模型中指定的键执行操作。
> t = Tweet.find('t123')
=> #<Tweet id: "t123", body: nil, favarited: nil, reply_to: #<Set: {"t122"}>, retweeted: nil, username: "_c_hase">
> t.username
=> "_c_hase"
然而,当尝试使用where方法进行筛选时,会触发ArgumentError错误,类似于RDB。
> Tweet.where(username: '_c_hase')
ArgumentError: Can't scope by non-indexed column username
如果您想根据特定列进行筛选,就需要根据错误代码创建索引。
$ git diff
diff --git a/app/models/tweet.rb b/app/models/tweet.rb
index 80d2400..be18e40 100644
--- a/app/models/tweet.rb
+++ b/app/models/tweet.rb
@@ -2,7 +2,7 @@ class Tweet
include Cequel::Record
key :id, :text
- column :username, :text
+ column :username, :text, :index => true
column :body, :text
column :retweeted, :int
column :favarited, :int
请在执行迁移时注意,会自动贴上索引,所以请务必执行 $ rake cequel:migrate。
> Tweet.where(username: '_c_hase')
=> [#<Tweet id: "t123", body: nil, favarited: nil, reply_to: #<Set: {"t122"}>, retweeted: nil, username: "_c_hase">]
总结
通过使用cequel, 我们确认可以像使用ActiveRecord一样操作Cassandra。尽管它仍然处于发展中的状态,但在处理时间序列数据等方面非常方便,建议考虑一下是否使用它。
下次会通知
我希望能从更理论的角度对Cassandra进行实验和探讨。
我认为这篇主要是关于Cassandra的文章,附带一点关于在Rails上使用的内容。
附录
由于本样例项目将来还会进行扩充,所以代码已经上传到了github(提交号为2b93f1211ace3ffde4c0217a32b4d2a29ba6dcda)。
https://github.com/chase0213/CassandraRailsSample