Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - yoshuki/multi_db: Connection proxy for ActiveRecord for single master / multiple slave database deployments · GitHub
Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - yoshuki/multi_db: Connection proxy for ActiveRecord for single master / multiple slave database deployments · GitHub
Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - yoshuki/multi_db: Connection proxy for ActiveRecord for single master / multiple slave database deployments · GitHub
Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - yoshuki/multi_db: Connection proxy for ActiveRecord for single master / multiple slave database deployments · GitHub
Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - yoshuki/multi_db: Connection proxy for ActiveRecord for single master / multiple slave database deployments · GitHub
Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - yoshuki/multi_db: Connection proxy for ActiveRecord for single master / multiple slave database deployments · GitHub
Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - yoshuki/multi_db: Connection proxy for ActiveRecord for single master / multiple slave database deployments · GitHub
Skip to content

Latest commit

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

multi_db uses a connection proxy, which sends read queries to slave databases, and all write queries to the master database (Read/Write Split). Within transactions, while executing ActiveRecord Observers and within “with_master” blocks (see below), even read queries are sent to the master database.

  • As of this version, ActiveRecord::Base.connection does not return the connection proxy by default anymore (therefore the jump to 0.2.0). Only models inheriting from AR::B return the proxy, unless they are defined as master_models (see below). If you want to access the connection proxy from AR::B directly, use ActiveRecord::Base.connection_proxy.

  • This version is the first attempt for thread-safety of this gem. There might still be some threading issues left!. So please test your apps thoroughly and report any issues you might encounter.

  • CGI::Session::ActiveRecordStore::Session is now automatically registered as a master model.

  • works only with activerecord 2.1, 2.2 and 2.3

gem sources --add http://gems.github.com # only if you haven't already added github
gem install schoefmax-multi_db

When using Rails, add this to your environment.rb:

config.gem'schoefmax-multi_db', :lib=>'multi_db', :source=>'http://gems.github.com'

In your database.yml, add sections for the slaves, e.g.:

production: # that would be the master
adapter: mysql
database: myapp_production
username: root
password: host: localhost
production_slave_database: # that would be a slave adapter: mysql
database: myapp_production
username: root
password: host: 10.0.0.2
production_slave_database_2: # another slave
...
production_slave_database_in_india: # yet another one
...

NOTE: multi_db identifies slave databases by looking for entries of the form “<environment>_slave_database<_optional_name>”. As a (useless) side effect you get abstract classes named MultiDb::SlaveDatabaseInIndia etc. The advantage of specifying the slaves explicitly, instead of the master, is that you can use the same configuration file for scripts that don’t use multi_db. Also, when you decide to disable multi_db for some reason, you don’t have to swap hosts in your database.yml from master to slave (which is easy to forget…).

To enable the proxy globally, add this to your environment.rb, or some file in config/initializers:

MultiDb::ConnectionProxy.setup!

If you only want to enable it for specific environments, add this to the corresponding file in config/environments:

config.after_initializedoMultiDb::ConnectionProxy.setup!end

In the development and test environments, you can use identical configurations for master and slave connections. This can help you finding (some of the) issues your application might have with a replicated database setup without actually having one on your development machine.

With Passengers smart spawning method, child processes forked by the ApplicationSpawner won’t have the connection proxy set up properly.

To make it work, add this to your environment.rb or an initializer script (e.g. config/initializers/connection_proxy.rb):

ifdefined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do|forked|ifforked# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!endendelse# not using passenger (e.g. development/testing)# ... set MultiDb configuration options, if any ...MultiDb::ConnectionProxy.setup!end

Thanks to Nathan Esquenazi for testing this.

Just add this to your controller:

around_filter(:only=>:foo_action) { |c,a|ActiveRecord::Base.connection_proxy.with_master { a.call } }

In your environment.rb or an initializer, add this before the call to setup!:

MultiDb::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
MultiDb::ConnectionProxy.setup!

NOTE: You cannot safely add more master_models after calling setup!.

This can be useful to leverage database level query caching as all queries will be sent to the same slave database during one web request.

To enable, add this to your environment.rb just before MultiDb::ConnectionProxy.setup!:

MultiDb::ConnectionProxy.sticky_slave = true

And add this to your ApplicationController:

after_filter { ActiveRecord::Base.connection_proxy.next_reader! }

NOTE: It’s not possible to toggle this mode in a running process, as the dynamically generated methods will have the initially defined “stickyness” built in.

You can use multi_db together with other framworks or in standalone scripts. Example:

require'rubygems'require'active_record'require'multi_db'ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.configurations = {
'development'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
},
'development_slave_database'=> {
'adapter'=>'mysql',
'host'=>'localhost',
'username'=>'root',
'database'=>'multi_db_test'
}
}
ActiveRecord::Base.establish_connection:developmentMultiDb::ConnectionProxy.setup!classMyModel<ActiveRecord::Base# ...end# ...

Note that the configurations hash should contain strings as keys instead of symbols.

  • Supports multiple slave databases (round robin)

  • It sends everything except “select …” queries to the master, instead of sending only specific things to the master and anything “else” to the slave. This avoids accidential writes to the master when there are API changes in ActiveRecord which haven’t been picked up by multi_db yet. Note that this behaviour will also always send helper methods like “quote” or “add_limit!” to the master connection object, which doesn’t add any more load on the master, as these methods don’t communicate with the db server itself.

  • It uses its own query cache as the slave’s cache isn’t emptied when there are changes on the master

  • It supports immediate failover for slave connections

  • It will wait some time before trying to query a failed slave database again

  • It supports nesting “with_master”-blocks, without unexpectedly switching you back to the slave again

  • It schedules a reconnect of the master connection if statements fail there. This might help with HA setups using virtual IPs (a test setup would be nice to verify this)

  • You specify slave databases in the configuration instead of specifying an extra master database. This makes disabling or removing multi_db less dangerous (Update: Recent versions of masochism support this, too).

  • There are no set_to_master! and set_to_slave! methods, just with_master(&block)

  • All proxied methods are dynamically generated for better performance

The original plugin:

A solution by FiveRuns, also based on masochism but without the “nested with_master”-issue, threadsafe and allows sharding of data.

See: github.com/schoefmax/multi_db/wikis/home

If you haven’t already, install the rspec gem, then create an empty database called “multi_db_test” (you might want to tweak the spec/config/database.yml). From the plugin directory, run:

specspec

Copyright © 2008, Max Schoefmann <max (a) pragmatic-it de> Released under the MIT license

About

Connection proxy for ActiveRecord for single master / multiple slave database deployments

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages