Updating multiple databases at the same time


#1

I have an application that is load balanced. I have a master database
which I update once a day. Then I push the raw mysql files to all other
servers so they are the same as the master. This works fine, but there
are a few situations where I need all databases to update in real-time.
What would be the best way to achieve this in rails?

Here is an example of what I am trying to do. I want to update the name
of a product on my website. Here is the controller:

def update_product_name
product = Product.find(params[:id])
product.name = params[:name]
product.save
#Say I want to save this to 3 other databases
#can I do this with activerecord?
#PSUEDO CODE… I know it cant do this
product.save(mysql_host2)
product.save(mysql_host3)
product.save(mysql_host4)
end

Any ideas? Alternative ways to do this?


#2

Another thing… I don’t want to do this per model. This would happen in
very few situations, so I would like to code this in the controller if
possible (I will probably add a method to application.rb and call it in
the controller when appropriate).

Yanni M. wrote:

I have an application that is load balanced. I have a master database
which I update once a day. Then I push the raw mysql files to all other
servers so they are the same as the master. This works fine, but there
are a few situations where I need all databases to update in real-time.
What would be the best way to achieve this in rails?

Here is an example of what I am trying to do. I want to update the name
of a product on my website. Here is the controller:

def update_product_name
product = Product.find(params[:id])
product.name = params[:name]
product.save
#Say I want to save this to 3 other databases
#can I do this with activerecord?
#PSUEDO CODE… I know it cant do this
product.save(mysql_host2)
product.save(mysql_host3)
product.save(mysql_host4)
end

Any ideas? Alternative ways to do this?


#3

Yanni M. wrote:

product = Product.find(params[:id])
Any ideas? Alternative ways to do this?

You could use MySQL’s built-in replication support.


Jack C.
removed_email_address@domain.invalid


#4

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jack C. wrote:

def update_product_name

Any ideas? Alternative ways to do this?

You could use MySQL’s built-in replication support.

What if I want it on other SQL server?

davi
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkltDOUACgkQ76Bs0E5RGKO3twCePRLi1tyfJM1FTGgQX3jiT7Co
BDgAnilihvAKaFQE+17ifR4RaASgLqjV
=a/a+
-----END PGP SIGNATURE-----


#5

A “not so easy” way to solve this is to write your own database
adapter, that would send the real SQL code to many different databases
(your adapter would contain an array of other adapters that would
receive the real SQL). That’s how tools like C-JDBC do it.

But if you need this for MySQL only, you should try to use the
database replication mechanism.

Maurício Linhares
http://alinhavado.wordpress.com/ (pt-br) | http://blog.codevader.com/
(en)


#6

The problem is that I don’t want to replicate everything. The way I
understand it, and correct me if I am wrong b/c I have never set up
master/slave replication in MySQL, every time there is a
insert/update/delete to the database, it will replicate to the others
automatically in real-time. I don’t want this to happen, because I am
running a script that updates 16 million rows and takes 20 hours to
complete… replication would affect performance on the live slaves.
In parallel to this script running I am making live changes to the data
in my app via a web interface. These changes (small portion compared to
the script running) will need to write to all 4 databases at the same
time. I am assuming mysql replication is all or none and can’t do
this… meaning replicate some times and not others??


#7

On 13 Jan 2009, at 23:08, Maurício Linhares wrote:

A “not so easy” way to solve this is to write your own database
adapter, that would send the real SQL code to many different databases
(your adapter would contain an array of other adapters that would
receive the real SQL). That’s how tools like C-JDBC do it.

Doesn’t that boil down to reinventing replication ?

Fred


#8

def update_product_name
product = Product.find(params[:id])
product.name = params[:name]
product.save
#Say I want to save this to 3 other databases
#can I do this with activerecord?
#PSUEDO CODE… I know it cant do this
product.save(mysql_host2)
product.save(mysql_host3)
product.save(mysql_host4)
end

Any ideas? Alternative ways to do this?

I would like to know what their connection are already configured to
your applications? because to connect multiple databases are different
configuration or you can do manually connection in your AR (if this is a
false solution, please give me issues and resolution ):

require “activerecord”

def update_product_name

// i am not sure about this script is put in Class AR
// Maybe it is suitable to put out of class AR
ActiveRecord::Base.establish_connection(
:adapter=>“mysql”,
:database=>“theSame”,
:username=>“theSame_theSame”,
:password=>“1234567890”
:host=>“theSame-2.com”)

saving_name(params[:id],params[:name])
end

// you can make array to descript your multiple login then loop it.

end

def saving_name(id,name)
product = Product.find(id)
product.name = name
product.save
ActiveRecord::Base.remove_connection
end

  • Ruby Servant -

#9

Yanni M. wrote:

I have an application that is load balanced. I have a master database
which I update once a day. Then I push the raw mysql files to all other
servers so they are the same as the master. This works fine, but there
are a few situations where I need all databases to update in real-time.
What would be the best way to achieve this in rails?

Here is an example of what I am trying to do. I want to update the name
of a product on my website. Here is the controller:

def update_product_name
product = Product.find(params[:id])
product.name = params[:name]
product.save
#Say I want to save this to 3 other databases
#can I do this with activerecord?
#PSUEDO CODE… I know it cant do this
product.save(mysql_host2)
product.save(mysql_host3)
product.save(mysql_host4)
end

Any ideas? Alternative ways to do this?

Before we have an adapter capable of supporting two-phase commit
distributed transaction, it will be difficult to have a single
transaction to commit changes to more than one database.

One alternative is to use message queuing. Essentially you generate
messages destined to each DB and each DB will process its queue. Of
course, you might have to devise some additional messages to compensate
any actions rolled back in the master/slave due to some reasons like
errors etc.

Regards,

rp8

http://competo.com


#10

Rails T. wrote:

def update_product_name
product = Product.find(params[:id])
product.name = params[:name]
product.save
#Say I want to save this to 3 other databases
#can I do this with activerecord?
#PSUEDO CODE… I know it cant do this
product.save(mysql_host2)
product.save(mysql_host3)
product.save(mysql_host4)
end

Any ideas? Alternative ways to do this?

I would like to know what their connection are already configured to
your applications? because to connect multiple databases are different
configuration or you can do manually connection in your AR (if this is a
false solution, please give me issues and resolution ):

require “activerecord”

def update_product_name

// i am not sure about this script is put in Class AR
// Maybe it is suitable to put out of class AR
ActiveRecord::Base.establish_connection(
:adapter=>“mysql”,
:database=>“theSame”,
:username=>“theSame_theSame”,
:password=>“1234567890”
:host=>“theSame-2.com”)

saving_name(params[:id],params[:name])
end

// you can make array to descript your multiple login then loop it.

end

def saving_name(id,name)
product = Product.find(id)
product.name = name
product.save
ActiveRecord::Base.remove_connection
end

  • Ruby Servant -

Yeah… I think this is sort of what I am looking for. I was playing
around with something like this (still tweaking it after getting some
errors)

slaves = [“host2”,“host3”,“host4”]
for slave in slaves
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[RAILS_ENV].merge(‘host’
=> slave))
unique_product.save
end
#set back to original host
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[RAILS_ENV].merge(‘host’
=> original_host))