blog
blog copied to clipboard
动手写RPC框架 - GeeRPC第六天 负载均衡(load balance) | 极客兔兔
https://geektutu.com/post/geerpc-day6.html
7天用 Go语言/golang 从零实现 RPC 框架 GeeRPC 教程(7 days implement golang remote procedure call framework from scratch tutorial),动手写 RPC 框架,参照 golang 标准库 net/rpc 的实现,实现了服务端(server)、支持异步和并发的客户端(client)、消息编码与解码(message encoding and decoding)、服务注册(service register)、支持 TCP/Unix/HTTP 等多种传输协议。第六天实现了2种简单的负载均衡(load balance)算法,随机选择和 Round Robin 轮询调度算法。
没看错的话,Broadcast
方法里面的 goroutine 使用了loop iterator variable rpcAddr
,这个可能会有问题吧?
@ppd0705 感谢指出问题,会尽快修正:
for _, rpcAddr := range servers {
wg.Add(1)
go func(rpcAddr string) {
defer wg.Done()
// ...
}(rpcAddr)
}
不客气,golang我还不太熟,所以有点不确定。
话说 if err == nil && !replyDone { reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem()) replyDone = true } 中的reflect.valueof(reply).Elem()...这一句 如果改成reply=clonedeReply main也能正常运行,请问这两者有什么区别?好像只是变成了闭包效果而已。。
话说 if err == nil && !replyDone { reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem()) replyDone = true } 中的reflect.valueof(reply).Elem()...这一句 如果改成reply=clonedeReply main也能正常运行,请问这两者有什么区别?好像只是变成了闭包效果而已。。
@gnehcein 我自己的猜测,会不会是reply=clonedReply会导致函数结束后,clonedReply变量不会被回收呢
@gnehcein 话说 if err == nil && !replyDone { reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem()) replyDone = true } 中的reflect.valueof(reply).Elem()...这一句 如果改成reply=clonedeReply main也能正常运行,请问这两者有什么区别?好像只是变成了闭包效果而已。。
我也有一样的疑问,似乎也不是不行?
@whitebluepants
话说 if err == nil && !replyDone { reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem()) replyDone = true } 中的reflect.valueof(reply).Elem()...这一句 如果改成reply=clonedeReply main也能正常运行,请问这两者有什么区别?好像只是变成了闭包效果而已。。
@gnehcein 我自己的猜测,会不会是reply=clonedReply会导致函数结束后,clonedReply变量不会被回收呢
我认为,兔兔的写法是不改变reply的指针,在reply指向的那块内存写数据。如果使用reply = cloneReply
,那就把reply换了一个地址,指向clonedReply指向的变量,所以会导致内存逃逸(也就是clonedReply变量不会被回收)。
想请教一个问题。大家在测试Day6这个例子时,会不会出现发送消息卡死的现象。(具体体现为RPC服务器无法处理客户端发的请求,从而导致客户端由于未收到响应从而阻塞导致程序无法正常进行处理)
发现Day6的代码执行多次后会出现 rpc server: read header error: gob: unknow type id or corrupted data 以及 wsarecv: An existing connecion was forcibly closed by remote host的错误 本来以为是自己哪里写错了,但是拿教程里的代码来跑也会有这个问题,有没有人知道是为什么啊
@winterszhangdong
@gnehcein 话说 if err == nil && !replyDone { reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem()) replyDone = true } 中的reflect.valueof(reply).Elem()...这一句 如果改成reply=clonedeReply main也能正常运行,请问这两者有什么区别?好像只是变成了闭包效果而已。。
我也有一样的疑问,似乎也不是不行?
不行的吧,reply 是指针,在函数里面改变不会影响到外面,直接 reply = clonedReply 函数外面就的不到计算结果了
@USER-ZKL 发现Day6的代码执行多次后会出现 rpc server: read header error: gob: unknow type id or corrupted data 以及 wsarecv: An existing connecion was forcibly closed by remote host的错误 本来以为是自己哪里写错了,但是拿教程里的代码来跑也会有这个问题,有没有人知道是为什么啊
应该是 TCP 粘包了,这个教程里没有处理粘包问题
在Broadcast
方法中,定义了
replyDone := reply == nil
if err == nil && !replyDone {
reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem())
replyDone = true
}
我想问的是为什么要在reply不为空的时候进行赋值呢
gee-rpc/day6-load-balance/xclient/discovery.go:50 可以替换为
d.mu.RLock()
defer d.mu.RUnlock()
提升锁的并发度
@yan0327 想请教一个问题。大家在测试Day6这个例子时,会不会出现发送消息卡死的现象。(具体体现为RPC服务器无法处理客户端发的请求,从而导致客户端由于未收到响应从而阻塞导致程序无法正常进行处理)
会的,而且大可能会,好像是个bug,没有得到解决方案。