Skip to content

Commit d6bbf03

Browse files
committed
refactor code structure for gnet
1 parent 144b642 commit d6bbf03

File tree

11 files changed

+167
-117
lines changed

11 files changed

+167
-117
lines changed

README.md

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,19 @@ middleware using golang.
1616
Key Features:
1717

1818
- Support string, list, hash, set, sorted set, bitmap
19-
- Multi Database and `SELECT` command
19+
- Concurrent Core for better performance
2020
- TTL
2121
- Publish/Subscribe
2222
- GEO
2323
- AOF and AOF Rewrite
2424
- RDB read and write
25-
- MULTI Commands Transaction is Atomic and Isolated. If any errors are encountered during execution, godis will rollback
26-
the executed commands
27-
- Replication (experimental)
28-
- Server-side Cluster which is transparent to client. You can connect to any node in the cluster to
29-
access all data in the cluster.
25+
- Multi Database and `SELECT` command
26+
- Transaction is **Atomic** and Isolated. If any errors are encountered during execution, godis will rollback the executed commands
27+
- Replication
28+
- Server-side Cluster which is transparent to client. You can connect to any node in the cluster to access all data in the cluster.
3029
- Use the raft algorithm to maintain cluster metadata. (experimental)
3130
- `MSET`, `MSETNX`, `DEL`, `Rename`, `RenameNX` command is supported and atomically executed in cluster mode, allow over multi node
3231
- `MULTI` Commands Transaction is supported within slot in cluster mode
33-
- Concurrent Core, so you don't have to worry about your commands blocking the server too much.
3432

