mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
MM-54998: Optimize JSON marshalling in websocket broadcast (#25286)
Marshalling a json.RawMessage is not zero overhead. Instead, it compacts the raw message which starts to have an overhead at scale. https://github.com/golang/go/issues/33422 Since we have full control over the message constructed, we can simply write the byte slice into the network stream. This gives considerable performance boost. ``` goos: linux goarch: amd64 pkg: github.com/mattermost/mattermost/server/public/model cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz │ old.txt │ new_2.txt │ │ sec/op │ sec/op vs base │ EncodeJSON-8 1640.5n ± 2% 289.6n ± 1% -82.35% (p=0.000 n=10) │ old.txt │ new_2.txt │ │ B/op │ B/op vs base │ EncodeJSON-8 528.0 ± 0% 503.0 ± 0% -4.73% (p=0.000 n=10) │ old.txt │ new_2.txt │ │ allocs/op │ allocs/op vs base │ EncodeJSON-8 5.000 ± 0% 4.000 ± 0% -20.00% (p=0.000 n=10) ``` P.S. No concerns over changing the model API because we are still using 0.x https://mattermost.atlassian.net/browse/MM-54998 ```release-note Improve websocket event marshalling performance ```
This commit is contained in:
parent
f29fbddef1
commit
3563e56a77
@ -463,7 +463,7 @@ func (wc *WebConn) writePump() {
|
||||
var err error
|
||||
if evtOk {
|
||||
evt = evt.SetSequence(wc.Sequence)
|
||||
err = evt.Encode(enc)
|
||||
err = evt.Encode(enc, &buf)
|
||||
wc.Sequence++
|
||||
} else {
|
||||
err = enc.Encode(msg)
|
||||
@ -530,7 +530,7 @@ func (wc *WebConn) writeMessage(msg *model.WebSocketEvent) error {
|
||||
// We don't use the encoder from the write pump because it's unwieldy to pass encoders
|
||||
// around, and this is only called during initialization of the webConn.
|
||||
var buf bytes.Buffer
|
||||
err := msg.Encode(json.NewEncoder(&buf))
|
||||
err := msg.Encode(json.NewEncoder(&buf), &buf)
|
||||
if err != nil {
|
||||
mlog.Warn("Error in encoding websocket message", mlog.Err(err))
|
||||
return nil
|
||||
|
@ -294,9 +294,10 @@ func (ev *WebSocketEvent) ToJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// Encode encodes the event to the given encoder.
|
||||
func (ev *WebSocketEvent) Encode(enc *json.Encoder) error {
|
||||
func (ev *WebSocketEvent) Encode(enc *json.Encoder, buf io.Writer) error {
|
||||
if ev.precomputedJSON != nil {
|
||||
return enc.Encode(json.RawMessage(ev.precomputedJSONBuf()))
|
||||
_, err := buf.Write(ev.precomputedJSONBuf())
|
||||
return err
|
||||
}
|
||||
|
||||
return enc.Encode(webSocketEventJSON{
|
||||
|
@ -247,8 +247,11 @@ func BenchmarkEncodeJSON(b *testing.B) {
|
||||
|
||||
ev := message.PrecomputeJSON()
|
||||
|
||||
var seq int64
|
||||
enc := json.NewEncoder(io.Discard)
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = ev.Encode(enc)
|
||||
ev = ev.SetSequence(seq)
|
||||
err = ev.Encode(enc, io.Discard)
|
||||
seq++
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user