blog icon indicating copy to clipboard operation
blog copied to clipboard

动手写RPC框架 - GeeRPC第七天 服务发现与注册中心(registry) | 极客兔兔

Open geektutu opened this issue 5 years ago • 26 comments

https://geektutu.com/post/geerpc-day7.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 等多种传输协议。第七天实现了一个简单的注册中心(registry),具备超时移除、接收心跳(heartbeat)等能力,并且实现了一个简单的服务发现(server discovery)模块。

geektutu avatar Oct 08 '20 09:10 geektutu

大佬加油,已肝完,期待下一个7days

Shadow-linux avatar Nov 07 '20 19:11 Shadow-linux

@Shadow-linux 正在努力~ 🤡

geektutu avatar Nov 08 '20 03:11 geektutu

@geektutu @Shadow-linux 正在努力~ 🤡

兔兔加油!!!超棒

Pissssofshit avatar Nov 13 '20 02:11 Pissssofshit

已跟完,多谢兔兔的分享

ppd0705 avatar Dec 02 '20 03:12 ppd0705

谢谢大佬的教程。想请教一下,这个rpc 框架如果实际应用,如何在不同机器,部署多节点呢,现在看是起一个进程,多个协程实现多节点。

yanqic avatar Jan 13 '21 10:01 yanqic

照着撸完了,迷迷糊糊懵懵懂懂,感谢大佬!大佬牛逼!

MyShip-jpg avatar Jan 14 '21 03:01 MyShip-jpg

谢谢大佬的教程。想请教一下,这个rpc 框架如果实际应用,如何在不同机器,部署多节点呢,现在看是起一个进程,多个协程实现多节点。

@yanqi321 多台机器的话,main 函数中在启动 RPC 服务,配置好注册中心,在不同的机器上运行就好了。然后,再实现一个程序去调用服务。

geektutu avatar Jan 14 '21 14:01 geektutu

照着撸完了,迷迷糊糊懵懵懂懂,感谢大佬!大佬牛逼!

@MyShip-jpg 希望对你有帮助,以后使用其他开源的 RPC 框架时,就比较有底气了。

geektutu avatar Jan 14 '21 14:01 geektutu

这里是不是要考虑删除定时器,不然可能会引起内存泄漏

	go func() {
		t := time.NewTicker(duration)
		defer t.Stop()
		for err == nil {
			<-t.C
			err = sendHeartbeat(registry, addr)
		}
	}()

fy403 avatar Apr 14 '21 12:04 fy403

大部分照着撸完,最近刚开始学go,非常感谢大佬提供的项目练手,虽然还停留在比较迷糊的状态,但是总体上是有了一个了解,学到了挺多东西,日后会重新对项目整体进行一个思考并且对一些模块进行封装,改进并且建立自己的rpc体系框架,再次感谢大佬!

imtzer avatar Jul 21 '21 08:07 imtzer

大佬你好,day6和day7代码在跑的时候有几率出现以下错误,不知道为什么,希望大佬能指点一下问题可能出在哪里,谢谢大佬。

rpc server: read header error: gob: unknown type id or corrupted data call Foo.Sum error: read tcp [::1]:57188->[::1]:40693: read: connection reset by peer

DrGreenpepper avatar Jul 24 '21 02:07 DrGreenpepper

感谢兔大佬的分享!!!

cyj19 avatar Sep 23 '21 06:09 cyj19

@DrGreenpepper 大佬你好,day6和day7代码在跑的时候有几率出现以下错误,不知道为什么,希望大佬能指点一下问题可能出在哪里,谢谢大佬。

rpc server: read header error: gob: unknown type id or corrupted data call Foo.Sum error: read tcp [::1]:57188->[::1]:40693: read: connection reset by peer

我感觉是 tcp 粘包的问题。我在 NewClient 阶段,让服务器给客户端一个响应,问题好像就解决了

cuglaiyp avatar Jan 06 '22 09:01 cuglaiyp

有个问题,discovery 里面的服务列表还没过期,但是已经有服务宕掉了,请求就只能失败了?

cuglaiyp avatar Jan 06 '22 12:01 cuglaiyp

有个问题,注册中心里的服务列表存储的就是所有注册的地址,似乎没有服务和地址列表的映射关系呀。

okumiko avatar Mar 14 '22 12:03 okumiko

@DrGreenpepper 大佬你好,day6和day7代码在跑的时候有几率出现以下错误,不知道为什么,希望大佬能指点一下问题可能出在哪里,谢谢大佬。

rpc server: read header error: gob: unknown type id or corrupted data call Foo.Sum error: read tcp [::1]:57188->[::1]:40693: read: connection reset by peer

我感觉是 tcp 粘包的问题。我在 NewClient 阶段,让服务器给客户端一个响应,问题好像就解决了

请问具体是怎么解决的啊,能详细解释下嘛,我也遇到了这个问题

GGGrin8 avatar May 09 '22 10:05 GGGrin8

@okumiko 有个问题,注册中心里的服务列表存储的就是所有注册的地址,似乎没有服务和地址列表的映射关系呀。

不影响吧,注册中心只需要告诉客户端哪些服务可用就行了,然后对可用的服务发起访问;假设注册中心的map维护的是服务地址和服务实例,哪些地方需要去拿服务实例呢?我们要的只是客户端实例!

liujing-siyang avatar Aug 18 '22 09:08 liujing-siyang

谢谢兔兔,明白了很多概念~ 我在tcp 粘包的问题是这么做的: json.NewDecoder(conn).Decode(&opt) if err := json.NewEncoder(conn).Encode(opt); err != nil,json底层read可能过多取字节缓存,导致readRequestHeader()中cc.ReadHeader(&h)的"encoding/gob" decode(&h)时字节流可能缺少部分开头字节,我这里修改了往conn传入struct Option的方法,直接从conn输入取出option长度声明(option长度int32字段指定),这样完全取出option时不过多取出字节;

不过在DialHTTP中好像有个隐患,这我不太清楚,

  1. NewHTTPClient() --> (1. HTTP CONNECT方法交流,而后传输option字节流)
  2. Server的ServeHTTP(w http.ResponseWriter, req *http.Request)方法先确认CONNECT方法,而后Hijack()剥离conn,再调用ServeConn()方法,第一个步骤仍会是从conn中接受option的字节流
我的假设是net/http实现的交流会将tcp conn的所有字节取出,那么我下一次在已经建立的tcp conn连接上将会接收所有option字节(我不知道这个假设对不对,有没有后来者能解惑,谢谢了QAQ)
做了几次测试,发现没有乱码和错误

wandering-readily avatar Oct 17 '23 15:10 wandering-readily

@liujing-siyang

@okumiko 有个问题,注册中心里的服务列表存储的就是所有注册的地址,似乎没有服务和地址列表的映射关系呀。

不影响吧,注册中心只需要告诉客户端哪些服务可用就行了,然后对可用的服务发起访问;假设注册中心的map维护的是服务地址和服务实例,哪些地方需要去拿服务实例呢?我们要的只是客户端实例!

只有一种服务的时候,这种方法可行;但是如果有多种服务的时候,这种方法就不可行了,就应该搞一个服务名和服务实例的映射关系了。

SCUTking avatar Dec 02 '23 08:12 SCUTking

感觉registry与discover这两个东西可以合在一起,这样就不用discover再去发给请求获取registry的数据了。

SCUTking avatar Dec 03 '23 04:12 SCUTking

@SCUTking 感觉registry与discover这两个东西可以合在一起,这样就不用discover再去发给请求获取registry的数据了。

但是 Discovery 用于 Client 客户端负载均衡获取 Server 地址,Registry 则是需要启动 HTTP 服务的注册中心,仅用来返回可用 Server 地址,这两个在这里的 RPC 情况下是不能耦合在一起的

KamePan avatar Jan 19 '24 02:01 KamePan

太帅了

galakelex avatar Mar 16 '24 12:03 galakelex