GithubHelp home page GithubHelp logo

gorpc's Introduction

gorpc

Simple, fast and scalable golang RPC library for high load and microservices.

Gorpc provides the following features useful for highly loaded projects with RPC:

  • It minimizes the number of connect() syscalls by pipelining request and response messages over a single connection.

  • It minimizes the number of send() syscalls by packing as much as possible pending requests and responses into a single compressed buffer before passing it into send() syscall.

  • It minimizes the number of recv() syscalls by reading and buffering as much as possible data from the network.

  • It supports RPC batching, which allows preparing multiple requests and sending them to the server in a single batch.

These features help the OS minimizing overhead (CPU load, the number of TCP connections in TIME_WAIT and CLOSE_WAIT states, the number of network packets and the amount of network bandwidth) required for RPC processing under high load.

Additionally gorpc provides the following features missing in net/rpc:

  • Client automatically manages connections and automatically reconnects to the server on connection errors.
  • Client supports response timeouts.
  • Client supports RPC batching.
  • Client supports async requests' canceling.
  • Client prioritizes new requests over old pending requests if server fails to handle the given load.
  • Client detects stuck servers and immediately returns error to the caller.
  • Client supports fast message passing to the Server, i.e. requests without responses.
  • Both Client and Server provide network stats and RPC stats out of the box.
  • Commonly used RPC transports such as TCP, TLS and unix socket are available out of the box.
  • RPC transport compression is provided out of the box.
  • Server provides graceful shutdown out of the box.
  • Server supports RPC handlers' councurrency throttling out of the box.
  • Server may pass client address to RPC handlers.
  • Server gracefully handles panic in RPC handlers.
  • Dispatcher accepts functions as RPC handlers.
  • Dispatcher supports registering multiple receiver objects of the same type under distinct names.
  • Dispatcher supports RPC handlers with zero, one (request) or two (client address and request) arguments and zero, one (either response or error) or two (response, error) return values.

Dispatcher API provided by gorpc allows easily converting usual functions and/or struct methods into RPC versions on both client and server sides. See Dispatcher examples for more details.

By default TCP connections are used as underlying gorpc transport. But it is possible using arbitrary underlying transport - just provide custom implementations for Client.Dial and Server.Listener. RPC authentication, authorization and encryption can be easily implemented via custom underlying transport and/or via OnConnect callbacks. Currently gorpc provides TCP, TLS and unix socket transport out of the box.

Currently gorpc with default settings is successfully used in highly loaded production environment serving up to 40K qps. Switching from http-based rpc to gorpc reduced required network bandwidth from 300 Mbit/s to 24 Mbit/s.

Docs

See http://godoc.org/github.com/valyala/gorpc .

Usage

Server:

s := &gorpc.Server{
	// Accept clients on this TCP address.
	Addr: ":12345",

	// Echo handler - just return back the message we received from the client
	Handler: func(clientAddr string, request interface{}) interface{} {
		log.Printf("Obtained request %+v from the client %s\n", request, clientAddr)
		return request
	},
}
if err := s.Serve(); err != nil {
	log.Fatalf("Cannot start rpc server: %s", err)
}

Client:

c := &gorpc.Client{
	// TCP address of the server.
	Addr: "rpc.server.addr:12345",
}
c.Start()

// All client methods issuing RPCs are thread-safe and goroutine-safe,
// i.e. it is safe to call them from multiple concurrently running goroutines.
resp, err := c.Call("foobar")
if err != nil {
	log.Fatalf("Error when sending request to server: %s", err)
}
if resp.(string) != "foobar" {
	log.Fatalf("Unexpected response from the server: %+v", resp)
}

Both client and server collect connection stats - the number of bytes read / written and the number of calls / errors to send(), recv(), connect() and accept(). This stats is available at Client.Stats and Server.Stats.

See tests for more usage examples.

gorpc's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gorpc's Issues

add benchmark results to docs

You state your library is high performace, but It'd be great if the docs would contain some performance numbers/ benchmarks compared to net/rpc. Especially for different workloads (small requests, large requests with byte slices, ...).

windows call timeout

go version go1.5.1 windows/amd64

go test -run ExampleDispatcher_serviceCalls

--- FAIL: ExampleDispatcher_serviceCalls (120.06s)
got:
Get=, gorpc.Client: [:7892]. Cannot obtain response during timeout=20s
Get=, gorpc.Client: [:7892]. Cannot obtain response during timeout=20s
Set=, gorpc.Client: [:7892]. Cannot obtain response during timeout=20s, 456

