blog icon indicating copy to clipboard operation
blog copied to clipboard

动手写RPC框架 - GeeRPC第六天 负载均衡(load balance) | 极客兔兔

Open geektutu opened this issue 3 years ago • 15 comments

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 轮询调度算法。

geektutu avatar Oct 08 '20 09:10 geektutu

没看错的话,Broadcast方法里面的 goroutine 使用了loop iterator variable rpcAddr,这个可能会有问题吧?

ppd0705 avatar Dec 01 '20 04:12 ppd0705

@ppd0705 感谢指出问题,会尽快修正:

for _, rpcAddr := range servers {
	wg.Add(1)
	go func(rpcAddr string) {
		defer wg.Done()
		// ...
	}(rpcAddr)
}

geektutu avatar Dec 01 '20 05:12 geektutu

不客气,golang我还不太熟,所以有点不确定。

ppd0705 avatar Dec 01 '20 08:12 ppd0705

话说 if err == nil && !replyDone { reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem()) replyDone = true } 中的reflect.valueof(reply).Elem()...这一句 如果改成reply=clonedeReply main也能正常运行,请问这两者有什么区别?好像只是变成了闭包效果而已。。

gnehcein avatar Apr 13 '21 14:04 gnehcein

话说 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变量不会被回收呢

whitebluepants avatar Nov 01 '21 08:11 whitebluepants

@gnehcein 话说 if err == nil && !replyDone { reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem()) replyDone = true } 中的reflect.valueof(reply).Elem()...这一句 如果改成reply=clonedeReply main也能正常运行,请问这两者有什么区别?好像只是变成了闭包效果而已。。

我也有一样的疑问,似乎也不是不行?

winterszhangdong avatar Jan 21 '22 16:01 winterszhangdong

@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变量不会被回收)。

yuanweining avatar Mar 08 '22 15:03 yuanweining

想请教一个问题。大家在测试Day6这个例子时,会不会出现发送消息卡死的现象。(具体体现为RPC服务器无法处理客户端发的请求,从而导致客户端由于未收到响应从而阻塞导致程序无法正常进行处理)

yan0327 avatar Apr 10 '22 14:04 yan0327

发现Day6的代码执行多次后会出现 rpc server: read header error: gob: unknow type id or corrupted data 以及 wsarecv: An existing connecion was forcibly closed by remote host的错误 本来以为是自己哪里写错了,但是拿教程里的代码来跑也会有这个问题,有没有人知道是为什么啊

klzhu-zz avatar May 09 '22 10:05 klzhu-zz

@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 函数外面就的不到计算结果了

pandaye avatar Jul 19 '22 15:07 pandaye

@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 粘包了,这个教程里没有处理粘包问题

pandaye avatar Jul 19 '22 15:07 pandaye

Broadcast方法中,定义了 replyDone := reply == nil

if err == nil && !replyDone {
 reflect.ValueOf(reply).Elem().Set(reflect.ValueOf(clonedReply).Elem())
 replyDone = true
}

我想问的是为什么要在reply不为空的时候进行赋值呢

abcdhope avatar Sep 03 '22 01:09 abcdhope

gee-rpc/day6-load-balance/xclient/discovery.go:50 可以替换为

d.mu.RLock()
defer d.mu.RUnlock()

提升锁的并发度

Inuyasha-Monster avatar Nov 02 '22 08:11 Inuyasha-Monster

@yan0327 想请教一个问题。大家在测试Day6这个例子时,会不会出现发送消息卡死的现象。(具体体现为RPC服务器无法处理客户端发的请求,从而导致客户端由于未收到响应从而阻塞导致程序无法正常进行处理)

会的,而且大可能会,好像是个bug,没有得到解决方案。

China-zhang-hui avatar Apr 17 '23 14:04 China-zhang-hui