serverCron() frequency is now a runtime parameter (was REDIS_HZ).

REDIS_HZ is the frequency our serverCron() function is called with.
A more frequent call to this function results into less latency when the
server is trying to handle very expansive background operations like
mass expires of a lot of keys at the same time.

Redis 2.4 used to have an HZ of 10. This was good enough with almost
every setup, but the incremental key expiration algorithm was working a
bit better under *extreme* pressure when HZ was set to 100 for Redis
2.6.

However for most users a latency spike of 30 milliseconds when million
of keys are expiring at the same time is acceptable, on the other hand a
default HZ of 100 in Redis 2.6 was causing idle instances to use some
CPU time compared to Redis 2.4. The CPU usage was in the order of 0.3%
for an idle instance, however this is a shame as more energy is consumed
by the server, if not important resources.

This commit introduces HZ as a runtime parameter, that can be queried by
INFO or CONFIG GET, and can be modified with CONFIG SET. At the same
time the default frequency is set back to 10.

In this way we default to a sane value of 10, but allows users to
easily switch to values up to 500 for near real-time applications if
needed and if they are willing to pay this small CPU usage penalty.
This commit is contained in:
antirez
2012-12-14 17:10:40 +01:00
parent 5207c03c49
commit a6d117b6c0
6 changed files with 47 additions and 13 deletions

View File

@ -627,9 +627,9 @@ void activeExpireCycle(void) {
/* We can use at max REDIS_EXPIRELOOKUPS_TIME_PERC percentage of CPU time
* per iteration. Since this function gets called with a frequency of
* REDIS_HZ times per second, the following is the max amount of
* server.hz times per second, the following is the max amount of
* microseconds we can spend in this function. */
timelimit = 1000000*REDIS_EXPIRELOOKUPS_TIME_PERC/REDIS_HZ/100;
timelimit = 1000000*REDIS_EXPIRELOOKUPS_TIME_PERC/server.hz/100;
if (timelimit <= 0) timelimit = 1;
for (j = 0; j < server.dbnum; j++) {
@ -762,13 +762,13 @@ int clientsCronResizeQueryBuffer(redisClient *c) {
}
void clientsCron(void) {
/* Make sure to process at least 1/(REDIS_HZ*10) of clients per call.
* Since this function is called REDIS_HZ times per second we are sure that
/* Make sure to process at least 1/(server.hz*10) of clients per call.
* Since this function is called server.hz times per second we are sure that
* in the worst case we process all the clients in 10 seconds.
* In normal conditions (a reasonable number of clients) we process
* all the clients in a shorter time. */
int numclients = listLength(server.clients);
int iterations = numclients/(REDIS_HZ*10);
int iterations = numclients/(server.hz*10);
if (iterations < 50)
iterations = (numclients < 50) ? numclients : 50;
@ -790,7 +790,7 @@ void clientsCron(void) {
}
}
/* This is our timer interrupt, called REDIS_HZ times per second.
/* This is our timer interrupt, called server.hz times per second.
* Here is where we do a number of things that need to be done asynchronously.
* For instance:
*
@ -804,7 +804,7 @@ void clientsCron(void) {
* - Replication reconnection.
* - Many more...
*
* Everything directly called here will be called REDIS_HZ times per second,
* Everything directly called here will be called server.hz times per second,
* so in order to throttle execution of things we want to do less frequently
* a macro is used: run_with_period(milliseconds) { .... }
*/
@ -976,7 +976,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
}
server.cronloops++;
return 1000/REDIS_HZ;
return 1000/server.hz;
}
/* This function gets called every time Redis is entering the
@ -1082,6 +1082,7 @@ void createSharedObjects(void) {
void initServerConfig() {
getRandomHexChars(server.runid,REDIS_RUN_ID_SIZE);
server.hz = REDIS_DEFAULT_HZ;
server.runid[REDIS_RUN_ID_SIZE] = '\0';
server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
server.port = REDIS_SERVERPORT;
@ -1879,6 +1880,7 @@ sds genRedisInfoString(char *section) {
"tcp_port:%d\r\n"
"uptime_in_seconds:%ld\r\n"
"uptime_in_days:%ld\r\n"
"hz:%d\r\n"
"lru_clock:%ld\r\n",
REDIS_VERSION,
redisGitSHA1(),
@ -1898,6 +1900,7 @@ sds genRedisInfoString(char *section) {
server.port,
uptime,
uptime/(3600*24),
server.hz,
(unsigned long) server.lruclock);
}