RESP3 is the third iteration of the Redis Serialization Protocol, and its most surprising feature is how it fundamentally shifts the client-server interaction from a purely request-response model to a more dynamic, event-driven architecture. The key to this shift lies in its enhanced support for client-side pushing of data and the introduction of attributes.
Let’s see this in action. Imagine a scenario where a server needs to push an update to multiple clients simultaneously without them explicitly asking for it. This is where RESP3’s PUSH command shines. A client, after establishing a connection and issuing HELLO with RESP3 enabled, can receive unsolicited messages.
# Client connects, sends HELLO
*2\r\n$5\r\nHELLO\r\n$3\r\n3\r\n
# Server responds with its capabilities and a PUSH channel
*3\r\n$10\r\nserver-hello\r\n$5\r\nredis\r\n*2\r\n$4\r\ncapa\r\n*0\r\n
# Server *unsolicited* PUSHes a message to the client
*3\r\n$4\r\nPUSH\r\n$6\r\nmychan\r\n$5\r\nhello\r\n
In this snippet, the client doesn’t ask for mychan. The server, recognizing this client is subscribed or has been designated to receive updates on mychan, simply pushes the message hello to it. This is a stark contrast to RESP2, where a client would have to periodically poll or use blocking operations like BLPOP to achieve similar (though less efficient) results.
The PUSH command is not just for simple string messages. It can carry complex data structures, mirroring the standard Redis data types. A server could push a list:
# Server PUSHes a list
*4\r\n$4\r\nPUSH\r\n$6\r\nupdates\r\n*3\r\n$5\r\napple\r\n$6\r\nbanana\r\n$5\r\ncherry\r\n
Or a map:
# Server PUSHes a map
*5\r\n$4\r\nPUSH\r\n$6\r\nconfig\r\n*2\r\n$3\r\nkey\r\n$5\r\nvalue\r\n*2\r\n$3\r\nopt\r\n$4\r\nONNN\r\n
This ability to push data asynchronously, without a preceding client request, is a game-changer for real-time applications. Think of live dashboards, notification systems, or collaborative editing tools. The server becomes a broadcaster, and clients are passive listeners waiting for relevant information.
Beyond PUSH, RESP3 introduces attributes. These are key-value pairs that can be attached to messages, providing metadata about the data being sent. Attributes allow for richer communication, enabling the server to convey context, instructions, or hints to the client.
Consider a READ command. In RESP2, you’d just get the value. In RESP3, the server can return the value along with attributes:
# Client READs a key
*2\r\n$4\r\nREAD\r\n$3\r\nmykey\r\n
# Server responds with value and attributes
*4\r\n$7\r\nresponse\r\n$11\r\nmyvalue-v1\r\n*2\r\n$7\r\nversion\r\n$1\r\n1\r\n*2\r\n$4\r\nflag\r\n$3\r\nnew\r\n
Here, the server not only returns myvalue-v1 for mykey but also tells the client that its version is 1 and that this data is new (flagged). This metadata can be used by the client to optimize its behavior, cache data more intelligently, or trigger specific actions. Attributes can be defined by the server and understood by the client, forming a mini-protocol within the RESP3 message.
The mechanism behind attributes involves a special RESP3 type, the map type, used to represent attribute-value pairs. These maps are distinguished from regular RESP3 maps by a specific header or context within the protocol stream. The HELLO command plays a crucial role here, as it’s where clients and servers negotiate support for attributes and their specific schemas.
The power of attributes becomes even more apparent when combined with PUSH. A server could push a configuration update and use attributes to specify which clients should apply it, or the urgency of the update.
# Server PUSHes a config update with attributes
*5\r\n$4\r\nPUSH\r\n$6\r\nconfig\r\n*2\r\n$5\r\nvalue\r\n$10\r\nnew-config\r\n*2\r\n$4\r\nlevel\r\n$3\r\nHIG\r\n
This message could be interpreted by the client as: "Push this config with the value new-config. This is a HIGH priority update."
The most profound implication of RESP3’s PUSH and attributes is the shift in architectural responsibility. In RESP2, the client was largely in control, dictating the flow of information. With RESP3, the server gains significant agency to proactively communicate with clients. This enables more sophisticated and efficient distributed systems where the server can manage and disseminate information dynamically, rather than waiting for explicit queries. Clients become more reactive, processing information as it arrives.
While RESP3 offers immense flexibility, it also introduces complexity. Clients must now handle unsolicited messages and parse attribute metadata, requiring more robust state management and event-handling logic. The HELLO command, which negotiates RESP3 features like PUSH and attribute support, is essential for establishing this richer communication channel. Without a proper HELLO handshake, clients will fall back to RESP2 behavior.
The next frontier in understanding RESP3 is how custom commands and modules can leverage these new features, particularly in defining and propagating their own attribute schemas for richer inter-component communication.