Skip to content

Instantly share code, notes, and snippets.

@capotej
Created December 17, 2008 00:06
Show Gist options
  • Save capotej/36877 to your computer and use it in GitHub Desktop.
Save capotej/36877 to your computer and use it in GitHub Desktop.
(07:28:35 PM) capotej: whew, i switched to sequel from activerecord and my req/s skyrocketed
(07:30:30 PM) danishkirel [[email protected]] entered the room.
(07:30:39 PM) MarkMenard_: capotej: What framework are you using for the web tier?
(07:31:01 PM) capotej: sinatra
(07:31:10 PM) MarkMenard_: Interesting.
(07:31:17 PM) capotej: yea i was blown away
(07:31:18 PM) MarkMenard_: Before and after numbers?
(07:31:22 PM) capotej: 0.81 req/s
(07:31:26 PM) capotej: 245 req/s
(07:31:27 PM) capotej: lol
(07:31:39 PM) MarkMenard_: Were you bootstrapping AR each time?
(07:31:48 PM) MarkMenard_: that's seems like to large a difference.
(07:32:06 PM) nicksieger left the room (quit: "ERC Version 5.2 (IRC client for Emacs)").
(07:32:29 PM) capotej: i dont know what it was doing, i think it was re reading the attributes every time
(07:32:53 PM) capotej: even in production mode
(07:33:26 PM) nicksieger [[email protected]] entered the room.
(07:33:33 PM) MarkMenard_: That doesn't seem right.
(07:33:45 PM) MarkMenard_: it really sounds like AR was bootstrapping each time.
(07:33:52 PM) MarkMenard_: It'll really slow down if you do that.
(07:34:03 PM) bitsweat: could you show your AR setup code, capotej ?
(07:34:16 PM) capotej: yea no problem, im getting the revision now
(07:34:22 PM) bitsweat: 0.81 req/sec is definitely way off what we'd expect to see :)
(07:34:36 PM) jeremyevans: capotej: That's probably do to the messed up connection pool in AR 2.2
(07:34:58 PM) jeremyevans: Rails cleans out dead connections via an after filter type mechanism
(07:35:16 PM) jeremyevans: Other frameworks don't.
(07:35:35 PM) capotej: http://github.com/jcapote/bloggy/tree/ac01d7b313c57b410bc21fd6fd87d1228affc6c1/bloggy.rb
(07:35:49 PM) capotej: yea i couldn't find much info on using AR outside of rails
(07:35:52 PM) jeremyevans: Basically, AR's connection pool cheats and leaks connections whenever you use AR. You have to clean the garbage up yourself if you aren't using Rails
(07:36:03 PM) capotej: sequel ended up being a better fit anyway
(07:36:09 PM) jeremyevans: This isn't a problem with Sequel or DM
(07:36:47 PM) bitsweat: messed up! cheats! leaks!
(07:36:51 PM) jeremyevans: I can't fault the AR connection pool implementer, I'm sure the correct way to do it would require rewriting most of AR
(07:36:52 PM) bitsweat: omg rails!
(07:37:39 PM) capotej: it was an interesting problem to debug
(07:37:44 PM) MarkMenard_: jeremyevans: Do you have information about how to clean up. I'm using AR outside of Rails.
(07:37:54 PM) jeremyevans: bitsweat: No offense, if you clean up the garbage AR is reasonably fast. However, don't you agree that leaking connections is an ugly hack?
(07:38:00 PM) capotej: i thought that query caching wasnt working so i was just going to write my own using sequel
(07:38:04 PM) capotej: turns out i didnt need to
(07:38:19 PM) jeremyevans: MarkMenard_: What are you using?
(07:38:47 PM) MarkMenard_: I'm using an embeded Rails environment inside a Java application.
(07:38:48 PM) bitsweat: jeremyevans: what do you mean by garbage?
(07:39:00 PM) MarkMenard_: So, I'll need to clean up connections on my own.
(07:39:11 PM) MarkMenard_: I'm really just using it to get access to AR stuff.
(07:39:15 PM) bitsweat: you mean that the connection pool doesn't verify connections on its own?
(07:39:17 PM) jeremyevans: bitsweat: ActiveRecord leaks connections from the connection pool, and Rails cleans the up in the dispatcher.
(07:39:29 PM) bitsweat: what do you mean by 'leaks'?
(07:40:00 PM) bitsweat: you dislike that there isn't an explicit claim/release?
(07:40:04 PM) jeremyevans: bitsweat: 6.times{Thread.new{Model.first}}
(07:40:26 PM) jeremyevans: bitsweat: It allows and by default chooses a checkin/checkout mechanism
(07:40:49 PM) jruby-linux-x86: (notice) jruby-spec-java5 build failed (http://jruby.headius.com:8080/hudson/job/jruby-spec-java5/195/) last commit(s): lopex
(07:41:03 PM) bitsweat: I guess I don't see this leak
(07:41:04 PM) jeremyevans: bitsweat: The checkout is implicit when you use AR, but the checkin is only implicit if you use Rails
(07:41:16 PM) bitsweat: oh, I see
(07:41:40 PM) bitsweat: how would you do implicit checkin?
(07:41:42 PM) jeremyevans: MarkMenard_: You want ActiveRecord::Base.clear_active_connections! in an after_filter type thing
(07:41:43 PM) MarkMenard_: jeremyevans: Do you know what file the reclamation is done in?
(07:41:52 PM) MarkMenard_: jeremyevans: Thanks.
(07:42:37 PM) jeremyevans: bitsweat: Sequel has a real connection pool that checks out a connection when needed and back in when it is finished using. I'm not sure if that's possible given AR's architecture
(07:42:48 PM) bitsweat: you can use ActiveRecord::Base.with_connection do ... to checkin/checkout explicitly
(07:42:56 PM) jeremyevans: I give the benefit of the doubt to the AR connection pool implementer
(07:42:59 PM) bitsweat: a *real* pool!
(07:43:04 PM) bitsweat: come on with the diss language
(07:43:17 PM) walters left the room (quit: Read error: 110 (Connection timed out)).
(07:43:33 PM) jeremyevans: bitsweat: True, but who does that? With Sequel it's all transparent, as it ought to be.
(07:43:58 PM) bitsweat: that'd certainly be preferable
(07:44:02 PM) jeremyevans: Why doesn't AR always use that internally, so the user never needs to worry about it?
(07:44:48 PM) MarkMenard_: jeremyevans: Thanks.
(07:44:49 PM) Jacob_Kessler left the room.
(07:45:05 PM) jeremyevans: I'm not here saying AR sucks, I'm saying the connection pool leaks connections which Rails cleans up in the dispatcher.
(07:45:26 PM) bitsweat: jeremyevans: because it's an evolution of AR, can't rewrite the whole thing every go around
(07:45:45 PM) bitsweat: jeremyevans: your language is full of "AR sucks", actually
(07:45:46 PM) jeremyevans: That's a fact. If you don't know how AR's connection pool works and you use it outside of Rails in a threaded environment, it's going to be painful slow
(07:45:47 PM) wmeissner [[email protected]] entered the room.
(07:46:24 PM) ephemerian left the room (quit: "Leaving.").
(07:47:03 PM) jeremyevans: bitsweat: Take offense if you want, none is intended. I'm sure the connection pool implementer did the best job he good. AR just wasn't designed for it, and the retrofit certainly works fine if you use Rails (or other frameworks so long as you know how to clean up the connections).
(07:47:04 PM) bitsweat: that's true...
(07:47:38 PM) bitsweat: I'm sure none is intended, it's just a messed up cheating ugly hack!
(07:49:01 PM) jeremyevans: bitsweat: An ugly hack it certainly is. It's messed up that the user has to manage it. And if I were a teacher and asked a student to write a connection pool, I'd certainly say AR's method is cheating. :)
(07:49:52 PM) sproutss [[email protected]] entered the room.
(07:49:54 PM) jeremyevans: bitsweat: Even being a messed up cheating ugly hack, it's still much better than not having a connection pool at all (at least if you use Rails or know how to handle it)
(07:55:15 PM) MenTaLguY [[email protected]] entered the room.
(07:58:50 PM) danishkirel left the room (quit: "Leaving...").
(08:00:13 PM) myabc left the room (quit: ).
(08:00:59 PM) lopex_ [[email protected]] entered the room.
(08:02:02 PM) fwierzbicki [[email protected]] entered the room.
(08:04:12 PM) bitsweat: jeremyevans: just looked at sequel's pool usage, pretty nice
(08:04:57 PM) bitsweat: your #hold is like AR's #with_connection, but it's done internally everywhere you use the connection
(08:05:33 PM) bitsweat: the connection pool itself is a pretty similar beast, but it's wired into the adapters differently
(08:06:12 PM) lopex left the room (quit: Read error: 145 (Connection timed out)).
(08:08:25 PM) bitsweat: not sure I prefer this strategy though
(08:09:24 PM) bitsweat: connections may be returned to the pool in a dirty state
(08:09:53 PM) bitsweat: there's no verification that the connection is clean on checkout
(08:12:08 PM) dcorbin left the room (quit: "Leaving").
(08:12:23 PM) robin_dewd [[email protected]] entered the room.
(08:12:59 PM) dcorbin [[email protected]] entered the room.
(08:15:27 PM) gautam [[email protected]] entered the room.
(08:17:19 PM) lopex_ left the room (quit: ).
(08:23:19 PM) fowlduck left the room (quit: "Leaving...").
(08:26:29 PM) mark_____ [[email protected]] entered the room.
(08:33:36 PM) jeremyevans: bitsweat: True. This hasn't been an issue, and would be easy to add if it was necessary.
(08:34:50 PM) jeremyevans: bitsweat: Hopefully AR can use with_connection everywhere internally in the future. That way, even Rails would work with things like: def action; Model.first; <expensive operation here> end.
(08:36:38 PM) jeremyevans: If you do that now, Rails won't return the connection until the end of the action, which could exhaust the pool if you have a lot of simultaneous clients using the action. If AR returned the connection before returning from Model.first, your concurrency would go way up.
(08:36:42 PM) slyphon [n=slyphon@unaffiliated/slyphon] entered the room.
(08:37:31 PM) bitsweat: yeah, maybe it'd help to introduce different notions of checkin/checkout
(08:37:40 PM) bitsweat: one per operation and another per session
(08:37:55 PM) bitsweat: the dirty connection thing hits a lot, actually, due to idle timeouts
(08:38:55 PM) bitsweat: I'd be interested to see how you'd add this to sequel
(08:39:24 PM) bitsweat: because with the current model there's no knowledge of whether a checkin is implicit or whether it may be used again
(08:39:52 PM) bitsweat: so you wouldn't want to disrupt a transaction or reset the current user/database
(08:40:47 PM) jeremyevans: bitsweat: With sequel, all transactions are done using Database#transaction, so that's not an issue.
(08:41:34 PM) jeremyevans: users shouldn't be doing anything to disrupt the connection. If the connection to the database dies, and the adapter is configured correctly, it should remove the connection from the pool.
(08:42:15 PM) xibbar left the room (quit: Read error: 110 (Connection timed out)).
(08:46:46 PM) bitsweat: I'm not seeing where that happens
(08:47:07 PM) wmeissner left the room (quit: Remote closed the connection).
(08:47:28 PM) david_koontz left the room (quit: ).
(08:47:31 PM) bitsweat: if an exception's raised in a transaction, a rollback is issued even if the connection is dead, then it's released back to the pool
(08:48:59 PM) bitsweat: I don't see any API to release & disconnect either
(08:53:53 PM) jeremyevans: bitsweat: The disconnection is implicit if the connection is lost (or you can use Database#disconnect)
(08:54:59 PM) jeremyevans: For a transaction, it would issue a rollback on a dead connection, but that shouldn't affect things (though the transaction code should probably be modified to check for that).
(08:59:06 PM) fwierzbicki left the room (quit: ).
(09:00:05 PM) bitsweat: I'm not seeing how or where a dead connection is evicted from the pool
(09:03:59 PM) jeremyevans: bitsweat: It's in the remove method. It catches DatabaseDisconnectError, which adapter are suppose to raise if they detect a disconnection.
(09:04:25 PM) jeremyevans: More accurately, hold catches DDE and calls remove, which removes the connection from the pool
(09:04:50 PM) bitsweat: hm, I must be looking at an old sequel checkout
(09:05:03 PM) jeremyevans: bitsweat: there's also the disconnect method, which removes all connections from the pool
(09:05:13 PM) bitsweat: ah yeah, 2.1.0 from June
(09:05:14 PM) jeremyevans: bitsweat: Probably, the disconnect stuff was just added in 2.8
(09:05:18 PM) fowlduck [[email protected]] entered the room.
(09:06:23 PM) james_britt left the room (quit: "KVIrc 3.2.4 Anomalies http://www.kvirc.net/").
(09:07:44 PM) dysinger left the room (quit: ).
(09:08:38 PM) polymar left the room (quit: "Leaving...").
(09:08:38 PM) stepheneb [[email protected]] entered the room.
(09:09:40 PM) bitsweat: indeed, the updated impl is a lot better
(09:10:27 PM) bitsweat: it still releases possibly dead or dirty connections though
(09:11:01 PM) MarkMenard left the room (quit: ).
(09:13:11 PM) bitsweat: looks like DatabaseDisconnectError is overused too
(09:13:19 PM) bitsweat: e.g. a duplicate key violation would disconnect
(09:13:58 PM) haku left the room (quit: ).
(09:14:59 PM) bitsweat: and most of the adapters don't implement it
(09:15:21 PM) bitsweat: anyway.. interesting to see :) checking out data mapper's; do you know where it lives?
(09:17:26 PM) MarkMenard [[email protected]] entered the room.
(09:17:37 PM) hipertracker_ [[email protected]] entered the room.
(09:18:17 PM) BrianTheCoder [n=williams@s208-180-21-105.bcstcmta02.clsttx.tl.sta.suddenlink.net] entered the room.
(09:23:13 PM) hipertracker left the room (quit: Read error: 110 (Connection timed out)).
(09:24:18 PM) _VVSiz_ [[email protected]] entered the room.
(09:24:27 PM) david_koontz [[email protected]] entered the room.
(09:29:11 PM) CIA-71: ruby: naruse * r20603 /trunk/ (ChangeLog re.c):
(09:29:11 PM) CIA-71: ruby: * re.c (rb_reg_initialize): raise RegexpError when encoding
(09:29:11 PM) CIA-71: ruby: is dummy encoding. [ruby-dev:37091]
(09:31:44 PM) wycats left the room (quit: ).
(09:32:56 PM) bitsweat: data mapper has no pool at all, it relies on data objects to handle that internally
(09:35:06 PM) bitsweat: it has the same dirty connection issues
(09:35:35 PM) bitsweat: and it doesn't do implicit checkin/out, it 'leaks' and cleans up old connections with a reaper thread
(09:36:11 PM) david_koontz left the room (quit: ).
(09:37:08 PM) bitsweat: that'll also die if you fork the process
(09:39:59 PM) jicksta left the room (quit: Read error: 104 (Connection reset by peer)).
(09:40:00 PM) hipertracker [[email protected]] entered the room.
(09:41:26 PM) moconnor [[email protected]] entered the room.
(09:42:31 PM) VVSiz_ left the room (quit: Read error: 110 (Connection timed out)).
(09:43:47 PM) MarkMenard left the room (quit: ).
(09:45:26 PM) stepheneb left the room (quit: ).
(09:45:31 PM) hipertracker_ left the room (quit: Read error: 110 (Connection timed out)).
(09:47:23 PM) stevenbristol left the room (quit: ).
(09:48:37 PM) MenTaLguY left the room (quit: "Leaving.").
(09:50:28 PM) MarkMenard [[email protected]] entered the room.
(09:52:12 PM) nicksieger: reaper thread? ouch
(09:58:08 PM) logan_barnett left the room (quit: ).
(09:59:07 PM) moconnor left the room (quit: ).
(09:59:49 PM) moconnor [[email protected]] entered the room.
(10:20:23 PM) _kofno_away is now known as _kofno
(10:21:23 PM) MarkMenard__ [[email protected]] entered the room.
(10:21:37 PM) MarkMenard left the room (quit: Connection reset by peer).
(10:21:57 PM) MarkMenard__ left the room (quit: Client Quit).
(10:26:32 PM) jeremyevans: bitsweat: Interesting. I hadn't looked at DM's implementation.
(10:27:44 PM) jeremyevans: DatabaseDisconnectError shouldn't be raised except if the connection has been lost. It's a bug otherwise. Only Postgres and Oracle implement it, though it shouldn't be hard to add to others if the underlying driver supports it.
(10:29:53 PM) miclorb left the room (quit: ).
(10:31:01 PM) pauldix left the room (quit: ).
(10:31:56 PM) jeremyevans: forking the process in the middle of a checkout would certainly screw things up, but you'd have to be crazy to fork inside a pool.hold call.
(10:33:59 PM) bitsweat: I mean forking will kill DO's reaper thread
(10:34:20 PM) bitsweat: these DO adapters are kinda odd too, C overkill
(10:34:57 PM) bitsweat: there are already db bindings for these, could just present a DO-compatible API
(10:35:33 PM) tarcieri: DO?
(10:35:43 PM) bitsweat: jeremyevans: the pg driver reraises PGError as DatabaseDisconnectError
(10:36:13 PM) bitsweat: could check whether the connection is actually hosed there, disconnect, then reraise
(10:36:22 PM) bitsweat: otherwise you're going to mask the real exception with a disconnect anyway
(10:36:41 PM) bitsweat: tarcieri: DO = data objects, the db driver lib that data mapper uses
(10:36:52 PM) tarcieri: aah
(10:39:11 PM) jicksta [[email protected]] entered the room.
(10:41:11 PM) jeremyevans: bitsweat: It should only raise DDE if a call to status raises PGError of if the status isn't CONNECTION_OK. If a duplicate key violation causes it, that's definitely a bug. Let me check.
(10:42:27 PM) bitsweat: jeremyevans: yeah, looks like that's right
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment