NeverBlock MySQL Support

We are pleased to announce the availability of a MySQL database driver for NeverBlock. This is the second database driver for NeverBlock after the PostgreSQL driver. We hope that with time, this family will grow.

Of course the driver does all that you expect from a decent NeverBlock driver. It can do IO operations concurrently and in a transparent manner, thanks to NeverBlock. An interesting side effect emerged during the development of this driver. We were required to update the current MySQL driver to be able to do async operations. Once those were done, we discovered that the basic foundation for threaded support was there. Hence we went forward and implemented it (with help from Ruby gurus like Aman Gupta and Roger Pack).

What we have now is a new general purpose MySQL driver that supports threaded access and async operations. This means that you can send queries to a MySQL server in a concurrent manner from Ruby applications. This is big news for those waiting for Rails thread safety. Finally there is a MySQL driver that can help them achieve that concurrency.

We have packaged this as mysqlplus, it lives in github now and people are welcome to try it out.

The package comes with a couple test scripts that show case the usage of the new library in a threaded or an evented environment.

Here are the results of running 10 “select sleep(1)” queries in normal, threaded and evented modes

MySQL: Normal vs Threaded vs Evented

These should be good news for MySQL users. With the near release of Rails 2.2 this driver can help exploit threaded servers for Rails.

Comments

1.

Oh, these are great news! Just when I was convinced into take a look in PosgreSQL! ;) Great job!

2.

I didn't even know this was coming, let alone so fast. This is awesome.

3.

And this is even supported by Ruby 1.8.6? You guys outdid yourselves. Can this also be used with Rails 2.1?

4.

José, I would still encouage you to have a look at postgres, it's an impressive bit of kit.

5.

@Jose, I second Richard, Postgres is definitely worth a look, you might even not want to look back :) @Nathan, it is a drop in replacement for the current mysql driver. It sure can work with 2.1 but you can only benefit from threaded access if Rails is thread safe/aware which means 2.2

6.

I notice you mentioned evented, does this mean if you use something like Thin, it will take advantage of this new driver? What about merb and datamapper?

7.

Wait, so is this or is this not available in the most recent stable Ruby (1.8.7)? If these features depend on neverblock, and neverblock depends on 1.9, doesn't that mean this only works in 1.9?

8.

@Josh, using the driver in the evented mode with Thin would require rewriting good parts of Rails and change the way you write your actions as well. So unless you use NeverBlock it cannot take advantage in a seamless way. @Justin, this is available for 1.8.x, it spun off the NeverBlock project but it does not depend on it at all. I won't be surprised if it works with 1.6.x as well (not so sure though)

9.

I've always wondered why Ruby on Rails community favors MySQL more - PostgreSQL has always been better and it's a true independent and open-source project. To me it's a misperception that MySQL is easier to install, maintain, etc.

10.

I am starting with a project that requires MS SQL Server development with Rails. I see that you say that with time the family of drivers will grow. I trust/hope that you will have a MS SQL Server driver as the next (hopefully soon) new member of the family :)

11.

@Nikolay, MySQL was - and still is - stupid fast. For stupid queries that just do CRUD without transactions, or functions or views or anything else "advanced" MySQL is brilliantly fast on very minimal hardware. Since most Web applications were (and some still are) built to use the database as nothing more then a persistent data dump, MySQL has been the default choice in that space. Both MySQL and PostgreSQL have advanced in terms of speed and featured. While I believe MySQL is still faster in its original market, PostgreSQL is not too far behind. And while PostgreSQL has always had the reputation of being a more powerful and complaint engine MySQL is catching up

12.

So this is a drop in replacement for the default mysql adapter, and can be used in Rails 2.1 and with mongrel? Or will apps only see any advantages when using Rails 2.2? Besides that, why is this a separate project and not a contribution to the default mysql adapter? Am I right when I assume it's planned once the adapter is stable?

13.

StarTrader: Catching up? No way, no how. As long as MySQL still incurs database corruption like it does during "crashes", it won't be caught up. We've never had a PostgreSQL server crash on us, but we have simulated crashes, and each time it comes back up reliably. We love PostgreSQL...

14.

@aleco, you will not gain any advantage from the threaded access support till Rails 2.2. That said, expect good news tomorrow regarding Rails 2.1 and Ruby 1.8.x

15.

hmm, so why can the mysql driver work with ruby 1.8.x but not the postgresql one? I would really like to use this on 1.8.x, but I don't want to mess up my system with having 2 different ruby versions installed.

16.

This is fantastic! I wrote a little drb worker drone to execute LONG queries to be able to run concurrent queries in a process. It looks like this library will remove that need completely.

17.

Hi, could anybody tell me how to use this adapter? I put mysqplus in my database.yml and it crashes saying "Please install the mysqlplus adapter: `gem install activerecord-mysqlplus-adapter` (no such file to load -- active_record/connection_adapters/mysqlplus_adapter)"

18.

I have the exact same problem as @Vidmantas, tried to search the web for an answer, but was unable to retrieve one.

19.

@Vidmantas , @Enog Please check this new blog post NeverBlock:Instant Scaling For Your Rails Apps It contains the whole steps

20.

when you announced postgres driver, though I was excited, but was sceptical as all my apps use mysql or oracle. first thing I will do is install this mysql driver on one of my app and do a benchmark myself.

21.

Mosta, thanks for link. But I followed all the steps but Rails stays complaining that neverblock_mysql_adapter doesn't exist. Any ideas?

22.

@j , the Postgres driver works with 1.8.6 now as well. @Vidmantas, that error means the neverblock gem was not installed correctly, please check your gems dir to make sure it is there

23.

This is great news! Awesome to see progress on the mysql driver... and on 1.8! Nice work guys.

24.

I have been installed Neverblock. I use MySQL and Ruby 1.8. When i start my server, i have an error : FiberError (not inside a fiber): /Library/Ruby/Gems/1.8/gems/espace-neverblock-0.1.3/lib/never_block.rb:43:in `current' /Library/Ruby/Gems/1.8/gems/espace-neverblock-0.1.3/lib/never_block.rb:77:in `neverblock' /Library/Ruby/Gems/1.8/gems/espace-neverblock-0.1.3/lib/active_record/connection_adapters/neverblock_mysql_adapter.rb:48:in `connect' Do you have an idea ? Thx you, Florian

25.

@Florian, make sure you require 'never_block/servers/thin' in your environment file

26.

Be careful with this. I installed this and rebooted my script/server and characters in the browser were being corrupted - it appeared that data in the database was corrupted. Upon uninstallation of the gem, data returned to normal. I'm using Mac OSX 10.5.4, Rails 2.1.0 and MySQL 5.0.51a.

27.

@gavin you can build the new gem from http://github.com/oldmoe/mysqlplus/tree/master by just running 'rake'.It includes fixes for the UTF 8 issue you experienced.

28.

@gavin, the data in the db was not corrupted, the c method that converts the result set to Ruby hashes had an issue with utf8 string termination. This is fixed now as Lourens have said.

29.

@Lourens, @oldmoe: Thanks very much, I'll be building the new gem.

30.

Does non-blocking mysql support mean two separate HTTP requests sharing the same MySQL connection at the same time? Wouldn't that cause problems with things like transactions?

31.

@daesan, transactions are fully handled, whenever a request starts a transaction a connection is associated with it until it releases it or until it terminates. That way we make sure all the sql commands in a transaction are sent to the same connection which is not interrupted by any other queries

32.

A quick test shows that Mysql.connect() in a thread still blocks the whole interpreter. Will this be fixed?

33.

@Jos, currently only the async_query method is Ruby threading friendly. We should be able to implement this for connect as well but currently you can rely on the connection pool to reduce the effect of this part.

34.

oldmoe, thanks for your response. async_query does works well. And I'm happy to hear Mysql.connect is part of the async roadmap. Could you please elaborate on how the connection pool helps here? My app has to talk to several dozen db servers, some of which may not even be up or slow to respond. This is why it's imperative that connect does not block, so that other connections can proceed. Today we address this with separate processes but using threads would likely be (much) more efficient, hence my question. Thanks for your help and for working on these great tools.

35.

@Jos Is it DNS that's blocking? If so have you tried using require 'resolv-replace' that might help It might also help to open a 'standard' connection [or maybe eventmachine style connection? or revactor style?] first to make sure the port is open THEN try and connect. Good luck! -=R

36.

Thanks @roger. http://pastie.org/276050 shows my test code and strace output. I don't think the problem is DNS because the script continues the moment I kill -CONT the STOPped mysqld. The idea to use a standard connection would be usable if the Mysql API had a way to pass in an existing socket to a connect()-like method. The problem with the `standard' connect() is that it introduces a race (1st connect succeeds, 2nd one fails).

37.

@Jos, I am not sure how can there be a race in "connect" as it should block the whole interpreter till it is completed. I need to look further into this. One quick fix for your issue is to delegate connection creation to a certain thread this way you make sure connection attempts are sequential. Btw, Lourens just added support for async_connect in mysql plus, you might try this as well

38.

@oldmoe, Roger suggests making a standard socket connection first to make sure the port is open. If that Socket.connect succeeds but the server immediately becomes unavailable, the following Mysql.connect() will still block. So there's a race between the Mysql.connect succeeding and the server becoming unavailable. If one could pass an open socket to Mysql.connect the race is avoided because while the server still becomes unavailable, Mysql.async_query deals with that properly and the other threads can proceed. I will try out the new Mysql.async_connect and report back. Thank you.

39.

I wonder if the problem is that the host2 allows socket connections but then basically doesn't respond to input on them [so it times out on waiting on authentication]. Regardless, here are some thoughts: you could try http://gist.github.com/11429 I think the first goal is to avoid the blocking aspect, and the second goal would be to avoid a race condition. So to avoid blocking, if desperate, you could try drb [or forking a process or is there some project called fork off?] and have the child process determine if the port is open, if it is then you would try to connect to it. If you're on 1.9, figure out which part of the code is hanging [the Ruby code] and maybe we can add a rb_thread_blocking_region around the C region of that part Also what does the screen output when you run that script? Note also a google group: http://groups.google.com/group/never-block?hl=en Good luck! -=R

41.

@oldmoe, where is this async_connect code? I don't see it in your mysqlplus tree. @roger, we use seperate processes today, kind of like forkoff; I'm investigating the use of threads to replace it. The gisted patch applies neither to oldmoe's nor the espace tree. The code is hanging on the Mysql.connect call, so I was hoping to try the async_connect change @oldmoe refers to but I can't find it. Partial script output at http://pastebin.com/m753b53fc. Thanks!

41.

@jos checkout http://github.com/oldmoe/mysqlplus/tree/19_non_gvl_connect that branch attempts a non blocking connect. That and make sure you're connecting to IP addresses [if it doesn't work]. Thanks! -=R

42.

@roger thanks, I'll try this with 1.9.1-preview1. Looks like it is for 1.9 only, right?

43.

@roger, ext/mysql.c needs this patch to build against ruby-1.9.1-preview1: http://pastie.org/303419

44.

@roger, I'm encountering an error; test script and output here: http://pastie.org/303424

45.

I'll look at that. You may also want to CC future comments to http://groups.google.com/group/never-block?hl=en so that I get them fast :)

46.

I'll go ahead and paste some comments to that group. GL!