Skip to content

Commit a580c15

Browse files
perf: improve gzip performance with sync.pool (#1321)
Signed-off-by: rfyiamcool <[email protected]> Co-authored-by: Gordon <[email protected]>
1 parent 8e0cb6d commit a580c15

File tree

4 files changed

+155
-3
lines changed

4 files changed

+155
-3
lines changed

internal/msggateway/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func (c *Client) readMessage() {
167167
func (c *Client) handleMessage(message []byte) error {
168168
if c.IsCompress {
169169
var err error
170-
message, err = c.longConnServer.DeCompress(message)
170+
message, err = c.longConnServer.DecompressWithPool(message)
171171
if err != nil {
172172
return utils.Wrap(err, "")
173173
}
@@ -317,7 +317,7 @@ func (c *Client) writeBinaryMsg(resp Resp) error {
317317

318318
_ = c.conn.SetWriteDeadline(writeWait)
319319
if c.IsCompress {
320-
resultBuf, compressErr := c.longConnServer.Compress(encodedBuf)
320+
resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf)
321321
if compressErr != nil {
322322
return utils.Wrap(compressErr, "")
323323
}

internal/msggateway/compressor.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,23 @@ package msggateway
1717
import (
1818
"bytes"
1919
"compress/gzip"
20+
"errors"
2021
"io"
22+
"sync"
2123

2224
"github.com/OpenIMSDK/tools/utils"
2325
)
2426

27+
var (
28+
gzipWriterPool = sync.Pool{New: func() any { return gzip.NewWriter(nil) }}
29+
gzipReaderPool = sync.Pool{New: func() any { return new(gzip.Reader) }}
30+
)
31+
2532
type Compressor interface {
2633
Compress(rawData []byte) ([]byte, error)
34+
CompressWithPool(rawData []byte) ([]byte, error)
2735
DeCompress(compressedData []byte) ([]byte, error)
36+
DecompressWithPool(compressedData []byte) ([]byte, error)
2837
}
2938
type GzipCompressor struct {
3039
compressProtocol string
@@ -46,6 +55,22 @@ func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) {
4655
return gzipBuffer.Bytes(), nil
4756
}
4857

58+
func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) {
59+
gz := gzipWriterPool.Get().(*gzip.Writer)
60+
defer gzipWriterPool.Put(gz)
61+
62+
gzipBuffer := bytes.Buffer{}
63+
gz.Reset(&gzipBuffer)
64+
65+
if _, err := gz.Write(rawData); err != nil {
66+
return nil, utils.Wrap(err, "")
67+
}
68+
if err := gz.Close(); err != nil {
69+
return nil, utils.Wrap(err, "")
70+
}
71+
return gzipBuffer.Bytes(), nil
72+
}
73+
4974
func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) {
5075
buff := bytes.NewBuffer(compressedData)
5176
reader, err := gzip.NewReader(buff)
@@ -59,3 +84,23 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) {
5984
_ = reader.Close()
6085
return compressedData, nil
6186
}
87+
88+
func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, error) {
89+
reader := gzipReaderPool.Get().(*gzip.Reader)
90+
if reader == nil {
91+
return nil, errors.New("NewReader failed")
92+
}
93+
defer gzipReaderPool.Put(reader)
94+
95+
err := reader.Reset(bytes.NewReader(compressedData))
96+
if err != nil {
97+
return nil, utils.Wrap(err, "NewReader failed")
98+
}
99+
100+
compressedData, err = io.ReadAll(reader)
101+
if err != nil {
102+
return nil, utils.Wrap(err, "ReadAll failed")
103+
}
104+
_ = reader.Close()
105+
return compressedData, nil
106+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package msggateway
2+
3+
import (
4+
"crypto/rand"
5+
"sync"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func mockRandom() []byte {
12+
bs := make([]byte, 50)
13+
rand.Read(bs)
14+
return bs
15+
}
16+
17+
func TestCompressDecompress(t *testing.T) {
18+
19+
compressor := NewGzipCompressor()
20+
21+
for i := 0; i < 2000; i++ {
22+
src := mockRandom()
23+
24+
// compress
25+
dest, err := compressor.CompressWithPool(src)
26+
assert.Equal(t, nil, err)
27+
28+
// decompress
29+
res, err := compressor.DecompressWithPool(dest)
30+
assert.Equal(t, nil, err)
31+
32+
// check
33+
assert.EqualValues(t, src, res)
34+
}
35+
}
36+
37+
func TestCompressDecompressWithConcurrency(t *testing.T) {
38+
wg := sync.WaitGroup{}
39+
compressor := NewGzipCompressor()
40+
41+
for i := 0; i < 200; i++ {
42+
wg.Add(1)
43+
go func() {
44+
defer wg.Done()
45+
src := mockRandom()
46+
47+
// compress
48+
dest, err := compressor.CompressWithPool(src)
49+
assert.Equal(t, nil, err)
50+
51+
// decompress
52+
res, err := compressor.DecompressWithPool(dest)
53+
assert.Equal(t, nil, err)
54+
55+
// check
56+
assert.EqualValues(t, src, res)
57+
58+
}()
59+
}
60+
wg.Wait()
61+
}
62+
63+
func BenchmarkCompress(b *testing.B) {
64+
src := mockRandom()
65+
compressor := NewGzipCompressor()
66+
67+
for i := 0; i < b.N; i++ {
68+
_, err := compressor.Compress(src)
69+
assert.Equal(b, nil, err)
70+
}
71+
}
72+
73+
func BenchmarkCompressWithSyncPool(b *testing.B) {
74+
src := mockRandom()
75+
76+
compressor := NewGzipCompressor()
77+
for i := 0; i < b.N; i++ {
78+
_, err := compressor.CompressWithPool(src)
79+
assert.Equal(b, nil, err)
80+
}
81+
}
82+
83+
func BenchmarkDecompress(b *testing.B) {
84+
src := mockRandom()
85+
86+
compressor := NewGzipCompressor()
87+
comdata, err := compressor.Compress(src)
88+
assert.Equal(b, nil, err)
89+
90+
for i := 0; i < b.N; i++ {
91+
_, err := compressor.DeCompress(comdata)
92+
assert.Equal(b, nil, err)
93+
}
94+
}
95+
96+
func BenchmarkDecompressWithSyncPool(b *testing.B) {
97+
src := mockRandom()
98+
99+
compressor := NewGzipCompressor()
100+
comdata, err := compressor.Compress(src)
101+
assert.Equal(b, nil, err)
102+
103+
for i := 0; i < b.N; i++ {
104+
_, err := compressor.DecompressWithPool(comdata)
105+
assert.Equal(b, nil, err)
106+
}
107+
}

internal/msggateway/init.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
2424
)
2525

26-
// RunWsAndServer run ws server
26+
// RunWsAndServer run ws server.
2727
func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error {
2828
fmt.Println(
2929
"start rpc/msg_gateway server, port: ",

0 commit comments

Comments
 (0)