I have the exact same requirement. For now, I'm working around it with
a helper process that does routing between the global task list and
each worker own work list, based on availability information that each
worker puts on Redis.
It works but its not very pretty.
I havent looked at the possibility of implementing this routing logic
inside Redis with Lua in the scripting branch. Its something to
consider.
Salvatore: I know from past threads about scripting that the idea is
to send the entire Lua script every time I need to execute it. Are
there any plans to add an alternative method by which I could add new
Redis commands that would be implemented in Lua?
I don't quite remember why storing the script into a key to be reused
was a bad idea though. Something like:
SET my_new_command_script LUA_CODE
ROUTE NEW_COMMAND my_new_command
From that point on, the Redis server would accept NEW_COMMAND as a
valid command and forward it to the scripting engine with the
"my_new_command" script as the Lua code to execute.
Thanks,
--
Pedro Melo
@pedromelo
http://www.simplicidade.org/
http://about.me/melo
xmpp:me...@simplicidade.org
mailto:me...@simplicidade.org
Hello Pedro,
we implemented EVALSHA for this (bandwidth) issue. Basically you send
EVALSHA <sha1 of your script>. If the script was already seen in that
server it gets executed, otherwise you get an error back and you'll
instead use EVAL for this time. The next time the EVALSHA will be
accepted.
Since EVALSHA will usually work you just send EVALSHA the first time,
so there is no additional round trip cost.
This is as good as defining commands from the point of view of
performances, but with the huge benefit that you don't need to make
sure your program is calling a Redis instance with the right version
of a command you implemented server-side and so forth. Also if you
have a cluster of Redis instances it is very handy to consider every
instance as every other regardless of defined script versions and so
forth.
All this is already into unstable.
Salvatore
--
Salvatore 'antirez' Sanfilippo
open source developer - VMware
http://invece.org
"We are what we repeatedly do. Excellence, therefore, is not an act,
but a habit." -- Aristotele
On Sun, Sep 25, 2011 at 11:48 AM, Ethan Collins
<collins...@gmail.com> wrote:
> Well, adding Lua scripts is a method to add a layer of intelligent
> logic using redis primitives. In this case, I think Lua script is a
> workaround, as Pedro mentions.
Yes I was replying to Pedro about the EVAL/EVALSHA thing. Sure,
scripting is a way to model things without having to implement them
and is a workaround, but in that case it is not a good workaround
since blocking operations are not callable
within scripts.
But even if it scripting could solve very well that problem, I think
this does not really answer your question about why BRPOPLPUSH can
wait for just one list, while BLPOP/BRPOP is able to wait for multiple
lists.
There are mainly two reasons:
1) There is no obvious semantic for BRPOPLPUSH listening to more than
a single list. I bet that if you implement it as "wait for N lists,
push against one" other users will complain that we need a "wait for N
lists, push against N lists", such as:
BLPOPRPUSH queue1 queue2 track1 track2
But even if we implement the above, is not a generalization of your
use case pushing against a single list.
So basically we are going to make the command either still too simple
to cover all the cases, or bloated.
2) In the "push against single list" information, how to store the
information about the originating list in the target list?
And if you can't have that, why it is different than putting that info
inside the list element pushed itself? And this brings us to the point
three, that is, you can do that already without making Redis more
complex.
3) Your use case is perfectly addressable just adding the information
about the message type in the data itself.
You want to do:
BRPOPLPUSH job_queue admin_queue tracking_list
So whatever the push is against the queue or the admin list you are
going to pollute the tracking list with admin messages.
So you can do that already as simple as:
BRPOPLPUSH job_and_admin_list tracking_list
And when you have to push simply use a single byte as a message prefix
that can be "A" for admin messages, or "J" for jobs.
Thanks for the discussion as it is interesting to review old design
decisions from time to time, but I'm still pretty sure that the
current simple approach is the best for us.
Salvatore
> --
> You received this message because you are subscribed to the Google Groups "Redis DB" group.
> To post to this group, send email to redi...@googlegroups.com.
> To unsubscribe from this group, send email to redis-db+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/redis-db?hl=en.
On Mon, Oct 10, 2011 at 9:25 AM, Suresh <suresh.m...@gmail.com> wrote:
> I too would like to see BRPOPLPUSH support multiple sources, but with
> multiple destinations, like
>
> BRPOPLPUSH src1 dst1 src2 dst2 ...
>
> My use case is as follows:
>
> Suppose I use Redis as a Q server with Lists for Q's, each Q has a
> name and is basically a Redis List storead against the name as Key.
>
> For the Q client I would like to use the safe queues pattern mentioned
> in the documentation for the command RPOPLPUSH.
>
> Now, if the client is to "listen" to multiple Q's on the same Redis
> server, I would require a socket connection for each Q because
> BRPOPLPUSH does not support multiple Keys.
Exactly. This solution so far solves all the requested use cases. Is
it that bad to open multiple connections? Honest question, really.
Most of those connections will be mostly idle, the server uses epolll
so the cost is pretty negligeble (I've personally seen a *Perl*-based
XMPP server using epoll with a bit over 150k connections work just
fine, used for a singalling/notification service)...
Isn't it simpler to just use multiple connections instead of making
the command semantics harder?
Bye,
On Mon, Oct 10, 2011 at 12:03 PM, Suresh <suresh.m...@gmail.com> wrote:
> Why is it that BRPOP takes multiple keys. Taking the consistency point
> of view BRPOP need not accept multiple keys either.
I disagree with the consistency argument here. BRPOP is single
direction: you remove stuff from lists, so the semantics is clear an
obvious.
BRPOPLPUSH is a two step command: remove from one, push into the
other. So I can think at least several semantics with multiple lists,
and I would not be able to say which one would be the correct, obvious
one:
* multiple sources, single destination;
* single source, multiple destinations;
* multiple sources, multiple destinations:
* map one-to-one: like having the current BRPOPLPUSH in parallel;
* any RPOPed element will be LPUSHed to all destinations.
Which one is the correct one?
So, no, there is no consistency argument to he had IMHO.
I would like to have a solution for multiple blocking actions in a
single TCP connection, but for now I think the multiple TCP
connections is the correct answer.
> The SUBSCRIBE command provided by Redis also allows listening for
> multiple channels on a socket.
True, but still very different use case, not a consistency issue.
> If we need to open a socket connection for each Q (List) in my
> previous example we need one thread per List in Java which would mean
> 100 threads for 100 Qs.
err... I'm sure you don't. Use one of the event loops for Java where
you can have a single thread serving all of your connection, I'm sure
that is possible.
> Of course there are ways to work around that
> using Non Blocking IO or polling.
Exactly.
> But my point is having BRPOPLPUSH
> support multiple sources and targets would make things easier for the
> client.
I don't disagree that a solution for blocking on several lists and
acting on the output would be easier for many, including myself who
use Redis as a task queue and had to work around this very same issue.
I'm just pointing that there are several semantics for such solution,
and personally I would not dare to say which one is the most obvious,
or most powerful, or most useful.
Best regards,
I agree that there are multiple options here, all of which could be
useful for different use cases. But, I disagree that it's so
difficult to choose which one is the obvious case for an extension to
BRPOPLPUSH.
To me it seems obvious that BRPOPLPUSH is semantically meant to be an
atomic combination of BRPOP + LPUSH. So, it should behave like
performing a BRPOP and then an LPUSH, except it should do it
atomically. BRPOP supports popping an element from the first
non-empty list argument, and therefore ideally BRPOPLPUSH would
support that as well. LPUSH only supports pushing an element into one
list, so BRPOPLPUSH should support only one destination. I suppose you
could also parse the command as B(locking) RPOP + LPUSH -- which would
describe the current behavior of the command. Any other behavior for
this command would be very confusing.
The other use cases are useful, but it seems to me that they would be
candidates for a new, different commands with different names.
> So, no, there is no consistency argument to he had IMHO.
>
> I would like to have a solution for multiple blocking actions in a
> single TCP connection, but for now I think the multiple TCP
> connections is the correct answer.
I don't think multiple TCP connections addresses my use case of trying
to pick the first available task out of a series of lists (with each
list representing a priority), and then placing it in a "running"
list, in an atomic fashion. Currently I am choosing to use a call to
BRPOP to pick the task, followed by a call to LPUSH to put in the
running queue, and accepting the risk that if my process crashes at
the wrong time it may not end up in the running queue. I don't have
the option to use multiple calls to BRPOPLPUSH with its current
behavior, because the command would block on the "high priority" list
and I wouldn't see incoming "regular priority" or "low priority"
tasks.
Thanks,
David Brewer
On Mon, Oct 10, 2011 at 7:13 PM, Felix Gallo <felix...@gmail.com> wrote:
> I originally thought scripting via lua was a bad design decision, but I've
> come around to it, and this is a perfect example of what it's for. You have
> a complex algorithm you'd like to execute atomically, and the existing
> command set doesn't seem suitable. You might give the scripting branch a
> try.
Not yet, if at all... Last I heard from Salvatore, Lua scripts cannot
block or call blocking Redis commands.
Bye,
... well, they block, but they block *everything* until they are done,
which wouldn't help in this situation.
Regards,
- Josiah
Where the regular blocking pop is unidirectional, BRPOPLPUSH is
bidirectional: it pops from a list and pushed onto another list. If
you look at the return value of the blocking pop, you'll see that it
both returns the list the value was popped from together with the
value itself. There is no way to preserve this information for
BRPOPLPUSH. A value is popped from one list and pushed to another. If
you think about a BRPOPLPUSH that pops from multiple lists to finally
push the value to another list, that information is lost. So, when
that information is lost anyway, why not push those values to a single
list to begin with?
Cheers,
Pieter
This is not going to be supports. To echo what Salvatore already said
in the pull request:
Where the regular blocking pop is unidirectional, BRPOPLPUSH is
bidirectional: it pops from a list and pushed onto another list. If
you look at the return value of the blocking pop, you'll see that it
both returns the list the value was popped from together with the
value itself. There is no way to preserve this information for
BRPOPLPUSH. A value is popped from one list and pushed to another. If
you think about a BRPOPLPUSH that pops from multiple lists to finally
push the value to another list, that information is lost. So, when
that information is lost anyway, why not push those values to a single
list to begin with?
2012/3/27 Pieter Noordhuis <pcnoo...@gmail.com>This is not going to be supports. To echo what Salvatore already said
in the pull request:
Where the regular blocking pop is unidirectional, BRPOPLPUSH is
bidirectional: it pops from a list and pushed onto another list. If
you look at the return value of the blocking pop, you'll see that it
both returns the list the value was popped from together with the
value itself. There is no way to preserve this information for
BRPOPLPUSH. A value is popped from one list and pushed to another. If
you think about a BRPOPLPUSH that pops from multiple lists to finally
push the value to another list, that information is lost. So, when
that information is lost anyway, why not push those values to a single
list to begin with?
Well, for a collection of job queues with multiple priorities, the simple reason is
that you need the information before you do the pop (the information is the order
of the lists you give to the command, i.e., the relative queue priorities) and you
don't need it afterwards, at least you can live without it.
But since BRPOPLPUSH does not currently support this, surely if the command
is extended to support multiple keys, the reply value could be extended for the
multiple key case to also return the list from which the value was popped just like
BRPOP? Hence, no information loss at all and backwards compatibility with the
single key case.