嘉宾帖子提醒!Marla和Ali与Cockroach Labs团队合作,让ActiveRecord CockroachDB适配器为Rails 5.2及以后的版本做好准备!他们与Cockroach Labs的合作已经结束,但适配器仍然存在。他们与Cockroach Labs的合作已经结束,但这个适配器却一直存在。这篇博文最初是在他们的博客Test Double.上分享的。
当我在Rails应用中工作时,我发现自己并不太担心数据库的问题。由于Rails原生支持MySQL和PostgreSQL等流行的数据库,我通常只需要做一些配置上的改变,就可以让应用程序的数据库启动和运行。我也没有发现自己在使用Rails不支持的数据库时遇到太多问题。由于Rails有良好的数据库接口文档和强大的社区支持,我仍然只需要做一些配置修改就可以使用Oracle和SQL Server等数据库。
如果你同意我的观点,那么在Rails中使用CockroachDB也就不足为奇了!🎉
什么是CockroachDB?
很高兴你问到了!CockroachDB是由Cockroach Labs建立的,是一个被设计为可扩展和高度可用的数据库。它还使用了PostgreSQL的线程协议,所以你几乎可以在任何你可以使用PostgreSQL的地方使用它。几乎是这样(后面会有更多的介绍)。
那么我们如何在Rails中使用CockroachDB呢?因为我喜欢通过实例来学习,所以让我们配置一个现有的Rails应用来使用CockroachDB。
在Rails中使用CockroachDB
在这个例子中,我们将改变CodeTriage Rails应用,使其使用CockroachDB而不是PostgreSQL。
在按照CodeTriage的贡献指南让应用在本地运行后,该应用就可以与PostgreSQL对话了。
要切换到使用CockroachDB,我们首先需要安装和配置CockroachDB。
如何安装CockroachDB?
首先,按照安装指南安装CockroachDB。接下来,我们将使用cockroach demo命令来创建一个单节点的CockroachDB集群。我们将使用--empty 标志运行该命令,这样我们就不会在以后加载CodeTriage模式时遇到任何冲突。
$ cockroach demo --empty
#
# Welcome to the CockroachDB demo database!
#
# You are connected to a temporary, in-memory CockroachDB cluster of 1 node.
#
# This demo session will attempt to enable enterprise features
# by acquiring a temporary license from Cockroach Labs in the background.
# To disable this behavior, set the environment variable
# COCKROACH_SKIP_ENABLING_DIAGNOSTIC_REPORTING=true.
#
# Reminder: your changes to data stored in the demo session will not be saved!
#
# Connection parameters:
# (console) http://127.0.0.1:63115
# (sql) postgres://root:admin@?host=%2Fvar%2Ffolders%2Fzj%2F41x2d76s4kq4vv8_c8qrl1z00000gn%2FT%2Fdemo900101820&port=26257
# (sql/tcp) postgres://root:admin@127.0.0.1:63117?sslmode=require
#
#
# The user "root" with password "admin" has been created. Use it to access the Web UI!
#
# Server version: CockroachDB CCL v20.2.5 (x86_64-apple-darwin14, built 2021/02/16 12:57:34, go1.13.14) (same version as client)
# Cluster ID: 83ec1cc1-4b7a-410f-b0b4-dea5ea562b9b
#
# Enter \? for a brief introduction.
#
root@127.0.0.1:63117/defaultdb>
在cockroach demo 命令创建了空的数据库之后,它打开了一个交互式SQL shell。当shell打开时,演示数据库只存在于内存中,所以我们将保持它的开放,直到我们完成。
cockroach demo 命令也给了我们一些关于如何连接它的信息。
# Connection parameters:
# (console) http://127.0.0.1:63115
# (sql) postgres://root:admin@?host=%2Fvar%2Ffolders%2Fzj%2F41x2d76s4kq4vv8_c8qrl1z00000gn%2FT%2Fdemo900101820&port=26257
# (sql/tcp) postgres://root:admin@127.0.0.1:63117?sslmode=require
从这些信息中我们可以看到
- 我们有一个名为
root的用户,他的密码是admin - CockroachDB服务器正在监听
127.0.0.1(又名localhost),端口为63117 - 而
sslmode被设置为require
当你运行cockroach demo 命令时,这些细节大多是相同的,但端口可能不同。
请注意这些连接细节,因为我们以后会需要它们。
现在CockroachDB已经在本地启动并运行,我们准备对CodeTriage进行一些配置上的修改。
添加ActiveRecord CockroachDB适配器
首先,我们要编辑Gemfile ,用ActiveRecord CockroachDB Adapter gem替换pg gem。由于CodeTriage目前是针对Rails 6.1运行的,我们将安装ActiveRecord CockroachDB Adapter的v6.1.0.beta1版本。
--- a/Gemfile
+++ b/Gemfile
@@ -31,7 +31,7 @@ gem 'local_time', '2.1.0'
gem 'maildown', '~> 3.1'
gem 'omniauth', '~> 1.9.1'
gem 'omniauth-github'
-gem 'pg'
+gem 'activerecord-cockroachdb-adapter', '6.1.0beta1'
gem 'puma'
gem 'rack-timeout'
gem 'rrrretry'
然后,在用bundle install 安装 gem 后,我们将对config/database.yml 进行一些修改。
配置CodeTriage以使用ActiveRecord CockroachDB适配器
首先,我们将把adapter 的值从postgresql 改为cockroachdb 。
--- a/config/database.yml
+++ b/config/database.yml
@@ -1,5 +1,5 @@
defaults: &defaults
- adapter: postgresql
+ adapter: cockroachdb
encoding: utf8
pool: 5
host: localhost
接下来,我们将从CockroachDB的交互式SQL shell中获取我们前面提到的连接细节
- 我们有一个名为
root的用户,他的密码是admin- CockroachDB服务器正在监听
127.0.0.1(又名localhost),端口为63117- 并且
sslmode被设置为require
并设置port,user,password, 和requiressl 。
--- a/config/database.yml
+++ b/config/database.yml
@@ -3,7 +3,10 @@ defaults: &defaults
encoding: utf8
pool: 5
host: localhost
- password:
+ port: 63117
+ user: root
+ password: admin
+ requiressl: true
现在CodeTriage应该可以使用CockroachDB了!让我们通过运行bin/rake db:create db:schema:load db:seed 来设置数据库。
$ bin/rake db:create db:schema:load db:seed
Created database 'triage_development'
Created database 'triage_test'
rake aborted!
ActiveRecord::StatementInvalid: PG::FeatureNotSupported: ERROR: unimplemented: extension "pg_stat_statements" is not yet supported
HINT: You have attempted to use a feature that is not yet implemented.
See: https://go.crdb.dev/issue-v/54516/v20.2
/Users/alimi/.rvm/gems/ruby-2.7.2/gems/activerecord-6.1.0/lib/active_record/connection_adapters/postgresql_adapter.rb:678:in `exec_params'
/Users/alimi/.rvm/gems/ruby-2.7.2/gems/activerecord-6.1.0/lib/active_record/connection_adapters/postgresql_adapter.rb:678:in `block (2 levels) in exec_no_cache'
/Users/alimi/.rvm/gems/ruby-2.7.2/gems/activesupport-6.1.0/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
呃......这看起来不妙。😅
CockroachDB听起来像PostgreSQL,但它不是PostgreSQL
如果我们再看一下最后一条命令/错误,我们可以看到CodeTriage数据库是在CockroachDB中创建的。
$ bin/rake db:create db:schema:load db:seed
Created database 'triage_development'
Created database 'triage_test'
但是当试图从db/schema.rb 中加载数据库模式时,事情就出错了。
rake aborted!
ActiveRecord::StatementInvalid: PG::FeatureNotSupported: ERROR: unimplemented: extension "pg_stat_statements" is not yet supported
HINT: You have attempted to use a feature that is not yet implemented.
See: https://go.crdb.dev/issue-v/54516/v20.2
在db/schema.rb ,CodeTriage正在启用pg_stat_statements 扩展,但正如错误告诉我们的那样,CockroachDB不支持它。
尽管CockroachDB使用了PostgreSQL的线程协议,并且行为上很像PostgreSQL,但是记住CockroachDB不是PostgreSQL是非常重要的。你可以在很多地方像使用PostgreSQL一样使用CockroachDB,这意味着你不必为使用它而学习大量的新东西。但是你可能会遇到像这样的行为上的小差异。
为了演示,我们将改变CodeTriage的db/schema.rb ,使其不再启用pg_stat_statments 扩展(也不启用plpgsql 扩展)。
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -12,9 +12,6 @@
ActiveRecord::Schema.define(version: 2020_11_15_123025) do
- # These are extensions that must be enabled in order to support this database
- enable_extension "pg_stat_statements"
- enable_extension "plpgsql"
create_table "data_dumps", id: :serial, force: :cascade do |t|
t.text "data"
现在,让我们再次尝试加载模式和种子。
$ bin/rake db:schema:load db:seed
success
....................................................................................................%
好的,这看起来好多了。但我们真的可以不使用这些扩展吗?
CodeTriage会在它期望PostgreSQL扩展被安装和可用的地方出错。我们在这里不需要担心这个问题,因为这只是一篇博文,但如果我正在改变一个生产数据库,这将使我感到不安。如果这是一次真正的迁移,我会查看兼容性文档并更新应用程序,使其不再依赖PostgreSQL的功能。
现在我们已经完成了配置的修改,并设置了数据库,我们应该可以从CodeTriage中与CockroachDB对话了。🕺🏾
从CodeTriage连接到CockroachDB数据库
让我们启动一个rails console ,获取一些数据吧!由于我们之前运行了bin/rake db:seed ,我们的数据库应该有一些种子数据。
$ bin/rails console
Loading development environment (Rails 6.1.0)
>> User.count
(67.7ms) SELECT COUNT(*) FROM "users"
=> 101
好的,我们有101个用户。让我们试着获取第一个用户。
>> User.first
User Load (2.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
TRANSACTION (0.9ms) BEGIN
User Update (3.9ms) UPDATE "users" SET "updated_at" = $1, "account_delete_token" = $2 WHERE "users"."id" = $3 [["updated_at", "2021-03-04 01:00:45.821404"], ["account_delete_token", "874464f621a5930c859c5b99b9d1d26705386d61bd34caf00b1288e949dec48dc257459c6fcb297da12ef32dd16419ff64bc7289d94425a94c46fd94ffb89ce9"], ["id", 637885482494296065]]
TRANSACTION (22.5ms) COMMIT
=> #<User id: 637885482494296065, email: "", created_at: "2021-03-03 02:13:20.466321000 +0000", updated_at: "2021-03-04 01:00:45.821404000 +0000", zip: nil, phone_number: nil, twitter: nil, github: "schneems", github_access_token: nil, admin: nil, avatar_url: "http://gravatar.com/avatar/default", name: nil, private: false, favorite_languages: nil, daily_issue_limit: 50, skip_issues_with_pr: false, account_delete_token: "874464f621a5930c859c5b99b9d1d26705386d61bd34caf00b...", last_clicked_at: "2021-03-03 02:13:20.466267000 +0000", email_frequency: "daily", email_time_of_day: nil, old_token: nil, raw_streak_count: 0, raw_emails_since_click: 0, last_email_at: nil>
它成功了!🙌🏾
你可能注意到这个用户有一个非常大的ID。CodeTriage为用户表指定了一个Serial id,所以你可能希望我们的第一个用户的id是1。 CockroachDB识别Serial,但它不是从1开始依次分配用户id,而是根据交易时间戳和节点的id来分配。CockroachDB这样做是为了确保全局唯一的ID在各节点之间以一种高性能的方式被使用。如果你忘记了,CockroachDB和PostgreSQL是不一样的。
我还可以通过运行bin/rails server ,并观察服务器的输出,看到ActiveRecord向CockroachDB进行了一些查询。
$ bin/rails s
=> Booting Puma
=> Rails 6.1.0 application starting in development
…
Started GET "/" for 127.0.0.1 at 2021-03-03 20:25:52 -0500
(0.7ms) SHOW crdb_version
(3.5ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by PagesController#index as HTML
(1.8ms) SELECT COUNT(*) FROM "users"
↳ app/controllers/pages_controller.rb:59:in `block in description'
(1.1ms) SELECT COUNT(*) FROM "repos"
↳ app/controllers/pages_controller.rb:60:in `block in description'
…
↳ app/views/pages/_repos_with_pagination.html.slim:1
Repo Load (2.7ms) SELECT "repos"."id", "repos"."updated_at", "repos"."issues_count", "repos"."language", "repos"."full_name", "repos"."name", "repos"."description" FROM "repos" WHERE (issues_count > 0) ORDER BY issues_count DESC LIMIT $1 OFFSET $2 [["LIMIT", 50], ["OFFSET", 0]]
…
Completed 200 OK in 661ms (Views: 387.9ms | ActiveRecord: 226.8ms | Allocations: 117408)
这些查询是有效的!而应用程序也在加载!!!。
今天就在Rails中使用CockroachDB
感谢ActiveRecord CockroachDB适配器,我们可以像其他数据库一样在Rails应用中使用CockroachDB。由于CockroachDB与PostgreSQL的对话和行为非常相似,它几乎可以取代PostgreSQL(几乎是😉)。
今天就试试在你的Rails应用中使用CockroachDB吧!
Humblebrag:Marla和我与Cockroach Labs合作,让ActiveRecord CockroachDB适配器为Rails 5.2及以后的版本做好准备,这让我们感到非常开心。我们与Cockroach Labs的合作已经结束了,但这个适配器还在继续。在GitHub上关注Cockroach Labs的进展。