Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
dfd3cc5f
Commit
dfd3cc5f
authored
Sep 24, 2018
by
artix
Browse files
Added basic support for clusters to redis-benchmark.
parent
563885d6
Changes
2
Expand all
Show whitespace changes
Inline
Side-by-side
src/crc16_slottable.h
0 → 100644
View file @
dfd3cc5f
This diff is collapsed.
Click to expand it.
src/redis-benchmark.c
View file @
dfd3cc5f
...
@@ -48,16 +48,19 @@
...
@@ -48,16 +48,19 @@
#include "adlist.h"
#include "adlist.h"
#include "zmalloc.h"
#include "zmalloc.h"
#include "atomicvar.h"
#include "atomicvar.h"
#include "crc16_slottable.h"
#define UNUSED(V) ((void) V)
#define UNUSED(V) ((void) V)
#define RANDPTR_INITIAL_SIZE 8
#define RANDPTR_INITIAL_SIZE 8
#define MAX_LATENCY_PRECISION 3
#define MAX_LATENCY_PRECISION 3
#define MAX_THREADS 16
#define MAX_THREADS 16
#define CLUSTER_SLOTS 16384
#define CLIENT_GET_EVENTLOOP(c) \
#define CLIENT_GET_EVENTLOOP(c) \
(c->thread_id >= 0 ? config.threads[c->thread_id]->el : config.el)
(c->thread_id >= 0 ? config.threads[c->thread_id]->el : config.el)
struct
benchmarkThread
;
struct
benchmarkThread
;
struct
clusterNode
;
static
struct
config
{
static
struct
config
{
aeEventLoop
*
el
;
aeEventLoop
*
el
;
...
@@ -92,6 +95,10 @@ static struct config {
...
@@ -92,6 +95,10 @@ static struct config {
int
precision
;
int
precision
;
int
num_threads
;
int
num_threads
;
struct
benchmarkThread
**
threads
;
struct
benchmarkThread
**
threads
;
int
cluster_mode
;
int
cluster_node_count
;
struct
clusterNode
**
cluster_nodes
;
struct
clusterNode
*
cluster_slots
[
CLUSTER_SLOTS
];
/* Thread mutexes to be used as fallbacks by atomicvar.h */
/* Thread mutexes to be used as fallbacks by atomicvar.h */
pthread_mutex_t
requests_issued_mutex
;
pthread_mutex_t
requests_issued_mutex
;
pthread_mutex_t
requests_finished_mutex
;
pthread_mutex_t
requests_finished_mutex
;
...
@@ -123,6 +130,23 @@ typedef struct benchmarkThread {
...
@@ -123,6 +130,23 @@ typedef struct benchmarkThread {
aeEventLoop
*
el
;
aeEventLoop
*
el
;
}
benchmarkThread
;
}
benchmarkThread
;
/* Cluster. */
typedef
struct
clusterNode
{
char
*
ip
;
int
port
;
sds
name
;
int
flags
;
sds
replicate
;
/* Master ID if node is a slave */
uint8_t
slots
[
CLUSTER_SLOTS
];
int
slots_count
;
int
replicas_count
;
sds
*
migrating
;
/* An array of sds where even strings are slots and odd
* strings are the destination node IDs. */
sds
*
importing
;
/* An array of sds where even strings are slots and odd
* strings are the source node IDs. */
int
migrating_count
;
/* Length of the migrating array (migrating slots*2) */
int
importing_count
;
/* Length of the importing array (importing slots*2) */
}
clusterNode
;
/* Prototypes */
/* Prototypes */
static
void
writeHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
static
void
writeHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
...
@@ -131,6 +155,7 @@ static benchmarkThread *createBenchmarkThread(int index);
...
@@ -131,6 +155,7 @@ static benchmarkThread *createBenchmarkThread(int index);
static
void
freeBenchmarkThread
(
benchmarkThread
*
thread
);
static
void
freeBenchmarkThread
(
benchmarkThread
*
thread
);
static
void
freeBenchmarkThreads
();
static
void
freeBenchmarkThreads
();
static
void
*
execBenchmarkThread
(
void
*
ptr
);
static
void
*
execBenchmarkThread
(
void
*
ptr
);
static
clusterNode
*
createClusterNode
(
char
*
ip
,
int
port
);
int
showThroughput
(
struct
aeEventLoop
*
eventLoop
,
long
long
id
,
int
showThroughput
(
struct
aeEventLoop
*
eventLoop
,
long
long
id
,
void
*
clientData
);
void
*
clientData
);
...
@@ -373,10 +398,22 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
...
@@ -373,10 +398,22 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
* Even when cloning another client, prefix commands are applied if needed.*/
* Even when cloning another client, prefix commands are applied if needed.*/
static
client
createClient
(
char
*
cmd
,
size_t
len
,
client
from
,
int
thread_id
)
{
static
client
createClient
(
char
*
cmd
,
size_t
len
,
client
from
,
int
thread_id
)
{
int
j
;
int
j
;
int
is_cluster_client
=
(
config
.
cluster_mode
&&
thread_id
>=
0
);
client
c
=
zmalloc
(
sizeof
(
struct
_client
));
client
c
=
zmalloc
(
sizeof
(
struct
_client
));
if
(
config
.
hostsocket
==
NULL
)
{
if
(
config
.
hostsocket
==
NULL
||
is_cluster_client
)
{
c
->
context
=
redisConnectNonBlock
(
config
.
hostip
,
config
.
hostport
);
const
char
*
ip
;
int
port
;
if
(
!
is_cluster_client
)
{
ip
=
config
.
hostip
;
port
=
config
.
hostport
;
}
else
{
clusterNode
*
node
=
config
.
cluster_nodes
[
thread_id
];
if
(
node
==
NULL
)
exit
(
1
);
ip
=
(
const
char
*
)
node
->
ip
;
port
=
node
->
port
;
}
c
->
context
=
redisConnectNonBlock
(
ip
,
port
);
}
else
{
}
else
{
c
->
context
=
redisConnectUnixNonBlock
(
config
.
hostsocket
);
c
->
context
=
redisConnectUnixNonBlock
(
config
.
hostsocket
);
}
}
...
@@ -621,6 +658,220 @@ static void *execBenchmarkThread(void *ptr) {
...
@@ -621,6 +658,220 @@ static void *execBenchmarkThread(void *ptr) {
return
NULL
;
return
NULL
;
}
}
static
clusterNode
*
createClusterNode
(
char
*
ip
,
int
port
)
{
clusterNode
*
node
=
zmalloc
(
sizeof
(
*
node
));
if
(
!
node
)
return
NULL
;
node
->
ip
=
ip
;
node
->
port
=
port
;
node
->
name
=
NULL
;
node
->
flags
=
0
;
node
->
replicate
=
NULL
;
node
->
replicas_count
=
0
;
memset
(
node
->
slots
,
0
,
sizeof
(
node
->
slots
));
node
->
slots_count
=
0
;
node
->
migrating
=
NULL
;
node
->
importing
=
NULL
;
node
->
migrating_count
=
0
;
node
->
importing_count
=
0
;
return
node
;
}
static
void
freeClusterNode
(
clusterNode
*
node
)
{
int
i
;
if
(
node
->
name
)
sdsfree
(
node
->
name
);
if
(
node
->
replicate
)
sdsfree
(
node
->
replicate
);
if
(
node
->
migrating
!=
NULL
)
{
for
(
i
=
0
;
i
<
node
->
migrating_count
;
i
++
)
sdsfree
(
node
->
migrating
[
i
]);
zfree
(
node
->
migrating
);
}
if
(
node
->
importing
!=
NULL
)
{
for
(
i
=
0
;
i
<
node
->
importing_count
;
i
++
)
sdsfree
(
node
->
importing
[
i
]);
zfree
(
node
->
importing
);
}
zfree
(
node
);
}
static
void
freeClusterNodes
()
{
int
i
=
0
;
for
(;
i
<
config
.
cluster_node_count
;
i
++
)
{
clusterNode
*
n
=
config
.
cluster_nodes
[
i
];
if
(
n
)
freeClusterNode
(
n
);
}
zfree
(
config
.
cluster_nodes
);
}
static
clusterNode
**
addClusterNode
(
clusterNode
*
node
)
{
int
count
=
config
.
cluster_node_count
+
1
;
config
.
cluster_nodes
=
zrealloc
(
config
.
cluster_nodes
,
count
*
sizeof
(
*
node
));
if
(
!
config
.
cluster_nodes
)
return
NULL
;
config
.
cluster_nodes
[
config
.
cluster_node_count
++
]
=
node
;
return
config
.
cluster_nodes
;
}
static
int
fetchClusterConfiguration
()
{
int
success
=
1
;
redisContext
*
ctx
=
NULL
;
redisReply
*
reply
=
NULL
;
if
(
config
.
hostsocket
==
NULL
)
ctx
=
redisConnect
(
config
.
hostip
,
config
.
hostport
);
else
ctx
=
redisConnectUnix
(
config
.
hostsocket
);
if
(
ctx
->
err
)
{
fprintf
(
stderr
,
"Could not connect to Redis at "
);
if
(
config
.
hostsocket
==
NULL
)
{
fprintf
(
stderr
,
"%s:%d: %s
\n
"
,
config
.
hostip
,
config
.
hostport
,
ctx
->
errstr
);
}
else
fprintf
(
stderr
,
"%s: %s
\n
"
,
config
.
hostsocket
,
ctx
->
errstr
);
exit
(
1
);
}
clusterNode
*
firstNode
=
createClusterNode
((
char
*
)
config
.
hostip
,
config
.
hostport
);
if
(
!
firstNode
)
{
success
=
0
;
goto
cleanup
;}
reply
=
redisCommand
(
ctx
,
"CLUSTER NODES"
);
success
=
(
reply
!=
NULL
);
if
(
!
success
)
goto
cleanup
;
success
=
(
reply
->
type
!=
REDIS_REPLY_ERROR
);
if
(
!
success
)
{
fprintf
(
stderr
,
"Cluster node %s:%d replied with error:
\n
%s
\n
"
,
config
.
hostip
,
config
.
hostport
,
reply
->
str
);
goto
cleanup
;
}
char
*
lines
=
reply
->
str
,
*
p
,
*
line
;
while
((
p
=
strstr
(
lines
,
"
\n
"
))
!=
NULL
)
{
*
p
=
'\0'
;
line
=
lines
;
lines
=
p
+
1
;
char
*
name
=
NULL
,
*
addr
=
NULL
,
*
flags
=
NULL
,
*
master_id
=
NULL
;
int
i
=
0
;
while
((
p
=
strchr
(
line
,
' '
))
!=
NULL
)
{
*
p
=
'\0'
;
char
*
token
=
line
;
line
=
p
+
1
;
switch
(
i
++
){
case
0
:
name
=
token
;
break
;
case
1
:
addr
=
token
;
break
;
case
2
:
flags
=
token
;
break
;
case
3
:
master_id
=
token
;
break
;
}
if
(
i
==
8
)
break
;
// Slots
}
if
(
!
flags
)
{
fprintf
(
stderr
,
"Invalid CLUSTER NODES reply: missing flags.
\n
"
);
success
=
0
;
goto
cleanup
;
}
int
myself
=
(
strstr
(
flags
,
"myself"
)
!=
NULL
);
int
is_replica
=
(
strstr
(
flags
,
"slave"
)
!=
NULL
||
(
master_id
!=
NULL
&&
master_id
[
0
]
!=
'-'
));
if
(
is_replica
)
continue
;
clusterNode
*
node
=
NULL
;
if
(
myself
)
{
node
=
firstNode
;
}
else
{
if
(
addr
==
NULL
)
{
fprintf
(
stderr
,
"Invalid CLUSTER NODES reply: missing addr.
\n
"
);
success
=
0
;
goto
cleanup
;
}
char
*
paddr
=
strchr
(
addr
,
':'
);
if
(
paddr
==
NULL
)
{
success
=
0
;
goto
cleanup
;
}
*
paddr
=
'\0'
;
char
*
ip
=
addr
;
addr
=
paddr
+
1
;
/* If internal bus is specified, then just drop it. */
if
((
paddr
=
strchr
(
addr
,
'@'
))
!=
NULL
)
*
paddr
=
'\0'
;
int
port
=
atoi
(
addr
);
node
=
createClusterNode
(
ip
,
port
);
}
if
(
node
==
NULL
)
{
success
=
0
;
goto
cleanup
;
}
node
->
name
=
sdsnew
(
name
);
if
(
!
addClusterNode
(
node
))
{
success
=
0
;
goto
cleanup
;
}
if
(
i
==
8
)
{
int
remaining
=
strlen
(
line
);
while
(
remaining
>
0
)
{
p
=
strchr
(
line
,
' '
);
if
(
p
==
NULL
)
p
=
line
+
remaining
;
remaining
-=
(
p
-
line
);
char
*
slotsdef
=
line
;
*
p
=
'\0'
;
if
(
remaining
)
{
line
=
p
+
1
;
remaining
--
;
}
else
line
=
p
;
char
*
dash
=
NULL
;
if
(
slotsdef
[
0
]
==
'['
)
{
slotsdef
++
;
if
((
p
=
strstr
(
slotsdef
,
"->-"
)))
{
// Migrating
*
p
=
'\0'
;
p
+=
3
;
char
*
closing_bracket
=
strchr
(
p
,
']'
);
if
(
closing_bracket
)
*
closing_bracket
=
'\0'
;
sds
slot
=
sdsnew
(
slotsdef
);
sds
dst
=
sdsnew
(
p
);
node
->
migrating_count
+=
2
;
node
->
migrating
=
zrealloc
(
node
->
migrating
,
(
node
->
migrating_count
*
sizeof
(
sds
)));
node
->
migrating
[
node
->
migrating_count
-
2
]
=
slot
;
node
->
migrating
[
node
->
migrating_count
-
1
]
=
dst
;
}
else
if
((
p
=
strstr
(
slotsdef
,
"-<-"
)))
{
//Importing
*
p
=
'\0'
;
p
+=
3
;
char
*
closing_bracket
=
strchr
(
p
,
']'
);
if
(
closing_bracket
)
*
closing_bracket
=
'\0'
;
sds
slot
=
sdsnew
(
slotsdef
);
sds
src
=
sdsnew
(
p
);
node
->
importing_count
+=
2
;
node
->
importing
=
zrealloc
(
node
->
importing
,
(
node
->
importing_count
*
sizeof
(
sds
)));
node
->
importing
[
node
->
importing_count
-
2
]
=
slot
;
node
->
importing
[
node
->
importing_count
-
1
]
=
src
;
}
}
else
if
((
dash
=
strchr
(
slotsdef
,
'-'
))
!=
NULL
)
{
p
=
dash
;
int
start
,
stop
;
*
p
=
'\0'
;
start
=
atoi
(
slotsdef
);
stop
=
atoi
(
p
+
1
);
node
->
slots_count
+=
(
stop
-
(
start
-
1
));
while
(
start
<=
stop
)
{
int
slot
=
start
++
;
node
->
slots
[
slot
]
=
1
;
config
.
cluster_slots
[
slot
]
=
node
;
}
}
else
if
(
p
>
slotsdef
)
{
int
slot
=
atoi
(
slotsdef
);
node
->
slots
[
slot
]
=
1
;
node
->
slots_count
++
;
config
.
cluster_slots
[
slot
]
=
node
;
}
}
}
}
cleanup:
if
(
ctx
)
redisFree
(
ctx
);
if
(
!
success
)
{
if
(
config
.
cluster_nodes
)
freeClusterNodes
();
}
if
(
reply
)
freeReplyObject
(
reply
);
return
success
;
}
/* Returns number of consumed options. */
/* Returns number of consumed options. */
int
parseOptions
(
int
argc
,
const
char
**
argv
)
{
int
parseOptions
(
int
argc
,
const
char
**
argv
)
{
int
i
;
int
i
;
...
@@ -704,6 +955,8 @@ int parseOptions(int argc, const char **argv) {
...
@@ -704,6 +955,8 @@ int parseOptions(int argc, const char **argv) {
MAX_THREADS
);
MAX_THREADS
);
config
.
num_threads
=
MAX_THREADS
;
config
.
num_threads
=
MAX_THREADS
;
}
else
if
(
config
.
num_threads
<
0
)
config
.
num_threads
=
0
;
}
else
if
(
config
.
num_threads
<
0
)
config
.
num_threads
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--cluster"
))
{
config
.
cluster_mode
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--help"
))
{
}
else
if
(
!
strcmp
(
argv
[
i
],
"--help"
))
{
exit_status
=
0
;
exit_status
=
0
;
goto
usage
;
goto
usage
;
...
@@ -850,12 +1103,48 @@ int main(int argc, const char **argv) {
...
@@ -850,12 +1103,48 @@ int main(int argc, const char **argv) {
config
.
precision
=
1
;
config
.
precision
=
1
;
config
.
num_threads
=
0
;
config
.
num_threads
=
0
;
config
.
threads
=
NULL
;
config
.
threads
=
NULL
;
config
.
cluster_mode
=
0
;
config
.
cluster_node_count
=
0
;
config
.
cluster_nodes
=
NULL
;
memset
(
config
.
cluster_slots
,
0
,
sizeof
(
config
.
cluster_slots
));
i
=
parseOptions
(
argc
,
argv
);
i
=
parseOptions
(
argc
,
argv
);
argc
-=
i
;
argc
-=
i
;
argv
+=
i
;
argv
+=
i
;
config
.
latency
=
zmalloc
(
sizeof
(
long
long
)
*
config
.
requests
);
config
.
latency
=
zmalloc
(
sizeof
(
long
long
)
*
config
.
requests
);
if
(
config
.
cluster_mode
)
{
/* Fetch cluster configuration. */
if
(
!
fetchClusterConfiguration
()
||
!
config
.
cluster_nodes
)
{
if
(
!
config
.
hostsocket
)
{
fprintf
(
stderr
,
"Failed to fetch cluster configuration from "
"%s:%d
\n
"
,
config
.
hostip
,
config
.
hostport
);
}
else
{
fprintf
(
stderr
,
"Failed to fetch cluster configuration from "
"%s
\n
"
,
config
.
hostsocket
);
}
exit
(
1
);
}
if
(
config
.
cluster_node_count
<=
1
)
{
fprintf
(
stderr
,
"Invalid cluster: %d node(s).
\n
"
,
config
.
cluster_node_count
);
exit
(
1
);
}
printf
(
"Cluster has %d master nodes:
\n\n
"
,
config
.
cluster_node_count
);
int
i
=
0
;
for
(;
i
<
config
.
cluster_node_count
;
i
++
)
{
clusterNode
*
node
=
config
.
cluster_nodes
[
i
];
if
(
!
node
)
{
fprintf
(
stderr
,
"Invalid cluster node #%d
\n
"
,
i
);
exit
(
1
);
}
if
(
node
->
name
)
printf
(
"%s "
,
node
->
name
);
printf
(
"%s:%d
\n
"
,
node
->
ip
,
node
->
port
);
}
config
.
num_threads
=
config
.
cluster_node_count
;
}
if
(
config
.
num_threads
>
0
)
{
if
(
config
.
num_threads
>
0
)
{
pthread_mutex_init
(
&
(
config
.
requests_issued_mutex
),
NULL
);
pthread_mutex_init
(
&
(
config
.
requests_issued_mutex
),
NULL
);
pthread_mutex_init
(
&
(
config
.
requests_finished_mutex
),
NULL
);
pthread_mutex_init
(
&
(
config
.
requests_finished_mutex
),
NULL
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment