Re: [tornado] Making database connections in SockJS-Tornado

131 views
Skip to first unread message

Serge S. Koval

unread,
Oct 8, 2012, 2:38:18 PM10/8/12
to python-...@googlegroups.com
Hi,

 Best approach: if you use async capable DB (mongo, for example) - you can create one connection for your application. If you use non-async DB (redis, as it can't send replies asynchronously), you need to open new connection for each client.
 
1. __init__ is called for every new client, but it is advised to do all initialization code in on_open, because created class does not mean that logic SockJS connection was established.
2. No, don't do it. Having one connection per connected client is quite expensive by itself. Opening and closing connections for every message is even more expensive.

Serge.

On Mon, Oct 8, 2012 at 3:17 PM, Chris <bhp...@gmail.com> wrote:

Hello,

I am developing with sockjs-tornado library, and wonder what is the right way to make connections to database (e.g. mongo or redis) for each connected sockjs client.

So far, I can think of two ways of doing it:

1. Establish the connection inside '__init__' constructor of my SockJSConnection subclass. The question is, will this connection stay open as long as the client is connected to sockjs-tornado?

2. Establish the connection inside 'on_message' method whenever the connected sockjs client needs to do db work, and close it when the work is done. Not sure if this is good.

Which of the above would be the right way to go with sockjs-tornado? And If there is better alternative, please do share! Thank you.

Chris

unread,
Oct 8, 2012, 8:37:22 PM10/8/12
to python-...@googlegroups.com

Hi Serge,

Thank you for the tips.

I assume that by 'async', you meant the db itself, not the driver for it, because there are async drivers for redis?

Serge S. Koval

unread,
Oct 9, 2012, 1:53:47 AM10/9/12
to python-...@googlegroups.com
DB and driver.

For example, if you pick redis - you can issue command over active connection and you wait for response for that command over same connection. You can not issue two commands over same connection and expect results to be received in proper order.

However, if driver is smart enough, it can queue requests if there's one going already. In this case, you can have one redis connection per application and rely on the driver queue. Only problem with this approach - throughput, you won't be able to fully load redis with this approach.

Serge.

Andrew Grigorev

unread,
Oct 9, 2012, 4:09:52 AM10/9/12
to python-...@googlegroups.com, Serge S. Koval
09.10.2012 09:53, Serge S. Koval пишет:
> On Tue, Oct 9, 2012 at 3:37 AM, Chris <bhp...@gmail.com
> <mailto:bhp...@gmail.com>> wrote:
> > I assume that by 'async', you meant the db itself, not the driver
> for it, because there are async drivers for redis?
> DB and driver.

OMG :-)

Redis uses one-threaded asynchronous design. Like the most of tornado
applications. It is asynchronous.
There are many asynchronous clients for redis to use it with tornado.
Some of them are better, some of them - worse, but almost all of them
are asynchronous. :-)Redis usesa very simple protocol that allows you to
easily write asynchronous clients.

> For example, if you pick redis - you can issue command over active
> connection and you wait for response for that command over same
> connection. You can not issue two commands over same connection and
> expect results to be received in proper order.

You actually can. Read this for sure: http://redis.io/topics/pipelining
--
Andrew

Serge S. Koval

unread,
Oct 9, 2012, 5:34:31 AM10/9/12
to Andrew Grigorev, python-...@googlegroups.com
Redis protocol is synchronous, come on. Request in -> request out. You can't make requests to redis and receive replies out of order. Redis will block while executing request.

But yes, asynchronous redis driver can work with redis, as internally it:
1. Sends request to redis
2. Waits for response from redis
3. Dispatches response to oldest listener

So, if you do something like (pseudo code):
def query():
  redis.send('GET abc', callback=callback1)
  redis.send('GET def', callback=callback2)

driver will:
1. Send 'GET abc', 'GET def' immediately
2. Wait for data from socket
3. Receive first reply: 'abc' and pass it to callback1 - because it was added to listeners queue first
4. Receive second reply: 'def' and pass it to callback2, because no one else left.

How you can accomplish this with pipelining or without listeners queue?

Serge.

Andrew Grigorev

unread,
Oct 10, 2012, 7:30:16 AM10/10/12
to Serge S. Koval, Tornado Mailing List
+python-...@googlegroups.com

Would you also say that ioloop.add_callback is not asynchoronous,
because it executes the callbacks in the same order in which they where
added?

> How you can accomplish this with pipelining or without listeners queue?

Facepalm. Why without queue? Look here
https://github.com/ei-grad/toredis/blob/master/toredis/client.py#L107
and here
https://github.com/ei-grad/toredis/blob/master/toredis/client.py#L47. It
works, it is asynchronous, man.

Brukva's code is terrible. Btw, I have its author, Konstantin, here in
the Yandex office. He sitting across the table from me, and he is agree
he does not want to interfere with this conversation .