3533
If you could read Chinese, you can find more details in [My Blog](https://www.cnblogs.com/Finley/category/1598973.html).
3634

@@ -40,6 +38,9 @@ You can get runnable program in the releases of this repository, which supports
4038

4139
```bash
4240
./godis-darwin
41+
```
42+
43+
```bash
4344
./godis-linux
4445
```
4546

@@ -85,46 +86,34 @@ See: [commands.md](https://github.com/HDT3213/godis/blob/master/commands.md)
8586

8687
Environment:
8788

88-
Go version:1.17
89-
90-
System: macOS Catalina 10.15.7
91-
92-
CPU: 2.6GHz 6-Core Intel Core i7
93-
94-
Memory: 16 GB 2667 MHz DDR4
89+
Go version:1.23
90+
System: MacOS Monterey 12.5 M2 Air
9591

9692
Performance report by redis-benchmark:
9793

9894
```
99-
PING_INLINE: 87260.03 requests per second
100-
PING_BULK: 89206.06 requests per second
101-
SET: 85034.02 requests per second
102-
GET: 87565.68 requests per second
103-
INCR: 91157.70 requests per second
104-
LPUSH: 90334.23 requests per second
105-
RPUSH: 90334.23 requests per second
106-
LPOP: 90334.23 requests per second
107-
RPOP: 90415.91 requests per second
108-
SADD: 90909.09 requests per second
109-
HSET: 84104.29 requests per second
110-
SPOP: 82918.74 requests per second
111-
LPUSH (needed to benchmark LRANGE): 78247.26 requests per second
112-
LRANGE_100 (first 100 elements): 26406.13 requests per second
113-
LRANGE_300 (first 300 elements): 11307.10 requests per second
114-
LRANGE_500 (first 450 elements): 7968.13 requests per second
115-
LRANGE_600 (first 600 elements): 6092.73 requests per second
116-
MSET (10 keys): 65487.89 requests per second
95+
PING_INLINE: 179211.45 requests per second, p50=1.031 msec
96+
PING_MBULK: 173611.12 requests per second, p50=1.071 msec
97+
SET: 158478.61 requests per second, p50=1.535 msec
98+
GET: 156985.86 requests per second, p50=1.127 msec
99+
INCR: 164473.69 requests per second, p50=1.063 msec
100+
LPUSH: 151285.92 requests per second, p50=1.079 msec
101+
RPUSH: 176678.45 requests per second, p50=1.023 msec
102+
LPOP: 177619.89 requests per second, p50=1.039 msec
103+
RPOP: 172413.80 requests per second, p50=1.039 msec
104+
SADD: 159489.64 requests per second, p50=1.047 msec
105+
HSET: 175131.36 requests per second, p50=1.031 msec
106+
SPOP: 170648.45 requests per second, p50=1.031 msec
107+
ZADD: 165289.25 requests per second, p50=1.039 msec
108+
ZPOPMIN: 185528.77 requests per second, p50=0.999 msec
109+
LPUSH (needed to benchmark LRANGE): 172117.05 requests per second, p50=1.055 msec
110+
LRANGE_100 (first 100 elements): 46511.62 requests per second, p50=4.063 msec
111+
LRANGE_300 (first 300 elements): 21217.91 requests per second, p50=9.311 msec
112+
LRANGE_500 (first 500 elements): 13331.56 requests per second, p50=14.407 msec
113+
LRANGE_600 (first 600 elements): 11153.25 requests per second, p50=17.007 msec
114+
MSET (10 keys): 88417.33 requests per second, p50=3.687 msec
117115
```
118116

119-
## Todo List
120-
121-
+ [x] `Multi` Command
122-
+ [x] `Watch` Command and CAS support
123-
+ [ ] Stream support
124-
+ [x] RDB file loader
125-
+ [ ] Master-Slave mode
126-
+ [ ] Sentinel
127-
128117
## Read My Code
129118

130119
If you want to read my code in this repository, here is a simple guidance.

README_CN.md

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@ Godis 是一个用 Go 语言实现的 Redis 服务器。本项目旨在为尝试
1111

1212
关键功能:
1313
- 支持 string, list, hash, set, sorted set, bitmap 数据结构
14+
- 并行内核,提供更优秀的性能
1415
- 自动过期功能(TTL)
1516
- 发布订阅
1617
- 地理位置
17-
- AOF 持久化及 AOF 重写
18-
- 加载和导出 RDB 文件
19-
- 主从复制 (测试中)
20-
- Multi 命令开启的事务具有`原子性``隔离性`. 若在执行过程中遇到错误, godis 会回滚已执行的命令
18+
- AOF 持久化、RDB 持久化、aof-use-rdb-preamble 混合持久化
19+
- 主从复制
20+
- Multi 命令开启的事务具有**原子性**和隔离性. 若在执行过程中遇到错误, godis 会回滚已执行的命令
2121
- 内置集群模式. 集群对客户端是透明的, 您可以像使用单机版 redis 一样使用 godis 集群
2222
- 使用 raft 算法维护集群元数据(测试中)
2323
- `MSET`, `MSETNX`, `DEL`, `Rename`, `RenameNX` 命令在集群模式下原子性执行, 允许 key 在集群的不同节点上
24-
- 在集群模式下支持在同一个 slot 内执行事务
25-
- 并行引擎, 无需担心您的操作会阻塞整个服务器.
2624

2725
可以在[我的博客](https://www.cnblogs.com/Finley/category/1598973.html)了解更多关于
2826
Godis 的信息。
@@ -33,6 +31,9 @@ Godis 的信息。
3331

3432
```bash
3533
./godis-darwin
34+
```
35+
36+
```bash
3637
./godis-linux
3738
```
3839

@@ -74,46 +75,34 @@ redis-cli -p 6399
7475

7576
环境:
7677

77-
Go version:1.17
78-
79-
System: macOS Catalina 10.15.7
80-
81-
CPU: 2.6GHz 6-Core Intel Core i7
82-
83-
Memory: 16 GB 2667 MHz DDR4
78+
Go version: 1.23
79+
System: MacOS Monterey 12.5 M2 Air
8480

8581
redis-benchmark 测试结果:
8682

8783
```
88-
PING_INLINE: 87260.03 requests per second
89-
PING_BULK: 89206.06 requests per second
90-
SET: 85034.02 requests per second
91-
GET: 87565.68 requests per second
92-
INCR: 91157.70 requests per second
93-
LPUSH: 90334.23 requests per second
94-
RPUSH: 90334.23 requests per second
95-
LPOP: 90334.23 requests per second
96-
RPOP: 90415.91 requests per second
97-
SADD: 90909.09 requests per second
98-
HSET: 84104.29 requests per second
99-
SPOP: 82918.74 requests per second
100-
LPUSH (needed to benchmark LRANGE): 78247.26 requests per second
101-
LRANGE_100 (first 100 elements): 26406.13 requests per second
102-
LRANGE_300 (first 300 elements): 11307.10 requests per second
103-
LRANGE_500 (first 450 elements): 7968.13 requests per second
104-
LRANGE_600 (first 600 elements): 6092.73 requests per second
105-
MSET (10 keys): 65487.89 requests per second
84+
PING_INLINE: 179211.45 requests per second, p50=1.031 msec
85+
PING_MBULK: 173611.12 requests per second, p50=1.071 msec
86+
SET: 158478.61 requests per second, p50=1.535 msec
87+
GET: 156985.86 requests per second, p50=1.127 msec
88+
INCR: 164473.69 requests per second, p50=1.063 msec
89+
LPUSH: 151285.92 requests per second, p50=1.079 msec
90+
RPUSH: 176678.45 requests per second, p50=1.023 msec
91+
LPOP: 177619.89 requests per second, p50=1.039 msec
92+
RPOP: 172413.80 requests per second, p50=1.039 msec
93+
SADD: 159489.64 requests per second, p50=1.047 msec
94+
HSET: 175131.36 requests per second, p50=1.031 msec
95+
SPOP: 170648.45 requests per second, p50=1.031 msec
96+
ZADD: 165289.25 requests per second, p50=1.039 msec
97+
ZPOPMIN: 185528.77 requests per second, p50=0.999 msec
98+
LPUSH (needed to benchmark LRANGE): 172117.05 requests per second, p50=1.055 msec
99+
LRANGE_100 (first 100 elements): 46511.62 requests per second, p50=4.063 msec
100+
LRANGE_300 (first 300 elements): 21217.91 requests per second, p50=9.311 msec
101+
LRANGE_500 (first 500 elements): 13331.56 requests per second, p50=14.407 msec
102+
LRANGE_600 (first 600 elements): 11153.25 requests per second, p50=17.007 msec
103+
MSET (10 keys): 88417.33 requests per second, p50=3.687 msec
106104
```
107105

108-
## 开发计划
109-
110-
+ [x] `Multi` 命令
111-
+ [x] `Watch` 命令和 CAS 支持
112-
+ [ ] Stream 队列
113-
+ [ ] 加载 RDB 文件
114-
+ [ ] 主从模式
115-
+ [ ] 哨兵
116-
117106
## 如何阅读源码
118107

119108
本项目的目录结构:

config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type ServerProperties struct {
4040
SlaveAnnouncePort int `cfg:"slave-announce-port"`
4141
SlaveAnnounceIP string `cfg:"slave-announce-ip"`
4242
ReplTimeout int `cfg:"repl-timeout"`
43-
43+
UseGnet bool `cfg:"use-gnet"`
4444
ClusterEnable bool `cfg:"cluster-enable"`
4545
ClusterAsSeed bool `cfg:"cluster-as-seed"`
4646
ClusterSeed string `cfg:"cluster-seed"`

main.go

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@ import (
66

77
"github.com/hdt3213/godis/cluster"
88
"github.com/hdt3213/godis/config"
9-
database2 "github.com/hdt3213/godis/database"
10-
"github.com/hdt3213/godis/gnet"
11-
"github.com/hdt3213/godis/interface/database"
9+
"github.com/hdt3213/godis/database"
10+
idatabase "github.com/hdt3213/godis/interface/database"
1211
"github.com/hdt3213/godis/lib/logger"
1312
"github.com/hdt3213/godis/lib/utils"
14-
15-
// RedisServer "github.com/hdt3213/godis/redis/server"
16-
// "github.com/hdt3213/godis/tcp"
17-
gnetv2 "github.com/panjf2000/gnet/v2"
13+
"github.com/hdt3213/godis/redis/server/gnet"
14+
stdserver "github.com/hdt3213/godis/redis/server/std"
1815
)
1916

2017
var banner = `
@@ -58,21 +55,21 @@ func main() {
5855
config.SetupConfig(configFilename)
5956
}
6057
listenAddr := fmt.Sprintf("%s:%d", config.Properties.Bind, config.Properties.Port)
61-
// err := tcp.ListenAndServeWithSignal(&tcp.Config{
62-
// Address: fmt.Sprintf("%s:%d", config.Properties.Bind, config.Properties.Port),
63-
// }, RedisServer.MakeHandler())
64-
// if err != nil {
65-
// logger.Error(err)
66-
// }
67-
68-
var db database.DB
69-
if config.Properties.ClusterEnable {
70-
db = cluster.MakeCluster()
58+
59+
var err error
60+
if config.Properties.UseGnet {
61+
var db idatabase.DB
62+
if config.Properties.ClusterEnable {
63+
db = cluster.MakeCluster()
64+
} else {
65+
db = database.NewStandaloneServer()
66+
}
67+
server := gnet.NewGnetServer(db)
68+
err = server.Run(listenAddr)
7169
} else {
72-
db = database2.NewStandaloneServer()
70+
handler := stdserver.MakeHandler()
71+
err = stdserver.Serve(listenAddr, handler)
7372
}
74-
server := gnet.NewGnetServer(db)
75-
err := gnetv2.Run(server, "tcp://" + listenAddr, gnetv2.WithMulticore(true))
7673
if err != nil {
7774
logger.Errorf("start server failed: %v", err)
7875
}

gnet/parser.go renamed to redis/parser/parserv2.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package gnet
1+
package parser
22

33
import (
44
"errors"
@@ -7,7 +7,7 @@ import (
77
"strings"
88
)
99

10-
func Parse(r io.Reader) ([][]byte, error) {
10+
func ParseV2(r io.Reader) ([][]byte, error) {
1111
// 读取起始字符 '*'
1212
buf := make([]byte, 1)
1313
_, err := io.ReadFull(r, buf)

gnet/parser_test.go renamed to redis/parser/parserv2_test.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package gnet
1+
package parser
22

33
import (
44
"bytes"
@@ -18,15 +18,29 @@ func BenchmarkParseSETCommand(b *testing.B) {
1818

1919
for i := 0; i < subB.N; i++ {
2020
reader := bytes.NewReader(cmd)
21-
_, err := Parse(reader)
21+
_, err := ParseV2(reader)
2222
if err != nil {
23-
subB.Fatalf("解析失败: %v", err)
23+
subB.Fatalf("parse failed: %v", err)
2424
}
2525
}
2626
})
2727
}
2828
}
2929

30+
func TestParseV2(t *testing.T) {
31+
value := bytes.Repeat([]byte("a"), 100)
32+
data := []byte(fmt.Sprintf("*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$%d\r\n%s\r\n", len(value), value))
33+
cmdLine, err := ParseV2(bytes.NewBuffer(data))
34+
if err != nil {
35+
t.Error(err)
36+
return
37+
}
38+
if len(cmdLine) != 3 || string(cmdLine[0]) != "SET" || string(cmdLine[1]) != "key" || string(cmdLine[2]) != string(value) {
39+
t.Error("parse error")
40+
return
41+
}
42+
}
43+
3044
func formatSize(size int) string {
3145
units := []string{"B", "KB", "MB"}
3246
unitIndex := 0

gnet/server.go renamed to redis/server/gnet/server.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package gnet
22

33
import (
4+
"context"
45
"sync/atomic"
56

67
"github.com/hdt3213/godis/interface/database"
78
"github.com/hdt3213/godis/interface/redis"
89
"github.com/hdt3213/godis/lib/logger"
910
"github.com/hdt3213/godis/redis/connection"
11+
"github.com/hdt3213/godis/redis/parser"
1012
"github.com/panjf2000/gnet/v2"
1113
)
1214

@@ -23,6 +25,10 @@ func NewGnetServer(db database.DB) *GnetServer {
2325
}
2426
}
2527

28+
func (s *GnetServer) Run(listenAddr string) error {
29+
return gnet.Run(s, "tcp://"+listenAddr, gnet.WithMulticore(true))
30+
}
31+
2632
func (s *GnetServer) OnBoot(eng gnet.Engine) (action gnet.Action) {
2733
s.eng = eng
2834
return
@@ -47,7 +53,7 @@ func (s *GnetServer) OnClose(c gnet.Conn, err error) (action gnet.Action) {
4753

4854
func (s *GnetServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
4955
conn := c.Context().(redis.Connection)
50-
cmdLine, err := Parse(c)
56+
cmdLine, err := parser.ParseV2(c)
5157
if err != nil {
5258
logger.Infof("parse command line failed: %v", err)
5359
return gnet.Close
@@ -62,3 +68,7 @@ func (s *GnetServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
6268
}
6369
return gnet.None
6470
}
71+
72+
func (s *GnetServer) Close() {
73+
s.eng.Stop(context.Background())
74+
}

0 commit comments

Comments
 (0)