Client Design
Client for Shunya KV in DPDK Mode
Shunya KV needs a smart client to operate at its full potential. Shunya KV exposes a single port for the clients to connect and internally distributes the connections to different shards. A client can choose to not be smart in managing connections and it will work fine but latency and throughput will take a hit.
Why ShunyaKV Needs a Smart Client
ShunyaKV exposes a single TCP port to clients. Internally, each CPU shard (core) listens on its own RSS queue. The NIC performs RSS hashing and distributes incoming packets uniformly across queues.
However:
- RSS hashing is flow-based1
- Key ownership is key-hash-based
- These two hashes are completely independent
The difference between how POSIX stack handles packet and how DPDK stack handles packet is illustrated by the diagrams below.
Packet flow via POSIX Stack
sequenceDiagram
participant C as Client
participant P as POSIX Stack
participant K as Kernel Socket Lookup
participant S as Target Process
C->>P: Send packet to Server IP:Port
P->>K: Check 5-tuple mapping
K-->>P: Determine owner for the port
P->>S: Forward packet to target process
S-->>C: Process request / send response
Packet flow via DPDK stack
flowchart LR
C[Client]
N[NIC]
H[RSS Logic<br/>Compute hash from 5-tuple<br/>Use indirection table]
C -->|Send packet to Server IP:Port| N
N --> H
subgraph R[RSS Queues]
direction TB
Q0[RSS Queue 0 / CPU Core 0]
Q1[RSS Queue 1 / CPU Core 1]
Q2[RSS Queue 2 / CPU Core 2]
QN[RSS Queue N / CPU Core N]
end
H -->|Hash selects queue| Q0
H -->|Hash selects queue| Q1
H -->|Hash selects queue| Q2
H -->|Hash selects queue| QN
As a result, RSS provides fairness, not correctness
Let’s assume:
- The DB node has N CPU shards
- RSS distributes traffic uniformly across N shards, so each shard owns ~1/N of the keyspace
For any given key:
- It is owned by exactly 1 shard
- RSS will send the packet to a random shard (uniform distribution)
Probability of correct placement
$P(\text{Direct Hit}) = \frac{1}{n}$
$P(\text{Hop}) = \frac{n-1}{n}$
So most requests will land on the wrong shard and require an internal submit_to() (SMP hop).
What This Looks Like in Practice
| CPU shard count | P(not landing on owner shard) | % Reroute |
|---|---|---|
| 4 | 0.75 | 75% |
| 8 | 0.87 | 87% |
| 12 | 0.91 | 91% |
| 22 | 0.95 | 95% |
| 48 | 0.97 | 97% |
As shard count increases:
- Direct-hit probability decreases
- Cross-core forwarding increases
- Cache locality degrades
- Latency variance increases
- Inter-core traffic increases
At 48 shards, ~98% of requests require a hop. That’s massive !!!
The Performance Consequence
Without a smart client:
- ~90–98% of requests require submit_to()
- Each request incurs:
- Cross-core queueing
- Additional scheduling
- Extra context overhead
This directly increases:
- p99 latency
- tail amplification
- CPU overhead
- cross-shard contention
What must a client do to fix this?
To avoid cross-shard forwarding and achieve maximum locality, a ShunyaKV client must implement shard-aware routing.
-
Establish Initial Connection
-
Connect to the server using the advertised port.
- Once connected, send: NODE_INFO2
- The server responds with the key range owned by the shard handling that connection.
- Discover All Shards
- Continue opening new connections to the same port.
-
For each connection:
- Issue NODE_INFO
- Record the key range returned
- Repeat until connections covering all CPU shards are obtained.
⚠️ Important:
-
Use timeouts for connection attempts.
- If some shards are not discovered, continue operating.
- Requests sent to the wrong shard will still be honored (with internal forwarding), though at reduced efficiency.
- Maintain Shard-Aware Routing
- The client should:
- Maintain a mapping of key-range → connection pool
- Hash the key client-side
- Select the correct shard pool
- Use:
- Round-robin
- Weighted round-robin
- Or custom load strategy
-
Connection pooling per shard is recommended for parallelism.
-
Graceful Degradation
-
The system continues functioning.
- Internal forwarding ensures correctness.
- Only latency and throughput are affected.
Summary
A smart client must:
- Discover shard topology
- Map keys to shard ranges
- Maintain per-shard connection pools
- Route requests deterministically
Client implementation details are intentionally flexible.
[^1][^2]
[^1]: RSS hashing operates at the flow level (IP/port 5-tuple) and cannot align with ShunyaKV’s application-level key ownership hashing.
[^2]: Refer to documentation to understand the various parameters NODE_INFO takes.