Re: [go-nuts] go-grpc question

2018-10-17 Thread nakuldesai88
Hi Josh,

Thanks for getting back ! Wouldn't having a single TCP connection be a 
bottleneck (assuming no layer-4 load balancer) especially if there is a 
slow reader, tcp flow control would limit other streams on that connection. 
In that case wouldn't having more connections help ?

Thanks,
Nakul

On Wednesday, October 17, 2018 at 6:26:00 AM UTC-7, Joshua Humphries wrote:
>
> *+grp...@googlegroups.com *
>
> *moving golan...@googlegroups.com  to BCC*
>
> In general, connections are not cheap, but stubs are. Actual 
> implementations for some languages differ, but Go complies with this.
>
> What that means is that, generally speaking, you should not try creating 
> the *grpc.ClientConn for each request. Instead create it once and cache 
> it. You *can* create the stub just once and cache it (they are safe to 
> use concurrently form multiple goroutines). But that is not necessary; you 
> could also create the stub for each request, using the cached connection.
>
> In practice, creating a new connection for each request will have overhead 
> in terms of allocations, creating and tearing down goroutines, and also in 
> terms of latency, to establish a new network connection every time. So it 
> is advisable to cache and re-use them. However, if you are not using TLS, 
> it *may be* acceptable to create a new connection per request (since the 
> network connection latency is often low, at least if the client and server 
> are in the same region/cloud provider). If you are using TLS, however, 
> creating a connection per request is a bit of an atrocity: you are not only 
> adding the extra latency of a TLS handshake to every request (typically 10s 
> of milliseconds IIRC), but you are also inducing a potentially huge amount 
> of load on the server, by making it perform many more digital signatures 
> (one of the handshake steps) than if the clients cached and re-used 
> connections.
>
> Historically, the only reason it might be useful to create a new 
> connection per request in Go was if you were using a layer-4(TCP) load 
> balancer. In that case, the standard DNS resolver would resolve to a single 
> IP address (that of the load balancer) and then only maintain a single 
> connection. This would result in very poor load balancing since 100% of 
> that client's requests would all route to the same backend. This would also 
> happen when using standard Kubernetes services (when using gRPC for 
> server-to-serve communication), as kubedns resolves a service name into a 
> single virtual IP. I'm not sure if the current state of the world regarding 
> TCP load balancers and the grpc-go project, but if it's still an issue and 
> you run services in Kubernetes, you can use a 3rd party resolver: 
> https://github.com/sercand/kuberesolver.
>
> 
> *Josh Humphries*
> jh...@bluegosling.com 
>
>
> On Wed, Oct 17, 2018 at 2:13 AM > wrote:
>
>> Hello,
>>
>> I intend to use grpc between two fixed endpoints (client and server) 
>> where the client receives multiple requests (the client serves as a proxy) 
>> which in turn sends a grpc request to the server. I wanted to know of the 
>> following would be considered good practice:
>>
>> a) For every request that comes in at the client, do the following in the 
>> http handler:
>>a) conn := grpc.Dial(...)// establish a grpc connection
>>b) client := NewClient(conn)// instantiate a new client
>>c) client.Something(..) // invoke the grpc method on 
>> the client
>>
>> i.e Establish a new connection and client in handling every request
>>
>> b) Establish a single grpc connection between client and server at init() 
>> time and then inside the handler, instantiate a new client and invoke the 
>> grpc method
>>a) client := NewClient(conn)// instantiate a new client
>>b) client.Something(..) // invoke the grpc method on 
>> the client 
>>
>> c) Establish a connection and instantiate a client at init() and then in 
>> every handler, just invoke the grpc method.
>>a) client.Something(..)
>>
>> The emphasis here is on performance as I expect the the client to process 
>> a large volume of requests coming in. I do know that grpc underneath 
>> creates streams but at the end of the day a single
>> logical grpc connection runs on a single TCP connection (multiplexing the 
>> streams) on it and having just one connection for all clients might not cut 
>> it. Thoughts and ideas appreciated !
>>
>> Thanks,
>> Nakul
>>
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to golang-nuts...@googlegroups.com .
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 