GetError42=, gorpc.Client: [:7892]. Cannot obtain response during timeout=2
0s
GetError42=, gorpc.Client: [:7892]. Cannot obtain response during timeout=2
0s
DDDD=, gorpc.Client: [:7892]. Cannot obtain response during timeout=20s
want:
Get=123,
Get=456,
Set=, , 78
GetError42=78,
GetError42=, error42
DDDD=13,
FAIL
exit status 1

Custom Encoding

Hi,

Is possible to use proto buffers instead of gob as encoding?

Thanks

WS supporting

Greetings! I am iteresting to handle connection via WS and redirect message to json-rpc. There is method: jsonrpc.ServeConn(conn *websocket.Conn) in the standart library, but i couldn't understand - is't possible to do something similar here?

Consider exposing gorpc.Server.ServeConn

net/rpc exposes ServeConn to attach net/rpc server to existing network connection,
it does not seem possible to achieve the same using this library
i.e. I want to use custom code to accept and manage my server connections

Build is breaking under go older than 1.4

as of a pull right now.

../../../valyala/gorpc/client.go:553: undefined: atomic.Value
../../../valyala/gorpc/server.go:187: undefined: atomic.Value
../../../valyala/gorpc/server.go:240: undefined: atomic.Value

Dispatcher type validation is probably a bit too strict (bug)

Hi,

I was trying to pass a struct containing a time.Time object between the server and the client and I got the following panic just after running:

gorpc.Dispatcher: response in the function [Foo.Bar] cannot contain struct without exported fields [time.Time] in the field [Start] of struct [foo.Result]

It appears that the dispatcher, in the validateType function, checks for at least one exported field in each struct it sees and therefore reject time.Time which has none. This seems overly strict because time.Time implements the GobEncoder and GobDecoder interfaces even with no exported fields and therefore should be able to pass on the wire without problem.

I am fairly new to Golang and therefore have no idea how this could be fixed but I am under the impression that it is a bug of gorpc and not an intended feature.

Could you have a look, please?

Best,

HLG

thread-safe?

The docs don't mention if the client is thread/go-routine safe. Would be great to have that information.

Is it possible to add support of struct{}?

In many cases sets implemented as map[T]struct{}. It would be nice to support it to avoid extra convertion on both server and client sides.

Currently Dispatcher AddFunc panics:

... cannot contain struct without exported fields [struct {}] in the value of map...

I could implement custom GobDecoder/GobDecoder for map[T]struct{}-type in my code, but it would be nice if gorpc supports it.

the docs make me confused, is there any project for reference?

I have seen the example_test.go, but I still feel confused about how to use gorpc. For exmaple, if my implementation of client and server is segregative, how can I use code like this
d := NewDispatcher() s := NewTCPServer("127.0.0.1:12445", d.NewHandlerFunc()) c := NewTCPClient("127.0.0.1:12445") dc := d.NewFuncClient(c)
And I feel confused that whether rpc call need a connection pool or not.
Thanks!

Dispatcher couples server and client

It seems that you need to register functions or services with the Dispatcher that are both used by the client and server. Because of this I'm not able to build the server and client code separately. I'd like to see the dispatcher decoupled from the server and client.

I don't have any idea what is a nice way to implement this. Could you give directions, than I can create a pull request with the changes.

Simpler compression library

I tried to create simple streaming compression library for this project

https://github.com/funny-falcon/go-funlz

Format derived from lzf. It is byte oriented, minimum compressed chunk is 4 bytes, backref window is 4096 bytes. It uses circular buffer of 8096 bytes for buffering uncompressed bytes. It does no output buffering.

Compression is just 1.5 faster than compress/flate, but decompression is up to 2-10 times faster.

ConnStats.Snapshot example please

Just a bit of pseudo code would be great...

d := gorpc.NewDispatcher()   
s := gorpc.NewTCPServer("127.0.0.1:43216", d.NewHandlerFunc())
s.Start()
stats := ??? Snapshot()

How to coordinate physically seperate servers and clients

I'm sure I'm missing something extremely trivial here, but am stuck. I'd like to implement a server on one computer that has a registered service, call it "Ping", that can be called from a client on another server and respond with "Pong".

Per https://godoc.org/github.com/valyala/gorpc#example-Dispatcher--FuncCalls the client wrapper is established as dc := d.NewFuncClient(c).

My concern is that d is not defined in a client only applet.

If I reference the NewTCPClient directly, with a call like c.Call("Ping") the server will error out with:

gorpc.Dispatcher: unsupported request type received from the client: string

Obviously I'm missing something basic, please clue me in.

Server side pseudo code:

 d := gorpc.NewDispatcher()
 d.AddFunc("Ping", func () string {return "Pong"})
 s := gorpc.NewTCPServer("localhost:1234",d.NewHandlerFunc())
 s.Start()

