- Notifications
You must be signed in to change notification settings - Fork408
An efficient, extensible and easy-to-use RPC framework.
License
andeya/erpc
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
eRPC is an efficient, extensible and easy-to-use RPC framework.
Suitable for RPC, Microservice, Peer-to-Peer, IM, Game and other fields.
go vesion ≥ 1.18
install
GO111MODULE=on go get -u -v -insecure github.com/andeya/erpc/v7
- import
import"github.com/andeya/erpc/v7"
- Use peer to provide the same API package for the server and client
- Provide multi-layout abstractions such as:
- peer
- session/socket
- router
- handle/context
- message
- protocol
- codec
- transfer filter
- plugin
- Support reboot and shutdown gracefully
- HTTP-compatible message format:
- Composed of two parts, the
Header
and theBody
Header
contains metadata in the same format as HTTP headerBody
supports for custom codec of Content Type-Like, already implemented:- Protobuf
- Thrift
- JSON
- XML
- Form
- Plain
- Support push, call-reply and more message types
- Composed of two parts, the
- Support custom message protocol, and provide some common implementations:
rawproto
- Default high performance binary protocoljsonproto
- JSON message protocolpbproto
- Ptotobuf message protocolthriftproto
- Thrift message protocolhttproto
- HTTP message protocol
- Optimized high performance transport layer
- Use Non-block socket and I/O multiplexing technology
- Support setting the size of socket I/O buffer
- Support setting the size of the reading message (if exceed disconnect it)
- Support controling the connection file descriptor
- Support a variety of network types:
tcp
tcp4
tcp6
unix
unixpacket
kcp
quic
- other
- websocket
- evio
- Provide a rich plug-in point, and already implemented:
- auth
- binder
- heartbeat
- ignorecase(service method)
- overloader
- proxy(for unknown service method)
- secure
- Powerful and flexible logging system:
- Detailed log information, support print input and output details
- Support setting slow operation alarm threshold
- Support for custom implementation log component
- Client session support automatically redials after disconnection
Self Test
A server and a client process, running on the same machine
CPU: Intel Xeon E312xx (Sandy Bridge) 16 cores 2.53GHz
Memory: 16G
OS: Linux 2.6.32-696.16.1.el6.centos.plus.x86_64, CentOS 6.4
Go: 1.9.2
Message size: 581 bytes
Message codec: protobuf
Sent total 1000000 messages
erpc
client concurrency | mean(ms) | median(ms) | max(ms) | min(ms) | throughput(TPS) |
---|---|---|---|---|---|
100 | 1 | 0 | 16 | 0 | 75505 |
500 | 9 | 11 | 97 | 0 | 52192 |
1000 | 19 | 24 | 187 | 0 | 50040 |
2000 | 39 | 54 | 409 | 0 | 42551 |
5000 | 96 | 128 | 1148 | 0 | 46367 |
- erpc/socket
client concurrency | mean(ms) | median(ms) | max(ms) | min(ms) | throughput(TPS) |
---|---|---|---|---|---|
100 | 0 | 0 | 14 | 0 | 225682 |
500 | 2 | 1 | 24 | 0 | 212630 |
1000 | 4 | 3 | 51 | 0 | 180733 |
2000 | 8 | 6 | 64 | 0 | 183351 |
5000 | 21 | 18 | 651 | 0 | 133886 |
Comparison Test
Environment | Throughputs | Mean Latency | P99 Latency |
---|---|---|---|
![]() | ![]() | ![]() | ![]() |
- Profile torch of erpc/socket
- Heap torch of erpc/socket
package mainimport ("fmt""time""github.com/andeya/erpc/v7")funcmain() {defererpc.FlushLogger()// gracefulgoerpc.GraceSignal()// server peersrv:=erpc.NewPeer(erpc.PeerConfig{CountTime:true,ListenPort:9090,PrintDetail:true,})// srv.SetTLSConfig(erpc.GenerateTLSConfigForServer())// routersrv.RouteCall(new(Math))// broadcast per 5sgofunc() {for {time.Sleep(time.Second*5)srv.RangeSession(func(sess erpc.Session)bool {sess.Push("/push/status",fmt.Sprintf("this is a broadcast, server time: %v",time.Now()),)returntrue})}}()// listen and servesrv.ListenAndServe()}// Math handlertypeMathstruct {erpc.CallCtx}// Add handles addition requestfunc (m*Math)Add(arg*[]int) (int,*erpc.Status) {// test metaerpc.Infof("author: %s",m.PeekMeta("author"))// addvarrintfor_,a:=range*arg {r+=a}// responsereturnr,nil}
package mainimport ("time""github.com/andeya/erpc/v7")funcmain() {defererpc.SetLoggerLevel("ERROR")()cli:=erpc.NewPeer(erpc.PeerConfig{})defercli.Close()// cli.SetTLSConfig(&tls.Config{InsecureSkipVerify: true})cli.RoutePush(new(Push))sess,stat:=cli.Dial(":9090")if!stat.OK() {erpc.Fatalf("%v",stat) }varresultintstat=sess.Call("/math/add", []int{1,2,3,4,5},&result,erpc.WithAddMeta("author","andeya"), ).Status()if!stat.OK() {erpc.Fatalf("%v",stat) }erpc.Printf("result: %d",result)erpc.Printf("Wait 10 seconds to receive the push...")time.Sleep(time.Second*10)}// Push push handlertypePushstruct { erpc.PushCtx}// Push handles '/push/status' messagefunc (p*Push)Status(arg*string)*erpc.Status {erpc.Printf("%s",*arg)returnnil}
NOTE:
- It is best to set the packet size when reading:
SetReadLimit
- The default packet size limit when reading is 1 GB
// Start a servervarpeer1=erpc.NewPeer(erpc.PeerConfig{ListenPort:9090,// for server role})peer1.Listen()...// Start a clientvarpeer2=erpc.NewPeer(erpc.PeerConfig{})varsess,err=peer2.Dial("127.0.0.1:8080")
typeAaastruct { erpc.CallCtx}func (x*Aaa)XxZz(arg*<T>) (<T>,*erpc.Status) {...returnr,nil}
- register it to root router:
// register the call route// HTTP mapping: /aaa/xx_zz// RPC mapping: Aaa.XxZzpeer.RouteCall(new(Aaa))// or register the call route// HTTP mapping: /xx_zz// RPC mapping: XxZzpeer.RouteCallFunc((*Aaa).XxZz)
The default mapping(HTTPServiceMethodMapper) of struct(func) name to service methods:
AaBb
->/aa_bb
ABcXYz
->/abc_xyz
Aa__Bb
->/aa_bb
aa__bb
->/aa_bb
ABC__XYZ
->/abc_xyz
Aa_Bb
->/aa/bb
aa_bb
->/aa/bb
ABC_XYZ
->/abc/xyz
erpc.SetServiceMethodMapper(erpc.HTTPServiceMethodMapper)
The mapping(RPCServiceMethodMapper) of struct(func) name to service methods:
AaBb
->AaBb
ABcXYz
->ABcXYz
Aa__Bb
->Aa_Bb
aa__bb
->aa_bb
ABC__XYZ
->ABC_XYZ
Aa_Bb
->Aa.Bb
aa_bb
->aa.bb
ABC_XYZ
->ABC.XYZ
erpc.SetServiceMethodMapper(erpc.RPCServiceMethodMapper)
funcXxZz(ctx erpc.CallCtx,arg*<T>) (<T>,*erpc.Status) {...returnr,nil}
- register it to root router:
// register the call route// HTTP mapping: /xx_zz// RPC mapping: XxZzpeer.RouteCallFunc(XxZz)
typeBbbstruct { erpc.PushCtx}func (b*Bbb)YyZz(arg*<T>)*erpc.Status {...returnnil}
- register it to root router:
// register the push handler// HTTP mapping: /bbb/yy_zz// RPC mapping: Bbb.YyZzpeer.RoutePush(new(Bbb))// or register the push handler// HTTP mapping: /yy_zz// RPC mapping: YyZzpeer.RoutePushFunc((*Bbb).YyZz)
// YyZz register the handlerfuncYyZz(ctx erpc.PushCtx,arg*<T>)*erpc.Status {...returnnil}
- register it to root router:
// register the push handler// HTTP mapping: /yy_zz// RPC mapping: YyZzpeer.RoutePushFunc(YyZz)
funcXxxUnknownCall (ctx erpc.UnknownCallCtx) (interface{},*erpc.Status) {...returnr,nil}
- register it to root router:
// register the unknown call route: /*peer.SetUnknownCall(XxxUnknownCall)
funcXxxUnknownPush(ctx erpc.UnknownPushCtx)*erpc.Status {...returnnil}
- register it to root router:
// register the unknown push route: /*peer.SetUnknownPush(XxxUnknownPush)
// NewIgnoreCase Returns a ignoreCase plugin.funcNewIgnoreCase()*ignoreCase {return&ignoreCase{}}typeignoreCasestruct{}var (_ erpc.PostReadCallHeaderPlugin=new(ignoreCase)_ erpc.PostReadPushHeaderPlugin=new(ignoreCase))func (i*ignoreCase)Name()string {return"ignoreCase"}func (i*ignoreCase)PostReadCallHeader(ctx erpc.ReadCtx)*erpc.Status {// Dynamic transformation path is lowercasectx.UriObject().Path=strings.ToLower(ctx.UriObject().Path)returnnil}func (i*ignoreCase)PostReadPushHeader(ctx erpc.ReadCtx)*erpc.Status {// Dynamic transformation path is lowercasectx.UriObject().Path=strings.ToLower(ctx.UriObject().Path)returnnil}
// add router groupgroup:=peer.SubRoute("test")// register to test groupgroup.RouteCall(new(Aaa),NewIgnoreCase())peer.RouteCallFunc(XxZz,NewIgnoreCase())group.RoutePush(new(Bbb))peer.RoutePushFunc(YyZz)peer.SetUnknownCall(XxxUnknownCall)peer.SetUnknownPush(XxxUnknownPush)
typePeerConfigstruct {Networkstring`yaml:"network" ini:"network" comment:"Network; tcp, tcp4, tcp6, unix, unixpacket, kcp or quic"`LocalIPstring`yaml:"local_ip" ini:"local_ip" comment:"Local IP"`ListenPortuint16`yaml:"listen_port" ini:"listen_port" comment:"Listen port; for server role"`DialTimeout time.Duration`yaml:"dial_timeout" ini:"dial_timeout" comment:"Default maximum duration for dialing; for client role; ns,µs,ms,s,m,h"`RedialTimesint32`yaml:"redial_times" ini:"redial_times" comment:"The maximum times of attempts to redial, after the connection has been unexpectedly broken; Unlimited when <0; for client role"`RedialInterval time.Duration`yaml:"redial_interval" ini:"redial_interval" comment:"Interval of redialing each time, default 100ms; for client role; ns,µs,ms,s,m,h"`DefaultBodyCodecstring`yaml:"default_body_codec" ini:"default_body_codec" comment:"Default body codec type id"`DefaultSessionAge time.Duration`yaml:"default_session_age" ini:"default_session_age" comment:"Default session max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`DefaultContextAge time.Duration`yaml:"default_context_age" ini:"default_context_age" comment:"Default CALL or PUSH context max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`SlowCometDuration time.Duration`yaml:"slow_comet_duration" ini:"slow_comet_duration" comment:"Slow operation alarm threshold; ns,µs,ms,s ..."`PrintDetailbool`yaml:"print_detail" ini:"print_detail" comment:"Is print body and metadata or not"`CountTimebool`yaml:"count_time" ini:"count_time" comment:"Is count cost time or not"`}
SetMessageSizeLimit sets max message size.If maxSize<=0, set it to max uint32.
funcSetMessageSizeLimit(maxMessageSizeuint32)
SetSocketKeepAlive sets whether the operating system should sendkeepalive messages on the connection.
funcSetSocketKeepAlive(keepalivebool)
SetSocketKeepAlivePeriod sets period between keep alives.
funcSetSocketKeepAlivePeriod(d time.Duration)
SetSocketNoDelay controls whether the operating system should delaymessage transmission in hopes of sending fewer messages (Nagle'salgorithm). The default is true (no delay), meaning that data issent as soon as possible after a Write.
funcSetSocketNoDelay(_noDelaybool)
SetSocketReadBuffer sets the size of the operating system'sreceive buffer associated with the connection.
funcSetSocketReadBuffer(bytesint)
SetSocketWriteBuffer sets the size of the operating system'stransmit buffer associated with the connection.
funcSetSocketWriteBuffer(bytesint)
package | import | description |
---|---|---|
json | "github.com/andeya/erpc/v7/codec" | JSON codec(erpc own) |
protobuf | "github.com/andeya/erpc/v7/codec" | Protobuf codec(erpc own) |
thrift | "github.com/andeya/erpc/v7/codec" | Form(url encode) codec(erpc own) |
xml | "github.com/andeya/erpc/v7/codec" | Form(url encode) codec(erpc own) |
plain | "github.com/andeya/erpc/v7/codec" | Plain text codec(erpc own) |
form | "github.com/andeya/erpc/v7/codec" | Form(url encode) codec(erpc own) |
package | import | description |
---|---|---|
auth | "github.com/andeya/erpc/v7/plugin/auth" | An auth plugin for verifying peer at the first time |
binder | "github.com/andeya/erpc/v7/plugin/binder" | Parameter Binding Verification for Struct Handler |
heartbeat | "github.com/andeya/erpc/v7/plugin/heartbeat" | A generic timing heartbeat plugin |
proxy | "github.com/andeya/erpc/v7/plugin/proxy" | A proxy plugin for handling unknown calling or pushing |
secure | "github.com/andeya/erpc/v7/plugin/secure" | Encrypting/decrypting the message body |
overloader | "github.com/andeya/erpc/v7/plugin/overloader" | A plugin to protect erpc from overload |
package | import | description |
---|---|---|
rawproto | "github.com/andeya/erpc/v7/proto/rawproto | A fast socket communication protocol(erpc default protocol) |
jsonproto | "github.com/andeya/erpc/v7/proto/jsonproto" | A JSON socket communication protocol |
pbproto | "github.com/andeya/erpc/v7/proto/pbproto" | A Protobuf socket communication protocol |
thriftproto | "github.com/andeya/erpc/v7/proto/thriftproto" | A Thrift communication protocol |
httproto | "github.com/andeya/erpc/v7/proto/httproto" | A HTTP style socket communication protocol |
package | import | description |
---|---|---|
gzip | "github.com/andeya/erpc/v7/xfer/gzip" | Gzip(erpc own) |
md5 | "github.com/andeya/erpc/v7/xfer/md5" | Provides a integrity check transfer filter |
package | import | description |
---|---|---|
multiclient | "github.com/andeya/erpc/v7/mixer/multiclient" | Higher throughput client connection pool when transferring large messages (such as downloading files) |
websocket | "github.com/andeya/erpc/v7/mixer/websocket" | Makes the eRPC framework compatible with websocket protocol as specified in RFC 6455 |
evio | "github.com/andeya/erpc/v7/mixer/evio" | A fast event-loop networking framework that uses the erpc API layer |
html | html "github.com/xiaoenai/tp-micro/helper/mod-html" | HTML render for http client |
project | description |
---|---|
TP-Micro | TP-Micro is a simple, powerful micro service framework based on eRPC |
Pholcus | Pholcus is a distributed, high concurrency and powerful web crawler software |
eRPC is under Apache v2 License. See theLICENSE file for the full license text
About
An efficient, extensible and easy-to-use RPC framework.