NSQ TCP协议规范-protocol_v2.go
通过本文你将学到:
- nsq中TCP协议是怎么处理的?
- nsq是怎么应对升级版本的(通过增加商量协议号,使升级比较方便)
- nsq使用的网络字节序是什么形式的?
- TCP通信中为啥要处理粘包?怎么处理粘包?NSQ中又是怎么处理粘包的?http是怎么处理粘包的?若传输的是UDP是否会出现粘包的现象?
一、协议描述
The NSQ protocol is simple enough that building clients should be trivial in any language. We provide official Go and Python client libraries.
An nsqd
process listens on a configurable TCP port that accepts client connections.
After connecting, a client must send a 4-byte “magic” identifier indicating what version of the protocol they will be communicating (upgrades made easy).
V2
(4-byte ASCII[space][space][V][2]
) a push based streaming protocol for consuming (and request/response for publishing)
After authenticating, the client can optionally send an IDENTIFY
command to provide custom metadata (like, for example, more descriptive identifiers) and negotiate features. In order to begin consuming messages, a client must SUB
to a channel.
Upon subscribing the client is placed in a RDY
state of 0. This means that no messages will be sent to the client. When a client is ready to receive messages it should send a command that updates its RDY
state to some # it is prepared to handle, say 100. Without any additional commands, 100 messages will be pushed to the client as they are available (each time decrementing the server-side RDY
count for that client).
The V2 protocol also features client heartbeats. Every 30s (default but configurable), nsqd
will send a _heartbeat_
response and expect a command in return. If the client is idle, send NOP
. After 2 unanswered _heartbeat_
responses, nsqd
will timeout and forcefully close a client connection that it has not heard from. The IDENTIFY
command may be used to change/disable this behavior.
NotesAnchor link for: notes
-
Unless stated otherwise, all binary sizes/integers on the wire are network byte order (ie. big endian)
-
Valid topic and channel names are characters
[.a-zA-Z0-9_-]
and1 <= length <= 64
(max length was32
prior tonsqd
0.2.28
)
二、消息的数据格式(Data Format):
Data is streamed asynchronously to the client and framed in order to support the various reply bodies, ie: (数据以异步方式流式传输到客户端并进行帧处理,以支持各种回复主体,即:)
[x][x][x][x][x][x][x][x][x][x][x][x]...
| (int32) || (int32) || (binary)
| 4-byte || 4-byte || N-byte
------------------------------------...
size frame type data
A client should expect one of the following frame types:
FrameTypeResponse int32 = 0
FrameTypeError int32 = 1
FrameTypeMessage int32 = 2
And finally, the message format:
[x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x]... | (int64) || || (hex string encoded in ASCII) || (binary) | 8-byte || || 16-byte || N-byte ------------------------------------------------------------------------------------------... nanosecond timestamp ^^ message ID message body (uint16) 2-byte attempts
三、协议中的命令
命令
|
作用
|
格式
|
返回结果
|
---|---|---|---|
IDENTIFY(识别,鉴定) |
Update client metadata on the server and negotiate features。 (更新服务器上的客户端元数据并协商功能) |
|
Success Response:
NOTE: if |
SUB |
Subscribe to a topic/channel |
|
Success response:
Error Responses:
|
PUB |
Publish a message to a topic:
|
|
Success Response:
Error Responses:
|
MPUB |
Publish multiple messages to a topic (atomically): |
|
Success Response:
Error Responses:
|
DPUB |
Publish a deferred message to a topic: |
|
Success Response:
Error Responses:
|
RDY |
Update NOTE: as of |
|
NOTE: there is no success response Error Responses:
|
FIN |
Finish a message (indicate successful processing) |
|
NOTE: there is no success response Error Responses:
|
REQ |
Re-queue a message (indicate failure to process) The re-queued message is placed at the tail of the queue, equivalent to having just published it, but for various implementation specific reasons that behavior should not be explicitly relied upon and may change in the future. Similarly, a message that is in-flight and times out behaves identically to an explicit ( 类似地,正在传输且超时的消息的行为与显式REQ相同。 ) |
|
NOTE: there is no success response Error Responses:
|
TOUCH |
Reset the timeout for an in-flight message NOTE: available in |
|
NOTE: there is no success response Error Responses:
|
CLS |
Cleanly close your connection (no more messages are sent) |
|
Success Responses:
Error Responses:
|
NOP(无实际用途) |
No-op |
|
NOTE: there is no response |
AUTH |
If the When |
|
Success Response: A JSON payload describing the authorized client’s identity, an optional URL and a count of permissions which were authorized.
Error Responses:
|
IDENTIFY命令协商的值:
字段名
|
解释
|
---|---|
client_id |
an identifier used to disambiguate this client (ie. something specific to the consumer) |
hostname |
the hostname where the client is deployed |
feature_negotiation |
( |
heartbeat_interval |
( Valid range:
Defaults to |
output_buffer_size |
( Valid range:
Defaults to |
output_buffer_timeout |
( Valid range:
Defaults to Warning: configuring clients with an extremely low ( This is due to the current implementation relying on Go timers which are maintained by the Go runtime in a priority queue. See the commit message in pull request #236 for more details. |
tls_v1 |
(
If the server supports TLS it will reply The client should begin the TLS handshake immediately after reading the The server will respond |
snappy |
(
The client should expect an additional, snappy compressed A client cannot enable both |
deflate |
(
The client should expect an additional, deflate compressed A client cannot enable both |
deflate_level |
(
Valid range: Higher values mean better compression but more CPU usage for nsqd. |
sample_rate |
( Valid range: Defaults to |
user_agent |
|
msg_timeout |
|
网络字节序:
Unless stated otherwise, all binary sizes/integers on the wire are network byte order (ie. big endian)
三、粘包问题
1 为什么会产生粘包?
参考:
https://segmentfault.com/a/1190000039691657
3. 若传输的是UDP是否会出现粘包的现象?
参考:
nsq 的协议文档地址: https://nsq.io/clients/tcp_protocol_spec.html