geektutu / blog

极客兔兔的博客,Coding Coding 创建有趣的开源项目。
https://geektutu.com
Apache License 2.0
166 stars 21 forks source link

动手写分布式缓存 - GeeCache第七天 使用 Protobuf 通信 | 极客兔兔 #66

Open geektutu opened 4 years ago

geektutu commented 4 years ago

https://geektutu.com/post/geecache-day7.html

7天用 Go语言/golang 从零实现分布式缓存 GeeCache 教程(7 days implement golang distributed cache from scratch tutorial),动手写分布式缓存,参照 groupcache 的实现。本文介绍了使用 protobuf(protocol buffer) 进行节点间通信,编码报文,提高效率

xupingao commented 4 years ago

跟着写完了,收获很多,谢谢博主。

geektutu commented 4 years ago

跟着写完了,收获很多,谢谢博主。

你的效率是真高!

evanxg852000 commented 4 years ago

Thanks a lot, I have unlocked another level of software inner working. Next stop is the GORM

geektutu commented 4 years ago

@evanxg852000 Thanks a lot, I have unlocked another level of software inner working. Next stop is the GORM

I'm very glad if it helps you. GeeORM has been implemented and I'll try my best to finish 7 blogs for GeeORM within 1 week.

mcrwayfun commented 4 years ago
fmt.Println("非常好的一个系列,循循善诱,受益良多!")
xiaoxfan commented 4 years ago

跟着做完了 受益匪浅 感谢大佬

yance-dev commented 4 years ago
ppd0705 commented 4 years ago

感谢分享 下一步GeeORM

ghosx commented 4 years ago

后面已经蒙了

wuqinqiang commented 4 years ago

终于学完了 精彩 得好好看带代码总结了。收货很多 感谢

proverbs commented 4 years ago

博主你的GroupCache service就没有用到,是不是删了比较好,否则有误导性。 但是不用service的话,现在peers之间的的rpc还是在用http的url传递request参数,使用protobuf其实和原本的没有区别。 如果要实现service的话,可能挺复杂的,一节课怕是写不完。 (后来又想了想用grpc的话,再HTTPPool实现GroupCacheServer接口,然后PeerGetter里用GroupCacheClient的接口是不是就行了,应该也不是特别复杂)

HallWoodZhang commented 3 years ago

精彩,太精彩了,意犹未尽,准备趁着假期整理一遍,顺便看看能不能用docker和k8s部署一下这个项目

xlban163 commented 3 years ago

感谢博主,受益匪浅

batreeon commented 3 years ago

看完了,也跟着把代码抄了一遍,但还是迷迷糊糊,很多地方我还没有理清🤣,后面需要把代码逻辑顺一顺。一致性哈希那一块是我觉得最有趣的,谢谢。

zoulux commented 3 years ago

@proverbs 博主你的GroupCache service就没有用到,是不是删了比较好,否则有误导性。 但是不用service的话,现在peers之间的的rpc还是在用http的url传递request参数,使用protobuf其实和原本的没有区别。 如果要实现service的话,可能挺复杂的,一节课怕是写不完。 (后来又想了想用grpc的话,再HTTPPool实现GroupCacheServer接口,然后PeerGetter里用GroupCacheClient的接口是不是就行了,应该也不是特别复杂)

我也觉得

catplays commented 3 years ago

学到很多,感谢博主

Feedingzhang commented 3 years ago

真的很受用,讲的浅显易懂,非常感谢

lemonness commented 2 years ago

感谢博主!收获很多

xugai commented 2 years ago

@proverbs 博主你的GroupCache service就没有用到,是不是删了比较好,否则有误导性。 但是不用service的话,现在peers之间的的rpc还是在用http的url传递request参数,使用protobuf其实和原本的没有区别。 如果要实现service的话,可能挺复杂的,一节课怕是写不完。 (后来又想了想用grpc的话,再HTTPPool实现GroupCacheServer接口,然后PeerGetter里用GroupCacheClient的接口是不是就行了,应该也不是特别复杂)

