In grpc-go, when implementing a service, the service interface defines methods contains only Context and Request. From the source of the Context, it is as simple as
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
So I wonder if it is possible to get some metadata (including remote IP address and other data) to maintain a session.
Thanks.
There's nothing that gRPC provides (in any language) that would be particularly robust as a session system across requests.
The streaming mechanism is great when you need to maintain context on a single server for clients: the stream callback's stack can point to whatever session information you need.
If you need state across separate RPC's (or across machines) you'll need to add your own session layer. You could do this by creating some unique id that you attach to (say) a 'my-session-id' metadata element when sending requests.
It's possible to retrieve remote IP address through the use of stats.Handler (see especially this struct https://github.com/grpc/grpc-go/blob/v1.20.x/stats/stats.go#L89).
grpc.Metadata is commonly used to store arbitrary information about sessions.
Related
Lets say I have a global net/http client in my program. Within this program, I have several goroutines making requests with the same global client. E.g.
Golang Pseudocode:
package main
func editTransportAndFetch(c *http.Client) {
c.Transport = &http.Transport{
// Make some unique change here
}
c.Get("https://www.google.com")
}
func main() {
client := http.Client
// Spawns 10 processes
for i := 0; i < 10; i++ {
go editTransportAndFetch(client)
}
}
In this pseudocode example, I demonstrate spawning 10 processes of the http.Transport being edited. In the case of this example, the same exact change is being made, so maybe interference isn't much of a concern. However, regardless, if these processes are happening concurrently, will one process updating the global client's transport interfere with the transport that a different process may be using?
My ultimate use case is that I would like to have a global client and be able to specify a custom DialTLSContext but only for certain requests. Requests that I don't want using the DialTLSContext may be running concurrently as well. I'm worried that if I edit the http.Transport of the client of one request that it may interfere and cause another request to also use DialTLSContext even though I don't want it to.
If you share the same client instance among multiple goroutines and if you modify that client from one of them, the behavior is undefined because it is a data race.
If you want to modify the client for some of the goroutines, there's no need to use a single client, and you can create a new client for every goroutine.
If you want to configure one client in main, and use that as a template for all goroutines, pass the client by value, not *client, so a copy of that template is passed to each goroutine, and each goroutine would work on its own copy, sharing the common Transport underneath. If you set the Transport to something else, then since the Client is a copy, it is still safe.
If you however modify something in the Transport instance (which is a RoundTripper), that is again a race condition. Don't do that.
Http clients are thread safe according to the docs (https://golang.org/src/net/http/client.go):
Clients are safe for concurrent use by multiple goroutines.
Let's say you have an application like a bookstore, and you split it into two simple microservices in the backend ->
Microservice 1: Book purchasers (with Accounts)
Microservice 2: Book list.
Let's say you make a request from the front end, goes into a reverse proxy and the request goes to microservice 1.
How exactly can you visualize how microservice 1 communicates with microservice 2?
Do you containerize microservices, and inside it you have a grpc client and server?
Does the client communicate with microservice 1's server and also microservice 2's server?
In this image here it looks like you containerize the client and server separately...?
How exactly does gRPC communicate between microservices?
IIUC you are asking how the gRPC server implements the functionality described by the protobuf?
I think you're referring to this example
The protobuf compiler generates client and server stubs that you must implement. You can implement these in any language implementation. When you implement the server, you are entirely responsible for ensuring that e.g. ListBooks() (for a shelf) returns any books added to the shelf by CreateBook().
The implementation is independent of gRPC.
rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {}
rpc CreateBook(CreateBookRequest) returns (Book) {}
gRPC conceptually simply ensures that your client(s) think they're calling a local method: CreateBook() when, in fact, they're calling a local stub that transfer the request over a network to the remote server that receives the CreateBook() request and does something about it.
So, let's focus on the server, it will likely use some form of persistence to record shelves and books. In practice this will be some of database:
type Server struct {
db db
}
func (s *Server) CreateBook(r *pb.CreateBookRequest) {
shelf := s.db.Get(r.get_shelf())
shelf.Add(r.get_book())
}
func (s *server) ListBooksRequest(r *pb.ListBooksRequest) {
shelf := s.db.Get(r.get_shelf())
for _, book := range shelf.Get() {
fmt.Println(book)
}
}
NOTE In the above, the server implementation of the gRPC service includes a database connection that, the gRPC methods use to interact with the database. This could represent some other micro-service too...turtles all the way!
So, to answer your question, somewhere in the bowels of your micro-services, there's some form of shared state (e.g. database or similar) where e.g. books are persisted (in shelves).
Whether the clients and|or servers are containerized, while probably good practice, is irrelevant to the question of how communication occurs.
I am the first scholar of grpc. I think it is an ugly question.
A simple chat application is created using grpc-go. and want to achieve is something like this.
#Each of clientA, clientB, clientC, connects to serverA, and has a bidirectional stream connection.
For example, if you want to notify clientA, B, C that clientD has connected to serverA, what kind of implementation method is there?
How to broadcast in gRPC from server to client?
gRPC: How can I distinguish bi-streaming clients at server side?
I have read these posts, but I would like to know the best practices.
For example, when creating a client list and notifying there, how should this be code?
I wrote it down because it was self-solving.
https://github.com/rodaine/grpc-chat
This project was very helpful.
type server struct {
ClientStreams map [string] chan chat.StreamResponse
}
In this way, a map that stores the stream of the client, here map, but slice or sync.Map may be used.
By connecting the information from the client to the structure when the stream was opened, we were able to support broadcasting and managing the number of connections.
I am having trouble understanding ProxyFromEnvironment and ProxyURL in net/http package. Can someone please explain me when and why these two functionalities are used?
My current understanding (at least for ProxyFromEnvironment) is that this is used to get the URL of a PROXY Server from the Environment Variables and this PROXY Server is used to make HTTP Requests.
Both functions are related to how you use the http.Transport mechanism.
One can be used to allow the transport to dynamically retrieve the proxy settings from the environment, the other can be used to provide a static URL to be used by the transport for the proxy every time.
ProxyFromEnvironment is a func that returns a URL describing the proxy that is configured in the Environment; it can be assigned to the Transport.Proxy field, and every time the Transport makes a request, the Proxy will depend on the values in the Environment.
ProxyURL is a func that returns a general func which returns the given URL every time it is invoked; it can be used to generate a helper function to assign to the Transport.Proxy field, so that your Transport has a consistent Proxy every time the Transport makes a request.
I have a web service that is running on IIS (6 or 7, doesn't matter) and I would like to know the port that the caller has sent their request/invocation from.
So if a client makes a call on my web service, how do I find out from the server side what the port number is they made the call from?
Is that something that even gets passed at even the lowest level? Just to be clear I'm not looking for the port for callback purposes. It's for logging only.
You should be able to find it as "REMOTE_PORT" in the server variables of the Server object.
However, this port should pretty much always be random, and is only active for the Request/Response pair the client is making. It should be can't be used for asynchronous call backs. Even your webservice when calling to someother service will use a random port number to initiate the request from. The only static port in the communication is the receiving port at the server end of the TCP connection.
If you service is on WCF, then:
OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
var endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name]
as RemoteEndpointMessageProperty;
if (endpointProperty != null)
{
string sRemoteAddress = endpointProperty.Address;
int nRemotePort = endpointProperty.Port;
}
TCP sockets do have the concept of sender port number but it doesn't have much use in application level protocols. That said, considering the last paragraph of the OP, I think you're looking for some way to call back the client. The ports I said previously cannot be used for that. Asynchronous requests are identical to synchronous ones running on a separate thread, nothing special about them.
Some Network Address Translation-type devices will hide the actual "sending" port number from you. You would then have access to a useless IP address and a useless port number.