diff --git a/keydb.conf b/keydb.conf index 04f66f766..55594ef56 100644 --- a/keydb.conf +++ b/keydb.conf @@ -2070,3 +2070,12 @@ server-threads 2 # # By default KeyDB sets this to 2. replica-weighting-factor 2 + +# Should KeyDB make active attempts at balancing clients across threads? This can impact +# performance accepting new clients. By default this is enabled. If disabled there is still +# a best effort from the kernel to distribute across threads with SO_REUSEPORT but it will not +# be as fair. +# +# By default this is enabled +# +active-client-balancing yes \ No newline at end of file diff --git a/src/config.cpp b/src/config.cpp index efd7928bd..eaa1e2dd9 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -2779,6 +2779,7 @@ standardConfig configs[] = { createBoolConfig("replica-announced", NULL, MODIFIABLE_CONFIG, g_pserver->replica_announced, 1, NULL, NULL), createBoolConfig("enable-async-commands", NULL, MODIFIABLE_CONFIG, g_pserver->enable_async_commands, 1, NULL, NULL), createBoolConfig("multithread-load-enabled", NULL, MODIFIABLE_CONFIG, g_pserver->multithread_load_enabled, 0, NULL, NULL), + createBoolConfig("active-client-balancing", NULL, MODIFIABLE_CONFIG, g_pserver->active_client_balancing, 1, NULL, NULL), /* String Configs */ createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, g_pserver->acl_filename, "", NULL, NULL), diff --git a/src/networking.cpp b/src/networking.cpp index 8b1fb7e36..e8e929a20 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -1319,7 +1319,7 @@ void acceptOnThread(connection *conn, int flags, char *cip) int ielCur = ielFromEventLoop(serverTL->el); bool fBootLoad = (g_pserver->loading == LOADING_BOOT); - int ielTarget = 0; + int ielTarget = ielCur; if (fBootLoad) { ielTarget = IDX_EVENT_LOOP_MAIN; // During load only the main thread is active @@ -1330,7 +1330,7 @@ void acceptOnThread(connection *conn, int flags, char *cip) while (cserver.cthreads > 1 && ielTarget == IDX_EVENT_LOOP_MAIN) ielTarget = rand() % cserver.cthreads; } - else + else if (g_pserver->active_client_balancing) { // Cluster connections are more transient, so its not worth the cost to balance // we can trust that SO_REUSEPORT is doing its job of distributing connections @@ -1405,6 +1405,8 @@ void acceptTLSHandler(aeEventLoop *el, int fd, void *privdata, int mask) { serverLog(LL_VERBOSE,"Accepted %s:%d", cip, cport); acceptOnThread(connCreateAcceptedTLS(cfd, g_pserver->tls_auth_clients), 0, cip); + if (aeLockContention() >= 2) + break; } } diff --git a/src/server.cpp b/src/server.cpp index e3ed33beb..3cac24e97 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3772,7 +3772,7 @@ static void initNetworkingThread(int iel, int fReusePort) makeThreadKillable(); for (int j = 0; j < g_pserver->rgthreadvar[iel].tlsfd.count; j++) { - if (aeCreateFileEvent(g_pserver->rgthreadvar[iel].el, g_pserver->rgthreadvar[iel].tlsfd.fd[j], AE_READABLE, + if (aeCreateFileEvent(g_pserver->rgthreadvar[iel].el, g_pserver->rgthreadvar[iel].tlsfd.fd[j], AE_READABLE|AE_READ_THREADSAFE, acceptTLSHandler,NULL) == AE_ERR) { serverPanic( diff --git a/src/server.h b/src/server.h index e174d6902..0a7d7c1e6 100644 --- a/src/server.h +++ b/src/server.h @@ -2696,6 +2696,7 @@ struct redisServer { int enable_async_commands; int multithread_load_enabled = 0; + int active_client_balancing = 1; long long repl_batch_offStart = -1; long long repl_batch_idxStart = -1; diff --git a/src/tls.cpp b/src/tls.cpp index c2490bd56..9b3a0415c 100644 --- a/src/tls.cpp +++ b/src/tls.cpp @@ -491,6 +491,12 @@ bool tlsCheckAgainstAllowlist(const char * client){ return false; } +/* ASN1_STRING_get0_data was introduced in OPENSSL 1.1.1 + * use ASN1_STRING_data for older versions where it is not available */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define ASN1_STRING_get0_data ASN1_STRING_data +#endif + bool tlsValidateCertificateName(tls_connection* conn){ if (g_pserver->tls_allowlist.empty()) return true; // Empty list implies acceptance of all diff --git a/tests/unit/tls-name-validation.tcl b/tests/unit/tls-name-validation.tcl index f0569b028..f6f20b4f9 100644 --- a/tests/unit/tls-name-validation.tcl +++ b/tests/unit/tls-name-validation.tcl @@ -1,111 +1,120 @@ -test {TLS: Able to connect with no allowlist} { - start_server {tags {"tls"}} { - catch {r PING} e - assert_match {PONG} $e +# only run this test if tls is enabled +if {$::tls} { + package require tls + test {TLS: Able to connect with no allowlist} { + start_server {tags {"tls"}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect with allowlist '*'} { - start_server {tags {"tls"} overrides {tls-allowlist *}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect with allowlist '*'} { + start_server {tags {"tls"} overrides {tls-allowlist *}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect with matching CN} { - start_server {tags {"tls"} overrides {tls-allowlist client.keydb.dev}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect with matching CN} { + start_server {tags {"tls"} overrides {tls-allowlist client.keydb.dev}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect with matching SAN} { - start_server {tags {"tls"} overrides {tls-allowlist san1.keydb.dev}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect with matching SAN} { + start_server {tags {"tls"} overrides {tls-allowlist san1.keydb.dev}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect with matching CN with wildcard} { - start_server {tags {"tls"} overrides {tls-allowlist client*.dev}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect with matching CN with wildcard} { + start_server {tags {"tls"} overrides {tls-allowlist client*.dev}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect with matching SAN with wildcard} { - start_server {tags {"tls"} overrides {tls-allowlist san*.dev}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect with matching SAN with wildcard} { + start_server {tags {"tls"} overrides {tls-allowlist san*.dev}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect while with CN having a comprehensive list} { - start_server {tags {"tls"} overrides {tls-allowlist {dummy.keydb.dev client.keydb.dev other.keydb.dev}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect while with CN having a comprehensive list} { + start_server {tags {"tls"} overrides {tls-allowlist {dummy.keydb.dev client.keydb.dev other.keydb.dev}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect while with SAN having a comprehensive list} { - start_server {tags {"tls"} overrides {tls-allowlist {dummy.keydb.dev san2.keydb.dev other.keydb.dev}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect while with SAN having a comprehensive list} { + start_server {tags {"tls"} overrides {tls-allowlist {dummy.keydb.dev san2.keydb.dev other.keydb.dev}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect while with CN having a comprehensive list with wildcards} { - start_server {tags {"tls"} overrides {tls-allowlist {dummy.* client*.dev other.*}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect while with CN having a comprehensive list with wildcards} { + start_server {tags {"tls"} overrides {tls-allowlist {dummy.* client*.dev other.*}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to connect while with SAN having a comprehensive list with wildcards} { - start_server {tags {"tls"} overrides {tls-allowlist {dummy.* san*.dev other.*}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to connect while with SAN having a comprehensive list with wildcards} { + start_server {tags {"tls"} overrides {tls-allowlist {dummy.* san*.dev other.*}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Not matching CN or SAN rejected} { - start_server {tags {"tls"} overrides {tls-allowlist {client.keydb.dev}}} { - catch {set r2 [redis_client_tls -keyfile "$::tlsdir/client2.key" -certfile "$::tlsdir/client2.crt" -require 1 -cafile "$::tlsdir/ca.crt"]} e - assert_match {*I/O error reading reply*} $e + test {TLS: Not matching CN or SAN rejected} { + start_server {tags {"tls"} overrides {tls-allowlist {client.keydb.dev}}} { + catch {set r2 [redis_client_tls -keyfile "$::tlsdir/client2.key" -certfile "$::tlsdir/client2.crt" -require 1 -cafile "$::tlsdir/ca.crt"]} e + assert_match {*I/O error reading reply*} $e + } } -} -test {TLS: Able to match against DNS SAN} { - start_server {tags {"tls"} overrides {tls-allowlist {san1.keydb.dev}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to match against DNS SAN} { + start_server {tags {"tls"} overrides {tls-allowlist {san1.keydb.dev}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to match against email SAN} { - start_server {tags {"tls"} overrides {tls-allowlist {someone@keydb.dev}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to match against email SAN} { + start_server {tags {"tls"} overrides {tls-allowlist {someone@keydb.dev}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to match against IPv4 SAN} { - start_server {tags {"tls"} overrides {tls-allowlist {192.168.0.1}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to match against IPv4 SAN} { + start_server {tags {"tls"} overrides {tls-allowlist {192.168.0.1}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to match against IPv4 with a wildcard} { - start_server {tags {"tls"} overrides {tls-allowlist {192.*}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to match against IPv4 with a wildcard} { + start_server {tags {"tls"} overrides {tls-allowlist {192.*}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} -test {TLS: Able to match against URI SAN} { - start_server {tags {"tls"} overrides {tls-allowlist {https://keydb.dev}}} { - catch {r PING} e - assert_match {PONG} $e + test {TLS: Able to match against URI SAN} { + start_server {tags {"tls"} overrides {tls-allowlist {https://keydb.dev}}} { + catch {r PING} e + assert_match {PONG} $e + } } -} +} else { + start_server {} { + # just a dummy server so that the test doesn't panic if tls is disabled + # otherwise the test will try to bind to a server that just isn't there + } +} \ No newline at end of file