redis expire: What's the purpose of fast expire cycle - redis

I'm reading the source code of redis 3.2. To expire keys actively, redis server calls activeExpireCycle function in the event loop.
This function has a parameter type to specify the time limit. The type can be ACTIVE_EXPIRE_CYCLE_FAST (fast cycle) or ACTIVE_EXPIRE_CYCLE_SLOW (slow cycle). The time limit of fast cycle is hard coded to 1 millisecond (ACTIVE_EXPIRE_CYCLE_FAST_DURATION). The time limit of slow cycle takes 25% of serverCron period, which is 25 milliseconds by default. So first cycle takes much shorter time than slow cycle.
What's more, the fast cycle is called in beforSleep function, and the slow cycle is called in serverCron function. I drew a diagram about these two calls in event loop.
I can't figure out the purpose of fast cycle. Why doesn't redis leave all the active expiring work to slow cycle?
UPDATE: I changed the upper diagram. Function serverCron doesn't be called in every loop. Redis executes serverCron() per 100 milliseconds by default.

I found the comment in redis source code. Hope It's helpful for you(it will get more aggressive to avoid that too much memory is used by keys that can be removed from the keyspace):
// in https://github.com/redis/redis/blob/6.0/src/expire.c#L76
/* Try to expire a few timed out keys. The algorithm used is adaptive and
* will use few CPU cycles if there are few expiring keys, otherwise
* it will get more aggressive to avoid that too much memory is used by
* keys that can be removed from the keyspace.
*
* The function can perform more or less work, depending on the "type"
* argument. It can execute a "fast cycle" or a "slow cycle". The slow
* cycle is the main way we collect expired cycles: this happens with
* the "server.hz" frequency (usually 10 hertz).
*
* However the slow cycle can exit for timeout, since it used too much time.
* For this reason the function is also invoked to perform a fast cycle
* at every event loop cycle, in the beforeSleep() function. The fast cycle
* will try to perform less work, but will do it much more often.
*/

Related

How are reserved slots re-allocated between reservation/projects if idle slots are used?

The documentation on Introduction to Reservations: Idle Slots states that idle slots from reservations can be used by other reservations if required
By default, queries running in a reservation automatically use idle slots from other reservations. That means a job can always run as long as there's capacity. Idle capacity is immediately preemptible back to the original assigned reservation as needed, regardless of the priority of the query that needs the resources. This happens automatically in real time.
However, I'm wondering if this can have a negative effect on other reservations in a scenario where idle slots are used but are shortly after required by the "owning" reservation.
To be concrete I would like to understand if i can regard assigned slots as guarantee OR as a best effort.
Example:
Reserved slots: 100
Reservation A: 50 Slots
Reservation B: 50 Slots
"A" starts a query at 14:00:00 and the computation takes 300 seconds if 100 slots are used.
All slots are idle at the start of the query, thus all 100 slots are made available to A.
5 seconds later at 14:00:05 "B" starts a query that takes 30 seconds if 50 slots are used.
Note:
For the sake of simplicity let's assume that both queries have only excactly 1 stage and each computation unit ("job") in the stage takes the full time of the query. I.e. the stage is divided into 100 jobs and if a slot starts the computation it takes the full 300 seconds to finish successfully.
I'm fairly certain that on "multiple stages" or "shorter computation times" (e.g. if the computation can be broken down in 1000 jobs) GBQ would be smart enough to dynamically re-assign the freed up slot the reservation it belongs to.
Questions:
does "B" now have to wait until a slot in "A" finishes?
this would mean ~5 min waiting time
I'm not sure how "realistic" the 5 min are, but I feel this is an important variable since I wouldn't worry about a couple of seconds - but I would worry about a couple of minutes!
or might an already started computation of "A" also be killed mid-flight?
the docu Introduction to Reservations: Slot Scheduling seems to suggest something like this
The goal of the scheduler is to find a medium between being too aggressive with evicting running tasks (which results in wasting slot time) and being too lenient (which results in jobs with long running tasks getting a disproportionate share of the slot time).
Answer via Reddit
A stage may run for quite some time (minutes, even hours in really bad cases) but a stage is run by many workers. And most workers complete their work within a very short time, e.g. milliseconds or seconds. Hence rebalancing, I.e. reallocating slots from one job to another is very fast.
So if a rebalancing happens and a job loses a large part of slots, then it will run a lot slower. And the one that gains slots will run fast. And this change is quick.
So in the above example. As job B starts 5 seconds in, within a second or so it would have acquired most of its slots.
So bottom line:
a query is broken up into "a lot" of units of work
each unit of work finishes pretty fast
this give GBQ to opportunity to re-assign slots

Can timestamp be used in synchronization of processes having Race Condition?

I am wondering whether timestamp can be used to solve process synchronization problem, when race condition occurs? Below is an algorithm for entry as well as exit sections for every process who wants to enter in critical section. Entry section uses FCFS (First Come First Serve) technique to give access to critical section.
interested[N] is shared array of N integers where N is number of processes.
// This section executed when process enters critical section.
entry_section (int processNumber) {
interested [processNumber] = getCurrentTimeStamp (); // Gets the current timestamp.
index = findOldestProcessNumber (interested); // Find the process number with least timestamp.
while (index != processNumber);
}
// This section executed when process leaves critical section.
exit_section (int processNumber) {
interested [processNumber] = NULL;
}
According to me, this algorithm satisfies all conditions for synchronization, i.e., Mutual Exclusion, Progress, Bounded waiting and Portability. So, Am I correct?
Thanks for giving your time.
Short and sweet, here are the two issues with this approach.
All your processes are busy-waiting. This means that even though the process cannot enter the critical section, it still cannot rest. Which means that the os scheduler needs to constantly keep scheduling all interested processes even though they're not producing a meaningful output. This hurts performance and power consumption.
This is the big one. There is no guarantee that two processes will not have the same timestamp. It may be unlikely, but likelihood is not what you're looking for when you want to guarantee mutual exclusion to prevent a race condition.
Your code is just a sketch, but most likely it will not work in all the cases.
If there are no locks and all the functions are using non-atomic operations, there are no guarantees that the code will execute correctly. It is essentially the same as the first example here, except that you are using an array and assuming you don't need the atomicity since each process will only access its own element.
Let me try to come up with a counterexample.
Few minor clarifications.
As far as I understand the omitted portion of each process is running in a loop
while(!processExitCondition)
{
// some non-critical code
...
// your critical section as in the question
entry_section (int processNumber) {
interested [processNumber] = getCurrentTimeStamp (); // Gets the current timestamp.
index = findOldestProcessNumber (interested); // Find the process number with least timestamp.
while (index != processNumber);
}
// This section executed when process leaves critical section.
exit_section (int processNumber) {
interested [processNumber] = NULL;
}
// more non-critical code
...
}
It seems to me that the scheduling portion should be busy-waiting, constantly getting the oldest process as such:
while (findOldestProcessNumber (interested) != processNumber);
as otherwise, all your threads can immediately hang in an infinite while loop, except for the first one which will execute once and hang right after that.
Now your scheduling function findOldestProcessNumber (interested); has some finite execution time and if my assumption about the presence of a process outer loop while(!processExitCondition) correct, this execution time might happen to be slower than the execution of code inside, before or after the critical section. As a result, the completed process can get back into the interested array before while findOldestProcessNumber (interested); iterates over it and if getCurrentTimeStamp (); is low fidelity (say seconds) you can get two processes entering critical section at once. Imagine adding a long sleep into findOldestProcessNumber (interested); and it will be easier to see how that might happen.
You can say it is an artificial example, but the point is that there are no guarantees of how the processes will interleave with each other, so your synchronization relies on the assumption that certain portions of the code execute certain time "large" or "small" enough. This is just an attempt to fake an atomic operation using those assumptions.
You can come up with the counter-ideas to make it work. Say you can implement getCurrentTimeStamp () to return a unique timestamp for each caller. Either a simple atomic counter with the hardware guarantee that only one process can increment it or by internally using an atomic lock (mutex), it's own critical section and busy waiting for this lock to provide each caller process a distinct system clock value if you wish to have it as a real-time. But with a separate findOldestProcessNumber (interested) call I find it hard to think of a way to make it guaranteed. I can't claim it is impossible, but the more complicated it gets the more likely you are just hiding absence of the Mutual Exclusion guarantee.
So the simplest solution with a lock (mutex) is the best. In your code snippet add a mutex around your critical section with your current entry and exit code used only for the scheduling on the first-come-first-serve basis and mutex with giving you mutual exclusion guarantee.
If you want a lockless solution you can use Boost lockfree queue or implement a lockless ring buffer to push the processes number the queue in entry_section and then wait for it to get its turn, although performance can be worse as contr-intuitive as it seems.

Collect statistics on current traffic with Bro

