-
Notifications
You must be signed in to change notification settings - Fork 8
Make ValkeyClient go brrrr #158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
❌ Benchmark comparison failed with error ❌ Summary
New baseline 'pull_request' is WORSE than the 'main' baseline thresholds. Full Benchmark ComparisonComparing results between 'main' and 'pull_request'
ValkeyBenchmarksClient: GET benchmark metricsMalloc (total): results within specified thresholds, fold down for details.
Client: GET benchmark | parallel 20 | 20 concurrent connections metricsMalloc (total): results within specified thresholds, fold down for details.
Client: GET benchmark | parallel 50 | 20 concurrent connections metricsMalloc (total): results within specified thresholds, fold down for details.
Connection: GET benchmark metricsMalloc (total): results within specified thresholds, fold down for details.
HashSlot – {user}.whatever metricsMalloc (total): results within specified thresholds, fold down for details.
ValkeyCommandEncoder – Command with 7 words metricsMalloc (total): results within specified thresholds, fold down for details.
ValkeyCommandEncoder – Simple GET metricsMalloc (total): results within specified thresholds, fold down for details.
ValkeyCommandEncoder – Simple MGET 15 keys metricsMalloc (total): results within specified thresholds, fold down for details.
|
let future: EventLoopFuture<Channel> | ||
switch address.value { | ||
case .hostname(let host, let port): | ||
future = connect.connect(host: host, port: port) | ||
let socketAddress = try! SocketAddress(ipAddress: host, port: port) | ||
future = connect.connect(to: socketAddress) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can see why you did this, but can we keep it to another PR. It would be good to still support hostnames.
@usableFromInline | ||
let continuation: CheckedContinuation<T, any Error> | ||
@usableFromInline | ||
let lock: Mutex<RequestState> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You setup RequestState to be AtomicRepresentable, but are using a Mutex
defer { self.connectionPool.releaseConnection(connection) } | ||
|
||
return try await operation(connection) | ||
fatalError() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And how are you planning to support withConnection now that the connection request is ValkeyConnectionRequest<RESPToken>
self.lock.withLock { state in | ||
state = .onConnection(connection) | ||
} | ||
self.onConnection(connection, self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
complete and succeed seem to do different things for a successful result, which is the correct one?
Motivation
ConnectionPool offers a fast mode for single requests. For this to work we have to leave the paradigms of structured concurrency. It is important that the ConnectionRequest is synchronously fulfilled without any continuations.
Using the
withConnection
API, we have the following context switch scenario:withConnection
is reached -> acquire lock -> get next waiting request -> fulfill continuation for connectionwithConnection
closure is invokedsend
is invokedIf we don't use structured concurrency here, we can have the following flow:
Not a single context switch was necessary in this scenario.
Performance
In local testing I can see about a 20% improvement (throughput and wall clock time) for all the client benchmarks.
Changes
ValkeyConnectionRequest
, that uses unstructured callbacks for improved performance