09.10.2012 13:37, Serge S. Koval О©╫О©╫О©╫О©╫О©╫:
> Clarification: by "wait" - I mean it listens for incoming data from
> socket (not blocking, etc).
>
> Like here:
> https://github.com/kmerenkov/brukva/blob/master/brukva/client.py#L268
>
> Serge.
> <and...@ei-grad.ru <mailto:and...@ei-grad.ru>> wrote:
>
> 09.10.2012 09:53, Serge S. Koval О©╫О©╫О©╫О©╫О©╫:
>
> On Tue, Oct 9, 2012 at 3:37 AM, Chris <bhp...@gmail.com
> <mailto:bhp...@gmail.com> <mailto:bhp...@gmail.com
> <mailto:bhp...@gmail.com> <mailto:bhp...@gmail.com
--
Andrew

Andrew Grigorev

unread,
Oct 10, 2012, 7:52:13 AM10/10/12
to python-...@googlegroups.com
The "he is agree" was crossed out. Fail)

10.10.2012 15:30, Andrew Grigorev О©╫О©╫О©╫О©╫О©╫:
> +python-...@googlegroups.com
>
> Would you also say that ioloop.add_callback is not asynchoronous,
> because it executes the callbacks in the same order in which they
> where added?
>
> > How you can accomplish this with pipelining or without listeners queue?
>
> Facepalm. Why without queue? Look here
> https://github.com/ei-grad/toredis/blob/master/toredis/client.py#L107
> and here
> https://github.com/ei-grad/toredis/blob/master/toredis/client.py#L47.
> It works, it is asynchronous, man.
>
> Brukva's code is terrible. Btw, I have its author, Konstantin, here in
> the Yandex office. He sitting across the table from me, and he is
> agree^W^W^W he does not want to interfere with this conversation .

Serge S. Koval

unread,
Oct 10, 2012, 9:02:16 AM10/10/12
to python-...@googlegroups.com
On Wed, Oct 10, 2012 at 2:52 PM, Andrew Grigorev <and...@ei-grad.ru> wrote:
Would you also say that ioloop.add_callback is not asynchoronous, because it executes the callbacks in the same order in which they where added?
Bad example - you can listen for FD events and, suddenly, your callbacks are out of order. Same as ioloop.add_timeout and so on.
 
Anyway, there was miscommunication - you're talking about redis driver (toredis) implementation and its asynchronous API, I was more into lower level protocol, which is synchronous. Obviously, you can write asynchronous library which works with synchronous protocol by queueing requests and expecting replies in proper order from the service. I'm not even arguing here.

And yes, after thinking about it - having one connection for tornado app to redis should work unless you have pretty heavy traffic and will send data faster than redis can handle it. If redis can't recv() data before internal socket buffer will be filled, connection will be dropped. Should not be the problem, as it is highly unlikely that 1 tornado process can create so much load on one redis server.

Serge.

Andrew Grigorev

unread,
Oct 10, 2012, 10:29:42 AM10/10/12
to python-...@googlegroups.com, Serge S. Koval
10.10.2012 17:02, Serge S. Koval пишет:
> On Wed, Oct 10, 2012 at 2:52 PM, Andrew Grigorev <and...@ei-grad.ru
> <mailto:and...@ei-grad.ru>> wrote:
>
> Would you also say that ioloop.add_callback is not
> asynchoronous, because it executes the callbacks in the same
> order in which they where added?
>
> Bad example - you can listen for FD events and, suddenly, your
> callbacks are out of order. Same as ioloop.add_timeout and so on.

I said "ioloop.add_callback". It doesn't listen any FDs for events. Its
callbacks are just called in every IOLoop cycle with "for callback in
self._callbacks" loop in place.

> Anyway, there was miscommunication - you're talking about redis driver
> (toredis) implementation and its asynchronous API, I was more into
> lower level protocol, which is synchronous. Obviously, you can write
> asynchronous library which works with synchronous protocol by queueing
> requests and expecting replies in proper order from the service. I'm
> not even arguing here.

It seems for me, like you are associating a strange thing with the
"asynchronous" in your mind. Redis protocol, on the "lower level", is
not synchronous. You can send new requests while you recieving the
answers to other requests, which were sent earlier. It is how
"pipelining" works (also, I found it quite funny when discovered [some
years ago] that such behaviorof the network protocols has its own name
:-) ).

I understand "synchronous" as you have to wait the result of the current
operation, before you execute the next. May be I understand it wrong?

> And yes, after thinking about it - having one connection for tornado
> app to redis should work unless you have pretty heavy traffic and will
> send data faster than redis can handle it.

It would not work if you want to use the redis transactions in
asynchronous request handler. Also, there is a PubSub.

> If redis can't recv() data before internal socket buffer will be
> filled, connection will be dropped. Should not be the problem, as it
> is highly unlikely that 1 tornado process can create so much load on
> one redis server.

You saying a strange thing. Could you justify your words by any
references to redis (or linux, probably) source code?)
Actually, there are mechanisms in TCP, which would regulate the data
flow to ammend the situation described by you.

> Serge.

Btw, our conversation reminded me this post -
http://softwaremaniacs.org/blog/2009/12/13/unfortunate-asynchronism/ :-).
So, lets just stop this useless flame...

--
Andrew

Reply all
Reply to author
Forward
0 new messages