I want to collect statistics on traffic every 10 seconds and the only tool that I found is connection_state_remove event,
event connection_state_remove(c: connection)
{
SumStats::observe( "traffic", [$str="all"] [$num=c$orig$num_bytes_ip] );
}
how to deal with those connections that did not removed by the end of this period. How to get statistics from them?
The events you're processing are independent of the time interval at which the SumStats framework reports statistics. First, you need to define what exactly are the statistics you care about — for example, you may want to count the number of connections for which Bro completes processing in a given time interval. Second, you need to define the time interval (in your case, 10 seconds) and how to process the statistical observations in the SumStats framework. This latter part is missing in your snippet: you're only making an observation but not telling the framework what to do with it.
The examples in the SumStats documentation are very close to what you're looking for.

Is there any option to use redis.expire more elastically?

I got a quick simple question,
Assume that if server receives 10 messages from user within 10 minutes, server sends a push email.
At first I thought it very simple using redis,
incr("foo"), expire("foo",60*10)
and in Java, handle the occurrence count like below
if(jedis.get("foo")>=10){sendEmail();jedis.del("foo");}
but imagine if user send one message at first minute and send 8 messages at 10th minute.
and the key expires, and user again send 3 messages in the next minute.
redis key will be created again with value 3 which will not trigger sendEmail() even though user send 11 messages in 2 minutes actually.
we're gonna use Redis and we don't want to put receive time values to redis.
is there any solution ?
So, there's 2 ways of solving this-- one to optimize on space and the other to optimize on speed (though really the speed difference should be marginal).
Optimizing for Space:
Keep up to 9 different counters; foo1 ... foo9. Basically, we'll keep one counter for each of the possible up to 9 different messages before we email the user, and let each one expire as it hits the 10 minute mark. This will work like a circular queue. Now do this (in Python for simplicity, assuming we have a connection to Redis called r):
new_created = False
for i in xrange(1,10):
var_name = 'foo%d' % i
if not (new_created or r.exists(var_name)):
r.set(var_name, 0)
r.expire(var_name, 600)
new_created = True
if not r.exists(var_name): continue
r.incr(var_name, 1)
if r.get(var_name) >= 10:
send_email(user)
r.del(var_name)
If you go with this approach, put the above logic in a Lua script instead of the example Python, and it should be quite fast. Since you'll at most be storing 9 counters per user, it'll also be quite space efficient.
Optimizing for speed:
Keep one Redis Sortet Set per user. Every time a user sends a message, add to his sorted set with a key equal to the timestamp and an arbitrary value. Then just do a ZCOUNT(now, now - 10 minutes) and send an email if that's greater than 10. Then ZREMRANGEBYSCORE(now - 10 minutes, inf). I know you said you didn't want to keep timestamps in Redis, but IMO this is a better solution, and you're going to have to hold some variant on timestamps somewhere no matter what.
Personally I'd go with the latter approach because the space differences are probably not that big, and the code can be done quickly in pure Redis, but up to you.

Triggering some code on every nth iteration of an NSTimer tick

I'm relatively new to coding, and wondering if there's a conventional way to have some code execute on every nth iteration of a loop (in this case, an NSTimer ticking).
I'm using a CADisplayLink and it updates however many times per second, 40, 50, whatever. If I want to execute some code on every, say, 500 of those loops, is there a standard way to do so? I assume I could put something together with the modulo operator and an integer, but is there a better / more normalized way that a new coder should know?
Extra clarity (though I'm sure this is a fairly common thing to do..): I have a timer that ticks 60 times per second, but I only want to do something with every 10th iteration. I already know that I can use a modulo and an integer to do this, but I want to know if there's any other convention for handling a situation like this.
Thanks in advance!
Establish a dedicated timer for the right interval.
Regardless of whether you're using NSTimer or CADisplayLink, timer calls can be coalesced and offset if they take too long. If you have a display link that takes 20 frames to run, it only gets called thrice every second (given the refresh interval is 60 frames per second). And if you have a timer set to run every second that at one instance takes a bit more than two and a half seconds to run, it will have "ate" its next iteration and will run the next iteration half a second too late.
Because of this, your timer can get out of sync if you only count timer calls. To do something repeatedly on an interval, having a timer set to that interval is the absolute best approximation.
Having a second timer like this is not a performance problem unless you do very many timers, in which case you should standardize on one tick timer and have events scheduled for specific points in time (which still isn't the same as counting previous iterations).