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
```
Этот коммит содержится в:
Agniva De Sarker
2023-11-08 12:15:24 +05:30
коммит произвёл GitHub
родитель f29fbddef1
Коммит 3563e56a77
3 изменённых файлов: 9 добавлений и 5 удалений

Просмотреть файл

@@ -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++
}
}