Building RPC Systems That Don't Break
The send function needs locking because one rpcClient can send requests concurrently. The pending map stores calls that the client is currently processing. Each key uses seq as its identifier. Seq increases monotonically—it’s like numbering requests on the client side.
Register and Call
The server executes remote calls based on service, method, and request parameters. It returns responses after execution. How do you register a service? How do you find the method to execute from registered services? go-RPC uses reflection to provide type information.
Here’s the Server data structure. serviceMap saves all registered services. Service holds the service name, service type, and service instance. The instance is usually a pointer value. Method contains exported service methods, method names, parameter types, and response types.
Native RPC Pitfalls
Handle timeouts for Dial and encoding to avoid blocking:
The rpc.Dial function has no timeout. The system has no default timeout, so it may hang here. Use net.DialTimeout from the net package instead.
The rpc package uses gobCodec by default for encoding and decoding. Here io may hang without returning an error. Write your own codec with timeouts. Note that the server has timeouts for both read and write, but the client only has write timeouts. Reading cannot predict task completion time. This version of rpc works fine with hundreds of thousands of tasks.
Deep Dive into Go RPC Standard Library
// A Service object represents one service (including methods, parameter types, and return values)
type Service struct {
Method reflect.Method
ArgType reflect.Type
ReplyType reflect.Type
}
// Multiple services are organized in Server using a map for easy lookup and deduplication, with locking protection
// You can easily connect this to client.Call("A.Add", ...) which provides lookup information
type Server struct {
ServiceMap map[string]map[string]*Service
serviceLock sync.Mutex
}
// Use custom serialization and deserialization to convert objects into byte streams for network transmission
// Use net.Conn to send and receive TCP byte streams
Flow:
1. Establish TCP connection
2. Client calls call
3. Client gets return values