littlerpc

package module
v0.3.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2022 License: MIT Imports: 1 Imported by: 0

README

LittleRpc Go Report Card Ci codecov Go Version GitHub

高性能、轻量实现、少依赖、跨语言的玩具级RPC实现

Features

  • 可替换的底层传输协议
    • tcp
    • webSocket
    • other
  • 可替换的序列化/反序列化组件
    • json
    • other
  • 可替换的压缩算法
    • gzip
  • 调用描述接口
    • Sync
    • Async
  • 负载均衡
    • 地址列表解析器
    • 轮询
    • 一致性Hash(问题很大,需要优化)
  • 客户端的实现
    • go
    • java
    • javascript
  • 完善的服务治理拓展API
    • 熔断
    • 限流
    • 网关
    • 注册中心
  • 完善可用的代码生成器
    • 生成async api
    • 生成sync api
  • 完善的示例

Benchmark

基准测试的指标来自rpcx-benchmark,以下结果仅供参考,不同平台的结果可能会不一致,想要清晰的测量结果之前最好自己动手试一试

设置的Client&Server的参数

Call Goroutine Sharring Client Request Number Server Delay
5000 500 1000000 100ns

基准测试使用的平台的详细信息

CPU Runtime System Go Runtime
R7 4700U 8c/16t Vmware15-pro Centos7-3.10kernal Go 1.17

参考结果

Name Min Max P99 Qps
LittleRpc 51285 ns 427180294 ns 205480247 ns 137287
Std-Rpc 55503 ns 352554016 ns 208655742 ns 140686
Rpcx null null null null
Kitex null null null null
Rpcx null null null null
Arpc null null null null
Grpc-go 173594 ns 463660659 ns 317374210 ns 73959

Quick-Start

假设有以下服务需要被使用

type Hello int

func (receiver Hello) Hello(s string) int {
	fmt.Println(s)
	return 1 << 20
}

以下代码启动一个服务器并声明可以被客户端调用的过程,需要注意的是go的过程命名规则是大小写敏感的hello之类在go中被识别为不可导出的过程,这些过程并不会被littlerpc注册。

server := server.NewServer(server.WithAddressServer(":1234"))
err := server.Elem(new(Hello))
if err != nil {
    panic(err)
}
err = server.Start()
if err != nil {
    panic(err)
}
clientInfo := new(Hello)
client := client.NewClient(client.WithAddressClient(":1234"))
_ = client.BindFunc(clientInfo)
rep, _ := client.Call("Hello", "hello world!")
fmt.Println(rep[0])

OutPut

hello world!
1048576

Start

过程的定义

littlerpc中一个合法的过程是如下那样,必须有一个接收器,参数可以是指针类型或者非指针类型,返回结果集允许指针/非指针类型,返回值列表中最后的值类型必须是error

Type的约束, 如上所说, 参数的类型可以是指针/非指针类型, 但是指针只不允许多重指针的出现, 另外参数不能为接口类型, 不管它是空接口还是非空接口, 除了LittleRpc能够理解的context.Context&stream.Stream&error

type Type interface {
    Pointer(NoInterface) | NoPointer(NoInterface)
}
func(receiver) FuncName(...Type) (...Type,error)

littlerpc并不规定合法的过程必须要传递参数,以下的声明也是合法的

func(receiver) FuncName() (...Type,error)

littlerpc也不规定,一定要返回一个值,但是error必须在返回值列表中被声明,以下的声明也是合法的

func(receiver) FuncName() error

关于context.Context&stream.Stream, 输入参数可以有context.Context也可以没有stream.Stream同理, 如果有的话context.Context必须被放置在第一个参数的位置, 当它们同时存在时, stream.Stream必须被放置在第二个位置, 以下列出了参数的几种排列情况, ...表示参数列表的长度为0...N

  •   func(receiver Type) FuncName(context.Context,...Type) (...result,error)
    
  •   func(receiver Type) FuncName(context.Context,stream.Stream,...Type) (...Type,error)
    
  •   func(receiver Type) FuncName(stream.Stream,...Type) (...Type,error)
    
  •   func(receiver Type) FuncName(...Type) (...Type,error)
    
代码生成器

在编写每个客户端的代理对象时有很多繁琐的动作需要人工去完成,所以为了减轻这些不必要的工作,我提供了一个简易实现的代码生成器,自动生成代理对象和对应的过程。

