WL#13442: X Protocol - zstd compression
Motivation
WL#9252 added deflate
and lz4
compression support to xprotocol.
WL#12039 added zstd
support to the Classic protocol, which currently supports deflate
and zstd
compression algorithms.
deflate
has a good compression ration, but is low throughput.lz4
has high throughput, but low compression ratiozstd
how good throughput, and good compression ratio.
Adding zstd
compression to the xprotocol gives the user a good choice over
saturated networks with lower CPU costs then deflate
, but higher compression ratios than lz4
.
Results comparison
performance:
Average - Degradation Algorithm Test Style DEFLATE LZ4 ZSTD OLTP_RO GROUP -24,68% -2,06% -10% (TBD) POINT_SELECT GROUP -7,12% -4,03% -12% (TBD) SELECT_RANGES GROUP -42,66% +3,23% -10% (TBD) Protocol compression ratio:
Average - Ratio Algorithm Test Style DEFLATE LZ4 ZSTD OLTP_RO GROUP 19.6 8.7 27.9 POINT_SELECT GROUP 5.4 1.7 4.8 SELECT_RANGES GROUP 23.3 11 37.9
Goal
Give user a possibility to use "modern" compression algorithm, which performance is better than deflate and compression ratio is much better than lz4.
Functional requirements
- FR1
- a client MUST be able to query the ZSTD compression algorithms if server supports it
an admin MUST be able to disable/enable ZSTD compression algorithms on the server
a client MUST be able to choose ZSTD compression algorithm
in capability negotiation phase (excluding reseted sessions)server MUST enable ZSTD compression after successful authentication in case when ZSTD compression algorithm was set successful
a server MUST allow multiple changes to compression algorithm in capability negotiation phase (last change is used)
server MUST return an error when client tries to set unsupported compression algorithm
- FR2
- a client MUST be able to control how and if uncompressed messages may be combined into a compressed message.
- FR3
- a client MUST be able to enable compression on connection after successful authentication in case when compression algorithm was set successful
client and server MUST manage a client-incoming compression context
client and server MUST manage a client-outgoing compression context
a server MUST report an error and disconnect after decompression error
a client MUST disconnect after it detect decompression error
a server MUST decompress each compressed message to keep compression context in sync on both sides even if expectation block in X Protocol is skipped
a server MAY consider to compress following X Protocol messages ColumnMetaData, Row, FetchDone, FetchSuspended, FetchMoreResultssets, FetchDoneMoreOutParams, Notice
- FR4
- a client MUST be able to query compression statistics
- FR5
- a client MUST be able to try to enable compression and accept a connection when server doesn't support compression (including ZSTD algorithm)
Implementation
In WL#9252 X Protocol added support for compression, which can be negotiated by client using connection capabilities.
To add zstd
support to xprotocol this WL needs to:
- implementing the new algorithm:
zstd_stream
- allow
zstd_stream
forcompression.algorithm
capability - allow
zstd_stream
formysqlx_compression_algorithms
Protocol
Server presents to the client known compression algorithm after
receiving CapabilitiesGet
protocol message:
client->server: Mysqlx.Connection.CapabilitiesGet()
client<-server: Mysqlx.Connection.Capabilities("compression":{"algorithm": ["deflate_stream", "lz4_message"]}, ...)
With WL#9252 it returns "deflate_stream" and "lz4_message". With zstd_stream
added, it should return:
client->server: Mysqlx.Connection.CapabilitiesGet()
client<-server: Mysqlx.Connection.Capabilities("compression":{"algorithm": ["deflate_stream", "lz4_message", "zstd_stream"]}, ...)
Compression algorithm is chosen by "CapabilitiesSet" message, which should allow "zstd_stream" value under "compression.algorithm" field:
client->server: Mysqlx.Connection.CapabilitiesSet("compression",{"algorithm"="zstd_stream",..})
client<-server: Mysqlx.Ok
The "zstd" compression algorithms must be enabled after authentication like other algorithms and must be applied in all compression configurations:
- "compression.server_combine_mixed_messages"
- "compression.server_max_combine_messages"
Compression Algorithm: zstd_stream
The payload of the Compressed message contains:
msgs = ...; // see WL#9252
payload = ZSTD_compressStream2(ctx, msgs.data(), msgs.size(), ...)
The zstd's compression context is kept alive over all messages to improve compression over time.
Note: each X Protocol compressed frame must be complete. Data from the zstd layer must be flushed before serializing them to X Protocol frame.
Maximum message size
The size of messages in xprotocol is limited to value of 'Mysqlx_max_allowed_packet' plugin variable.
The value applies to both:
* Compressed messages
* messages after uncompression
When a single message extracted from compressed message is larger than 'Mysqlx_max_allowed_packet' then decompression must be stopped and X Plugin must return ER_X_DECOMPRESSION_FAILED error and close the connection.
Compressed messages
As WL#9252 defines that everything except messages before authentication and Mysqlx.Ok, Mysqlx.Error, Mysqlx.Sql.StmtExecuteOk might be compressed. Same rules must be applied to "zstd" algorithm.
Instrumentation
Status variables
Monitoring of compressed data by the server
Monitoring of compression was implemented in WL#9252, and this worklog should increment same counters for the new compression algorithm. Those status variables are:
- mysqlx_bytes_sent_compressed_payload
- mysqlx_bytes_sent_uncompressed_frame
- mysqlx_bytes_received_compressed_payload
- mysqlx_bytes_received_uncompressed_frame
Configuration
mysqlx_compression_algorithms - using this variable, admin may limit supported compression algorithms. This variable already exists, it must be extended with new value "zstd" which represents the algorithm.
client->server: CapabilitiesGet client->server: Capabilities(compression:{algorithm:["deflate_stream", "lz4_message",
"zstd_stream"]}) ... admin executes SET @@mysqlx_compression_algorithms="zstd_stream"... client->server: CapabilitiesGet client->server: Capabilities(compression:{algorithm=["zstd_stream"]})
Property Value Name mysqlx_compression_algorithms Type SET("deflate_stream", "lz4_message", "zstd_stream") Scope Global Default 'deflate_stream,lz4_message,zstd_stream' Comment Already existing variable, new "zstd" value added