- golang实现redis兼容的redis服务
- 实现redis兼容的redis服务思路
golangredisredis_1">golang实现redis兼容的redis服务
- 之前做的redis服务是通过tcp封装的自定义协议
原版项目地址:https://github.com/dengjiayue/my-redis.git
- 那么能不能实现一个redis兼容的redis服务,这样一般的redis包也可以调用我们写的redis服务了呢?
当然可以,需要实现redis的RESP通信协议
新版项目地址: https://github.com/dengjiayue/my-redis-v2.0-RESP-.git
实现redis兼容的redis服务思路
- 原本的数据处理模型不变,依旧使用单线程模型,map储存数据
- 实现RESP协议的支持就可以了
首先,我们需要知道redis一般收到的读写命令是什么样的去搞清楚RESP协议的原理
读
"*2\r\n$3\r\nget\r\n$4\r\nname\r\n"
写
"*3\r\n$3\r\nset\r\n$4\r\nname\r\n$8\r\nzhangsan\r\n"
RESP使用\r\n作为换行符
*2,*3表示命令的个数
一个命令包含前面一个命令数据的长度,比如$3 表示后面的数据长度为3; 然后在长度下一行才是数据;
一般第一个是方法名set,get什么的,第二个是key值,第三个是val值(如果是get就没有第三个),后面是过期时间什么的.
明白了工作原理我们就可以封装RESP协议支持了
- 根据换行符解析每一行数据
- 先解析第一行,获取整个请求的包含多少个命令
- 再解析每一个命令
- 先解析长度,再解析数据,
- 最后根据数据中的方法,key,val等消息做数据处理
- 封装返回:成功就返回“+{msg}\r\n”,msg为处理结果;失败就返回“-Err {msg}\r\n”,msg 为失败的信息
这样你就可以通过golang的redis包调用你的redis服务了
使用go-redis包做测试
import ("context""fmt""time""github.com/go-redis/redis/v8"
)// 新建连接池
func NewPool() *redis.Client {return redis.NewClient(&redis.Options{Addr: "localhost:8080",PoolSize: 1,MinIdleConns: 1,})
}// 写入redis
func WriteRedis(client *redis.Client) {ctx := context.Background()// 写入redisrsp, err := client.Set(ctx, "name", "tom", time.Minute).Result()if err != nil {panic(err)}fmt.Println(rsp)
}// 读取redis
func ReadRedis(client *redis.Client) {ctx := context.Background()// 读取redisrsp, err := client.Get(ctx, "name").Result()if err != nil {panic(err)}fmt.Println(rsp)
}func TestWriteRedis(t *testing.T) {type args struct {client *redis.Client}tests := []struct {name stringargs args}{// TODO: Add test cases.{"test", args{NewPool()}},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {WriteRedis(tt.args.client)})}
}func TestReadRedis(t *testing.T) {type args struct {client *redis.Client}tests := []struct {name stringargs args}{// TODO: Add test cases.{"test", args{NewPool()}},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {ReadRedis(tt.args.client)defer tt.args.client.Close()})}
}// 读写测试
func TestReadWriteRedis(t *testing.T) {type args struct {client *redis.Client}tests := []struct {name stringargs args}{// TODO: Add test cases.{"test", args{NewPool()}},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {WriteRedis(tt.args.client)ReadRedis(tt.args.client)defer tt.args.client.Close()})}
}// 读写测试
func TestReadWriteRedis(t *testing.T) {type args struct {client *redis.Client}tests := []struct {name stringargs args}{// TODO: Add test cases.{"test", args{NewPool()}},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {WriteRedis(tt.args.client)ReadRedis(tt.args.client)defer tt.args.client.Close()})}
}
读写结果
=== RUN TestReadWriteRedis
=== RUN TestReadWriteRedis/test
OK
tom
--- PASS: TestReadWriteRedis/test (0.00s)
--- PASS: TestReadWriteRedis (0.00s)
PASS
ok redis_performance_test/go_redis_read_write 0.756s
仓库地址: https://github.com/dengjiayue/my-redis-v2.0-RESP-.git