代理对象生成器只会识别接收器类型为指针、拥有可导出名字(首字母大写)的过程,其它类型的过程均不会被生成器识别

Install(安装)
go install github.com/nyan233/littlerpc/pxtor
使用

比如有以下对象需要生成

example/littlerpc/proxy/main.go

type FileServer struct {
	fileMap map[string][]byte
}

func NewFileServer() *FileServer {
	return &FileServer{fileMap: make(map[string][]byte)}
}

func (fs *FileServer) SendFile(path string, data []byte) {
	fs.fileMap[path] = data
}

func (fs *FileServer) GetFile(path string) ([]byte, bool) {
	bytes, ok := fs.fileMap[path]
	return bytes, ok
}

func (fs *FileServer) OpenSysFile(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	return ioutil.ReadAll(file)
}
 pxtor -o test_proxy.go -r main.FileServer

生成完之后需要您手动调节一下import,因为生成器无法判断正确的import上下文

example/littlerpc/proxy/Test_proxy.go

/*
	@Generator   : littlerpc-generator
	@CreateTime  : 2022-06-21 02:33:45.094649 +0800 CST m=+0.000846871
	@Author      : littlerpc-generator
*/
package main

import (
	"github.com/nyan233/littlerpc/impl/client"
)

type FileServerInterface interface {
	SendFile(path string, data []byte) error
	GetFile(path string) ([]byte, bool, error)
	OpenSysFile(path string) ([]byte, error)
}

type FileServerProxy struct {
	*client.Client
}

func NewFileServerProxy(client *client.Client) FileServerInterface {
	proxy := &FileServerProxy{}
	err := client.BindFunc(proxy)
	if err != nil {
		panic(err)
	}
	proxy.Client = client
	return proxy
}

func (proxy FileServerProxy) SendFile(path string, data []byte) error {
	inter, err := proxy.Call("FileServer.SendFile", path, data)
	if err != nil {
		return err
	}
	r0, _ := inter[0].(error)
	return r0
}

func (proxy FileServerProxy) GetFile(path string) ([]byte, bool, error) {
	inter, err := proxy.Call("FileServer.GetFile", path)
	if err != nil {
		return nil, false, err
	}
	r0 := inter[0].([]byte)
	r1 := inter[1].(bool)
	r2, _ := inter[2].(error)
	return r0, r1, r2
}

func (proxy FileServerProxy) OpenSysFile(path string) ([]byte, error) {
	inter, err := proxy.Call("FileServer.OpenSysFile", path)
	if err != nil {
		return nil, err
	}
	r0 := inter[0].([]byte)
	r1, _ := inter[1].(error)
	return r0, r1
}

Example

API

Common
自定义序列化/反序列化框架(Codec)

littlerpc默认使用json传递载荷数据,当然你也可以将其替换

自定义压缩算法(Encoder)

littlerpc默认不进行压缩,框架的内部队默认不压缩的Encoder有特殊优化,不会产生额外的内存拷贝,当然你也可以将其替换

自定义使用的底层传输协议

littlerpc默认使用tcp来传输数据,当然这也是可以替换的

关闭LittleRpc使用到的所有组件的日志
Server
NewServer(op ...Options)

Sever的Codec和Encoder都是自适应的,根据Client需要自动切换,所以不需要单独设置

WithAddressServer(adds ...string)

addrs是变长参数,此函数可以指定监听的地址

WithTlsServer(tlsC *tls.Config)

Tls的配置相关

WithTransProtocol(scheme string)

根据规则来选择不同的底层传输协议的实现

WithOpenLogger(ok bool)

是否开启Server特定

Client

Client需要指定Codec和Encoder,否则则使用默认的Codec和Encoder,也就是json&text

NewClient(op ...Options)
WithCallOnErr(fn func(err error))

设置处理Server错误返回的回调函数

WithProtocol(scheme string)

设置客户端的底层传输协议

WithTlsClient(tlsC *tls.Config)

Tls配置相关

Thanks

感谢,以下这些项目给本项目的一些设计带来了想法和灵感

Lisence

The LittleRpc Use Mit licensed. More is See Lisence

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
cmd
internal
pool
Package pool littlerpc自带的goroutine池
Package pool littlerpc自带的goroutine池
pkg
plugins
ddio Module
limiter Module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL