Dubbo/Dubbox、Google gRPC、RPCX、Spring Boot/Spring Cloud 如此多的RPC框架 咱们当然要理解下他们的原理呀
咱们以 LightRPC github.com/dollarkillerx/light 为例 写一个属于本人的RPC
最初的成绩是怎么的
https://github.com/dollarkill...
payload:
// 申请体strcut Request { Msg string}// 返回体struct Response { Msg string}
server:
// 定义根底服务struct HelloWorldServer {}func (h *HelloWorldServer) HelloWorld(ctx *light.Context, request *Request, response *Response) error { response.Msg = fmt.Sprintf("request: %s ",request.Msg) return nil}// 启动服务func main() { ser := server.NewServer() err := ser.RegisterName(&HelloWorldServer{}, "HelloWorldServer") // 注册 服务 if err != nil { log.Fatalln(err) } // 监听服务 if err := ser.Run(server.UseTCP("0.0.0.0:8074")); err != nil { log.Fatalln(err) } }
client:
client := client.NewClient(discovery.NewSimplePeerToPeer("127.0.0.1:8074", transport.TCP)) connect, err := client.NewConnect("HelloWorldServer") // 对特定服务 建设连贯 if err != nil { log.Fatalln(err) return } req := Request{ Msg: "hello", } resp := Response{} err = connect.Call(light.DefaultCtx(), "HelloWorld", &req, &resp) // 调用某个服务 if err != nil { log.Fatalln(err) } fmt.Println(resp)
这就是咱们要实现的根底服务, 咱们能够在这个服务之上增加 服务发现与注册 熔断器 监控 等等...
1. 实现服务外部注册
先看看server端的根底需要:
- [ ] 1. 一个server端能够注册多个服务
- [ ] 2. middleware
咱们先定义一个服务管理器 以治理多个服务
type MiddlewareFunc func(ctx *light.Context, request interface{}, response interface{}) error// 定义服务管理器type Server struct { serviceMap map[string]*service // 服务应用map的形式进行注册 options *Options // 相干的配置 beforeMiddleware []MiddlewareFunc // 全局前置middleware afterMiddleware []MiddlewareFunc // 全局后置middleware beforeMiddlewarePath map[string][]MiddlewareFunc // 特定路由 前置middleware afterMiddlewarePath map[string][]MiddlewareFunc // 特定路由 后置middleware}// 定义单个服务type service struct { name string // server name 服务名称 refVal reflect.Value // server reflect value refType reflect.Type // server reflect type methodType map[string]*methodType // server method 服务具体的办法}
咱们刚刚定义了这个服务 当初开始 实现服务的初始化代码
func NewServer() *Server { return &Server{ serviceMap: map[string]*service{}, options: defaultOptions(), beforeMiddleware: []MiddlewareFunc{}, afterMiddleware: []MiddlewareFunc{}, beforeMiddlewarePath: map[string][]MiddlewareFunc{}, afterMiddlewarePath: map[string][]MiddlewareFunc{}, }}
当初来编写服务注册 这是本章的重点 !!!
咱们会定义两个 服务注册的形式
- 通过 Register() 间接注册服务, 服务名称 设置为以后构造体的名称
- 通过 RegisterName() 进行服务注册, 能够传入服务名称 进行设置
func (s *Server) Register(server interface{}) error { return s.register(server, "", false)}func (s *Server) RegisterName(server interface{}, serverName string) error { return s.register(server, serverName, true)}// 具体服务注册办法func (s *Server) register(server interface{}, serverName string, useName bool) error { ser, err := newService(server, serverName, useName) // 生成一个服务 if err != nil { return err } s.serviceMap[ser.name] = ser // 放到serviceMap中去 return nil}
结构具体服务
func newService(server interface{}, serverName string, useName bool) (*service, error) { ser := &service{ refVal: reflect.ValueOf(server), refType: reflect.TypeOf(server), } // 获取服务名称 sName := reflect.Indirect(ser.refVal).Type().Name() if !utils.IsPublic(sName) { // IsPublic 判断 是否是Public return nil, pkg.ErrNonPublic } if useName { if serverName == "" { return nil, errors.New("Server Name is null") } sName = serverName } ser.name = sName // constructionMethods 获取以后构造体的 合规办法 进行注册 methods, err := constructionMethods(ser.refType) if err != nil { return nil, err } ser.methodType = methods for _, v := range methods { log.Println("Registry Service: ", ser.name, " method: ", v.method.Name) } return ser, nil}// constructionMethods Get specific methodfunc constructionMethods(typ reflect.Type) (map[string]*methodType, error) { methods := make(map[string]*methodType) for idx := 0; idx < typ.NumMethod(); idx++ { // 咱们对以后struct的办法进行遍历 找到合乎的办法进行注册 method := typ.Method(idx) mType := method.Type mName := method.Name if !utils.IsPublic(mName) { return nil, pkg.ErrNonPublic } // 默认是4个 if mType.NumIn() != 4 { // func(*server.MethodTest, *light.Context, *server.MethodTestReq, *server.MethodTestResp) error continue } // 测验它第一个参数是否是ctx ctxType := mType.In(1) if !(ctxType.Elem() == typeOfContext) { continue } // request 参数查看 requestType := mType.In(2) if requestType.Kind() != reflect.Ptr { continue } // 穷举的查看是否均所有参数均为 public if !utils.IsPublicOrBuiltinType(requestType) { continue } // response 参数查看 responseType := mType.In(3) if responseType.Kind() != reflect.Ptr { continue } if !utils.IsPublicOrBuiltinType(responseType) { continue } // 校验返回参数 if mType.NumOut() != 1 { continue } returnType := mType.Out(0) if returnType != typeOfError { continue } methods[mName] = &methodType{ method: method, RequestType: requestType, ResponseType: responseType, } } if len(methods) == 0 { return nil, pkg.ErrNoAvailable } return methods, nil}
下面咱们就实现了根底的服务注册了