Simple RPC framework in 300 lines of Go
github.com
github.com
Related: Scott Mansfield of Netflix gave a talk at Gophercon 2017 on their custom serialization format if these things are interesting to you... https://github.com/gophercon/2017-talks/blob/master/ScottMan...
That is,
1. deploy the modules within the same process then the method invocation is most efficient;
2. deploy the module across separate OS processes on the same machine then the method invocation is via the best available OS IPC mechanism;
3. deploy the module across separate machines then the method invocation is over network with most efficient remote procedure call implementation.
A long time ago I worked on a project that used Corba (with ACE TAO) that had facilities like this and it made development, testing environments vs various production environment permutations a lot easier to build for and manage over multiple product lifecycles. Now-a-days, these Microservices frameworks are missing these (basic) features and it overly complicates the deployment scenarios.
Rather than hand-rolling 300 line custom RPC mechanisms like this one, I would rather prefer a more complete one that did solve the above problems.
- You cannot instantiate a piece of code built on top of a GRPC client directly on top of another piece of code that implements a GRPC service. You will need to create a full GRPC client and server. Don't want to let them communicate over an OS-level socket? You'll have to use something like https://godoc.org/google.golang.org/grpc/test/bufconn to create an in-memory socket.
- You cannot let a GRPC server process forward requests to a GRPC client directly. Quite annoying in case you want to multiplex requests, add an authenticating proxy, etc. etc.
- Unit testing a GRPC service is annoying, as the service implementation has to take some concrete GRPC types that can only be instantiated by a GRPC server. This means that you also have to create a full GRPC client/server/bufconn to be able to test it.
This whole thing raises the question though, is this hard to do in other languages?
The Server package contains the Register function. Main package implements the QueryUser function that does the work of querying the DB. When Main calls Server.Register to register the function with Server, it sends the function name (QueryUser) and..something else? Is that the memory address of QueryUser on my computer? And when Server actually runs the function, it's just pointing to QueryUser at the memory address given to it by Main?
If that's the case, am I correct in thinking that this wouldn't work as written if the Server package were running on a different physical server, because it obviously wouldn't be able to access the memory location of QueryUser on a different machine. So in this case, the Server would need to implement QueryUser itself on its hardware, but otherwise would work.
Or maybe the use case of RPCs isn't for two servers communicating, but rather for two different programs on the same machine only? Or maybe what Server.Register receives is the actual function, not just the memory location (though I see no evidence of this).
Can someone help enlighten me?
This is correct, let me unpack this a little more.
The 'Register' function tells the server object that when a client tries to call the function "QueryUser" call the function passed as the second parameter and send back the result.
the client object's "CallRPC" functions tells the client object that i know that there is a function called "QueryUser" that the server know about and it has the same structure as the second parameter, when i call the second parameter, call the server with the arguments passed. The client object then creates a stub implementation which when called, creates a connection to the server, tell the server to call the function "QueryUser" with the given parameters, reads the results and returns the result.
The "Remote" part of RPC is done over the transport package which the main function is mostly unaware of.
https://golang.org/pkg/encoding/gob/
Gob is apparently out of the box with Go.
I'm still learning through Go, there's so much available OOTB that I love about Go. I wish other languages would take Go's Standard Library as a good example of things to include with a language. I can do web applications entirely with Go's standard libraries. Course then you gotta worry about storing data in some database, but those libraries are usually done by Database vendors or the language community.
Lack of interop with other languages is still a bad idea (the lesson of Java RMI), and I thought Google agreed. Having all the C++ and Java and Python services speaking Stubby was one of the most futuristic experiences there.
And as for .NET, Python I never saw any reference about such regrets, while ISO C++ is still discussing papers for some kind of future support via static reflection.
Here’s a discussion for .NET core not adding support for security reasons (eventually overruled for backwards compatibility reasons unfortunately). https://github.com/dotnet/corefx/issues/6564#issuecomment-21...
Java: https://www.bleepingcomputer.com/news/security/oracle-plans-...
Also the official path forward for WCF is gRPC, which also supports binary serialization.
As per Java, Brian Goetz has spoken multiple times about it, but the issue was mainly due to how the whole thing is designed, not necessarily due to using binary formats.