[go-nuts] go-grpc question

2018-10-17 Thread nakuldesai88
Hello,

I intend to use grpc between two fixed endpoints (client and server) where 
the client receives multiple requests (the client serves as a proxy) which 
in turn sends a grpc request to the server. I wanted to know of the 
following would be considered good practice:

a) For every request that comes in at the client, do the following in the 
http handler:
   a) conn := grpc.Dial(...)// establish a grpc connection
   b) client := NewClient(conn)// instantiate a new client
   c) client.Something(..) // invoke the grpc method on the 
client

i.e Establish a new connection and client in handling every request

b) Establish a single grpc connection between client and server at init() 
time and then inside the handler, instantiate a new client and invoke the 
grpc method
   a) client := NewClient(conn)// instantiate a new client
   b) client.Something(..) // invoke the grpc method on the 
client 

c) Establish a connection and instantiate a client at init() and then in 
every handler, just invoke the grpc method.
   a) client.Something(..)

The emphasis here is on performance as I expect the the client to process a 
large volume of requests coming in. I do know that grpc underneath creates 
streams but at the end of the day a single
logical grpc connection runs on a single TCP connection (multiplexing the 
streams) on it and having just one connection for all clients might not cut 
it. Thoughts and ideas appreciated !

Thanks,
Nakul


-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[go-nuts] Golang concurrency design question

2016-07-13 Thread nakuldesai88
I was going through the concurrent directory traversal program (similar to 
the unix du command) provided as an example in the "Go Programming 
Language" book (by Kernighan and Donovan). The example is on lines of the 
following (slightly modified to clarify the question):


*// semaphore to control the number of open file descriptorsvar sem = 
make(chan struct{}, 20)*

func dirents(dirName string) []os.FileInfo {
  




* defer func() {   <-sem   }()   // Acquire a semaphore to read a Dir   
sem <- struct{}{}*

entrySlice, err := ioutil.ReadDir(dirName)

if err != nil {
return nil
}
return entrySlice
}


func walkDir(directoryName string, filesizeChan chan int64, wg 
*sync.WaitGroup) {
 defer wg.Done()

 for _, entry := range dirents(name) {
 if entry.IsDir() {
  // if it is a directory, recurse 
  subDirName := ...
  wg.Add(1)
  go walkDir(...)
  } else {
  // if it is a file, send down the size
  filesizeChan <- entry.size 
 }
}
}

The above example basically recurses through a directory 
(ioutil.ReadDir()), if it is a file, then send its size, if it is a 
directory, recurse again.
A semaphore is used to control the number of open file descriptors (control 
ioutil.ReadDir()). Lets assume we have a deeply nested structure of files 
and directories, there
could potentially be 200 goroutines active in the system with only 20 
proceeding and the remaining blocked. This is because the program in the 
example first spawns a goroutine 
and then potentially blocks on the semaphore. 

Wouldn't is be better to first acquire the semaphore and then spawn the 
goroutine. This way we are limiting the number of the goroutines that would 
remain blocked at any given moment. i.e the walkDir function would look 
like this :
 
func walkDir(directoryName string, filesizeChan chan int64, wg 
*sync.WaitGroup) {
defer wg.Done()

   




* defer func() { <-sem}()// Acquire a semaphore be 
proceedingsem <- struct{}{}*

for _, entry := range dirents(name) {
 if entry.IsDir() {
  // if it is a directory, recurse 
  subDirName := ...
  wg.Add(1)
  go walkDir(...)
  } else {
  // if it is a file, send down the size
  filesizeChan <- entry.size 
 }
}
}


This approach would limit the number of goroutines active in a system. 
Wouldnt this be a better approach ? 
Essentially, the question boils downs to either spawn a goroutine and then 
block or block and then spawn a goroutine.

Thanks,
Nakul

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.