对啊,我看完这一节后也是有点懵逼。这好像没有完全利用到pb高效通信的优点,因为传输方式还是基于HTTP请求。原本http传输的就是字节流,现在只不过换为了传输具有结构化的数据而已,感觉效果没变

fyyjyx-github commented 2 years ago

@proverbs 请问有关于这个GeeCache的相关性能测试的结果吗?

0RAJA commented 2 years ago

写的非常好,十分感谢

018429 commented 2 years ago

感谢~

DurantVivado commented 2 years ago

Thanks a lot. Hopefully, I can integrate that into my own system. More practice is needed.

yinhuanyi commented 2 years ago

博主:proto文件中,指定golang的package,现在使用go_package指令 参考文档

需要修改一下:option go_package = "./;geecachepb";

sfusong commented 2 years ago

Thanks a lot

voidspiral commented 2 years ago

博主分析的很好,可是命名为geeCache实在是太滑稽了

voidspiral commented 2 years ago

收获多多!!

ZXM250250 commented 2 years ago

老哥写的这么好 为啥不出本书

yyqingshui commented 2 years ago

写的非常好,感谢博主!

AkisAya commented 2 years ago

proto 文件需要 option go_package,编译才能通过

syntax = "proto3";

package geecachepb;

option go_package = "./geecachepb";

...