Client side pseudo code:

 c := gorpc.NewTCPClient("localhost:1234")
 c.Start()
 c.Call("Ping")

I've also tried:

d := gorpc.NewDispatcher()
c := gorpc.NewTCPClient("localhost:1234")
c.Start()
dc := d.NewFuncClient(c)
resp, err := dc.Call("Ping", nil)

Which results in a " Error when reading handshake from client: [EOF]" error since no d.AddFunc() has been called.

My brain is having problems groking that the client code would need any details beyond a function name that the server handles.

I did find that if I used the 2nd approach and added a d.AddFunc("Ping", func() {}) prior to the dc assignment it works.

Really not clear if that is the right way though or if I just hacked it... Comments please.

GoRPC on 32 bits platforms

Hello,

Since I ran into this issue and I cannot upgrade my machine for now, I am stuck with 32 bits mode.
I think that the stats could just be made uint32 on 32 bits platforms and left as is on 64 bits ones.

What do you think?

Pierre

Dispatcher.AddService: allow clients to register interfaces

Currently Dispatcher.AddService requires a *struct to be registered. For clients that is not convenient, the options are to register the actual struct used on the server side, but that will pull in more code than necessary into the client or create a dummy struct on the client side with dummy methods that match the server side struct.
It would be nice to just have a common interface that can be shared by both the server and the client side. The server would have to register a concrete impl of that interface of course, but that struct would be known to the server only, while the client could register just the interface so that it can make calls.

Cannot decode request

Hi,

When running example code from README:

2015/08/11 12:31:48 Obtained request foobar from the client 127.0.0.1:62891
2015/08/11 12:31:48 gorpc.Server: [127.0.0.1:62891]->[:12345]. Cannot decode request: [unexpected EOF]

bidirectional support

Powerfull code.

You have in your roadmap the bidirectional support.

-- x --
I work in an simple server that resolve transactions and route message between different peers in bidirectional mode.

You can imagine, the lots concerns and pitfalls when using tcpsockets, channels, goroutines and so on.

It's like many services with an central coordinator.

--- x ---
I can assign an port to each service, and set it's to server-RPC, and an client-RPC to Server-resolver.

Finally, the Server-resolver it's an client-RPC of all services.

Please, your comments.

Thank's.
JM

Is this still a better choice than golang roc?

I see the last commit is more than two years ago, so I would like to know whether this is better choice if I want to use it in high-load servers with large request size (~200K content per request on average).

Client connection cause server panic on ARM

Hi,

As title, it seems to relate to golang/go#23345.
Is there any way to avoid this problem?

Here is my test steps.

  1. Sample code
package main

import (
	"log"
	"time"
	"github.com/valyala/gorpc"
)

func main() {
	go func() {
		s := &gorpc.Server{
			// Accept clients on this TCP address.
			Addr: "0.0.0.0:12345",
	
			// Echo handler - just return back the message we received from the client
			Handler: func(clientAddr string, request interface{}) interface{} {
				log.Printf("Obtained request %+v from the client %s\n", request, clientAddr)
				return request
			},
		}
		if err := s.Serve(); err != nil {
			log.Fatalf("Cannot start rpc server: %s", err)
		}	
	}()
		
	c := &gorpc.Client{
		// TCP address of the server.
		Addr: "127.0.0.1:12345",
	}
	c.Start()
	time.Sleep(3 * time.Second)

	// All client methods issuing RPCs are thread-safe and goroutine-safe,
	// i.e. it is safe to call them from multiple concurrently running goroutines.
	resp, err := c.Call("foobar")
	if err != nil {
		log.Fatalf("Error when sending request to server: %s", err)
	}
	if resp.(string) != "foobar" {
		log.Fatalf("Unexpected response from the server: %+v", resp)
	}
	log.Printf("resp: %v", resp)
}
  1. Use go1.9, and build with GOARCH=arm GOARM=7 GOOS=linux go build -o testgorpc ./main.go
  2. Run testgorpc and get panic as the client connects to the server.
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x4 pc=0x114fc]

goroutine 8 [running]:
sync/atomic.addUint64(0x10598084, 0x1, 0x0, 0x10523708, 0x11afb4)
	/usr/local/go/src/sync/atomic/64bit_arm.go:31 +0x4c
github.com/valyala/gorpc.(*ConnStats).incAcceptCalls(0x10598034)
	/go/src/github.com/valyala/gorpc/conn_stats_generic.go:87 +0x34
github.com/valyala/gorpc.serverHandler(0x10598000, 0x10518300)
	/go/src/github.com/valyala/gorpc/server.go:207 +0x1b0
created by github.com/valyala/gorpc.(*Server).Start
	/go/src/github.com/valyala/gorpc/server.go:158 +0x2e8

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.