使用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

广告
将在 10 秒后关闭
bannerAds