而且需要在 geecachepb 的同级目录执行 protoc --go_out=. geecachepb/*.proto

@yinhuanyi 写的做法也行,option go_package = "./;geecachepb"; 不过官方文档里写这种做法不鼓励,毕竟约定目录最后一级就是包名。

LLoyou00 commented 2 years ago

PeerPicker 的 PickPeer 是本地调用,为什么还要用 proto 呢。。。纯粹为了演示吗?

weekmy commented 1 year ago

给博主点赞,一遍刷完了,感觉还是有些地方有点懵,再刷一遍

itherunder commented 1 year ago

实现了一下真正用protobuf c/s进行通信的方式

grpc.go

package geecache

import (
    "context"
    "fmt"
    "geecache/geecache/consistent"
    pb "geecache/geecache/geecachepb"
    "geecache/geecache/peers"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
    "log"
    "net"
    "sync"
)

type grpcGetter struct {
    addr string
}

func (g *grpcGetter) Get(in *pb.Request, out *pb.Response) error {
    c, err := grpc.Dial(g.addr, grpc.WithInsecure())
    if err != nil {
        return err
    }
    client := pb.NewGroupCacheClient(c)
    response, err := client.Get(context.Background(), in)
    out.Value = response.Value
    return err
}

var _ peers.PeerGetter = (*grpcGetter)(nil)

type GrpcPool struct {
    pb.UnimplementedGroupCacheServer

    self        string
    mu          sync.Mutex
    peers       *consistent.Map
    grpcGetters map[string]*grpcGetter
}

func NewGrpcPool(self string) *GrpcPool {
    return &GrpcPool{
        self:        self,
        peers:       consistent.New(defaultReplicas, nil),
        grpcGetters: map[string]*grpcGetter{},
    }
}

func (p *GrpcPool) Set(peers ...string) {
    p.mu.Lock()
    defer p.mu.Unlock()
    p.peers.Add(peers...)
    for _, peer := range peers {
        p.grpcGetters[peer] = &grpcGetter{
            addr: peer,
        }
    }
}

func (p *GrpcPool) PickPeer(key string) (peers.PeerGetter, bool) {
    p.mu.Lock()
    defer p.mu.Unlock()
    if peer := p.peers.Get(key); peer != "" && peer != p.self {
        return p.grpcGetters[peer], true
    }
    return nil, false
}

var _ peers.PeerPicker = (*GrpcPool)(nil)

func (p *GrpcPool) Log(format string, v ...interface{}) {
    log.Printf("[Server %s] %s", p.self, fmt.Sprintf(format, v...))
}

func (p *GrpcPool) Get(ctx context.Context, in *pb.Request) (*pb.Response, error) {
    p.Log("%s %s", in.Group, in.Key)
    response := &pb.Response{}

    group := GetGroup(in.Group)
    if group == nil {
        p.Log("no such group %v", in.Group)
        return response, fmt.Errorf("no such group %v", in.Group)
    }
    value, err := group.Get(in.Key)
    if err != nil {
        p.Log("get key %v error %v", in.Key, err)
        return response, err
    }

    response.Value = value.ByteSlice()
    return response, nil
}

func (p *GrpcPool) Run() {
    lis, err := net.Listen("tcp", p.self)
    if err != nil {
        panic(err)
    }

    server := grpc.NewServer()
    pb.RegisterGroupCacheServer(server, p)

    reflection.Register(server)
    err = server.Serve(lis)
    if err != nil {
        panic(err)
    }
}

main.go

func startCacheServerGrpc(addr string, addrs []string, gee *geecache.Group) {
    peers := geecache.NewGrpcPool(addr)
    peers.Set(addrs...)
    gee.RegisterPeers(peers)
    log.Println("geecache is running at", addr)
    peers.Run()
}

func startGRPCServer() {
    var port int
    var api bool
    flag.IntVar(&port, "port", 8001, "Geecache server port")
    flag.BoolVar(&api, "api", false, "Start a api server?")
    flag.Parse()

    apiAddr := "http://localhost:9999"
    addrMap := map[int]string{
        8001: ":8001",
        8002: ":8002",
        8003: ":8003",
    }

    var addrs []string
    for _, v := range addrMap {
        addrs = append(addrs, v)
    }

    gee := createGroup()
    if api {
        go startAPIServer(apiAddr, gee)
    }
    startCacheServerGrpc(addrMap[port], addrs, gee)
}
krischen1999 commented 1 year ago

一遍刷完了,并且自己做了拓展,附上自己的成果 https://github.com/krischen1999/MyCache

lyisbest commented 12 months ago

好像只有返回数据使用的是protobuf的格式,但是请求数据还是通过http的url来传递。整个节点间的通信还是使用http协议的。

eric49861 commented 10 months ago

想问一下,大佬这种设计思路是怎么来的?跟着搓完,就一个感觉,还是不自己瞎做项目了|:) 多看一些好的开源项目源码吗?

lyisbest commented 10 months ago

您的来信我已收到,请耐心等待,我会尽快处理!

1055373165 commented 10 months ago

教程跟完了,收获了很多,protobuf 通信这部分应该算不上完全利用了 rpc,因为我是面试要用,所以需要扩展一些功能;我后来从 github 上面找了其他的教程,实现了基于 rpc 的节点间通信并实现了基于 etcd 的服务注册发现,提供项目分析和详细代码注释,大家如果想要扩展一下这个轮子项目的,可以瞅瞅,我放的有最终的调用效果图。地址在这:https://github.com/1055373165/DistributedKVCache

最后:感谢兔子哥这么优秀的教程,后面有时间把手写系列都跟下来。

wandering-readily commented 9 months ago

proto 文件需要 option go_package,编译才能通过

syntax = "proto3";

package geecachepb;

option go_package = "./geecachepb";

...

而且需要在 geecachepb 的同级目录执行 protoc --go_out=. geecachepb/*.proto

@yinhuanyi 写的做法也行,option go_package = "./;geecachepb"; 不过官方文档里写这种做法不鼓励,毕竟约定目录最后一级就是包名。

option go_package = “” 选项内容是为了其他go module import编译的.proto文件吧,最好和其他go module一样的格式吧("example.com/module1/module2")

lyisbest commented 9 months ago

您的来信我已收到,请耐心等待,我会尽快处理!

EndlessParadox1 commented 3 months ago

感觉我可以把他改写成纯grpc

lyisbest commented 3 months ago

您的来信我已收到,请耐心等待,我会尽快处理!

jikefan commented 2 months ago

认真读完了GeeCache的实现,收获很多,感谢兔兔大佬的风险!

lyisbest commented 2 months ago

您的来信我已收到,请耐心等待,我会尽快处理!

lsknawm commented 1 week ago

看完b站那个分布式系统的再来看看这边的,基础学完就得多刷别的代码

lyisbest commented 1 week ago

您的来信我已收到,请耐心等待,我会尽快处理!