eRPC — это эффективный, расширяемый и удобный в использовании фреймворк RPC.
Подходит для использования в RPC, микросервисах, peer-to-peer системах, мессенджерах, играх и других областях.
версия Go ≥ 1.11
установите
GO111MODULE=on go get -u -v -insecure github.com/andeya/erpc/v7
import "github.com/andeya/erpc/v7"
peer
для предоставления одинакового пакета API для сервера и клиентаpeer
сессия/сокет
маршрутизатор
обработчик/контекст
сообщение
протокол
кодировка
фильтр передачи
плагин
Заголовок
и Содержание
Заголовок
содержит метаданные в том же формате, что и заголовок HTTPСодержание
поддерживает пользовательскую кодировку типа контента, уже реализованы:
rawproto
- По умолчанию высокопроизводительный двоичный протоколjsonproto
- Протокол сообщений JSONpbproto
- Протокол сообщений Protobufthriftproto
- Протокол сообщений Thrifthttproto
- Протокол сообщений HTTPtcp
tcp4
tcp6
unix
unixpacket
kcp
quic
websocket
evio
auth
binder
heartbeat
ignorecase
(метод сервиса)overloader
proxy
(для неизвестного метода сервиса)secure
Самостоятельное тестирование
Параллелизм клиента | Среднее (мс) | Медиана (мс) | Макс (мс) | Мин (мс) | Пропускная способность (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 |
Параллелизм клиента | Среднее (мс) | Медиана (мс) | Макс (мс) | Мин (мс) | Пропускная способность (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 |
Сравнение тестов
Окружение | Пропускная способность | Средняя задержка | Задержка P99 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
package main
import (
"fmt"
"time"
"github.com/andeya/erpc/v7"
)
func main() {
defer erpc.FlushLogger()
// плавное завершение работы
go erpc.GraceSignal()
// серверный узел
srv := erpc.NewPeer(erpc.PeerConfig{
CountTime: true,
ListenPort: 9090,
PrintDetail: true,
})
// srv.SetTLSConfig(erpc.GenerateTLSConfigForServer())
// маршрутизация вызова
srv.RouteCall(new(Math))
// широковещательная рассылка каждые 5 секунд
go func() {
for {
time.Sleep(time.Second * 5)
srv.RangeSession(func(sess erpc.Session) bool {
sess.Push(
"/push/status",
fmt.Sprintf("это широковещательная рассылка, время сервера: %v", time.Now()),
)
return true
})
}
}()
// прослушивание и обслуживание запросов
srv.ListenAndServe()
}
// Обработчик Math
type Math struct {
erpc.CallCtx
}
// Add обрабатывает запрос на сложение
func (m *Math) Add(arg *[]int) (int, *erpc.Status) {
// тест метаданных
erpc.Infof("автор: %s", m.PeekMeta("author"))
// суммирование
var r int
for _, a := range *arg {
r += a
}
// ответ
return r, nil
}
package main
import (
"time"
"github.com/andeya/erpc/v7"
)
func main() {
defer erpc.SetLoggerLevel("ERROR")()
cli := erpc.NewPeer(erpc.PeerConfig{})
defer cli.Close()
// cli.SetTLSConfig(&tls.Config{InsecureSkipVerify: true})
cli.RoutePush(new(Push))
sess, stat := cli.Dial(":9090")
if !stat.OK() {
erpc.Fatalf("%v", stat)
}
``` var result int
stat = 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("результат: %d", result)
erpc.Printf("ожидание 10 секунд до получения широковещательной рассылки...")
time.Sleep(time.Second * 10)
}
// Обработчик Push
type Push struct {
erpc.PushCtx
}
// Status обрабатывает сообщение '/push/status'
func (p *Push) Status(arg *string) *erpc.Status {
erpc.Printf("%s", *arg)
return nil
}
ЗАМЕЧАНИЕ:
SetReadLimit
.// Запуск сервера
var peer1 = erpc.NewPeer(erpc.PeerConfig{
ListenPort: 9090, // для роли сервера
})
peer1.Listen()
var peer2 = erpc.NewPeer(erpc.PeerConfig{})
var sess, err = peer2.Dial("127.0.0.1:8080")
type Aaa struct {
erpc.CallCtx
}
func (x *Aaa) XxZz(arg *<T>) (<T>, *erpc.Status) {
...
return r, nil
}
// регистрация вызова маршрута
// HTTP отображение: /aaa/xx_zz
// RPC отображение: Aaa.XxZz
peer.RouteCall(new(Aaa))
// или регистрация вызова маршрута
// HTTP отображение: /xx_zz
// RPC отображение: XxZz
peer.RouteCallFunc((*Aaa).XxZz)
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)
```- Отображение (RPCServiceMethodMapper):
- `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`
```go
erpc.SetServiceMethodMapper(erpc.RPCServiceMethodMapper)
```
### Шаблон API Call-Function
```go
func XxZz(ctx erpc.CallCtx, arg *<T>) (<T>, *erpc.Status) {
...
return r, nil
}
// регистрация вызова маршрута
// HTTP отображение: /xx_zz
// RPC отображение: XxZz
peer.RouteCallFunc(XxZz)
type Bbb struct {
erpc.PushCtx
}
func (b *Bbb) YyZz(arg *<T>) *erpc.Status {
...
return nil
}
// регистрация обработчика отправки
// HTTP отображение: /bbb/yy_zz
// RPC отображение: Bbb.YyZz
peer.RoutePush(new(Bbb))
// или регистрация обработчика отправки
// HTTP отображение: /yy_zz
// RPC отображение: YyZz
peer.RoutePushFunc((*Bbb).YyZz)
// YyZz регистрирует обработчик
func YyZz(ctx erpc.PushCtx, arg *<T>) *erpc.Status {
...
return nil
}
// регистрация обработчика отправки
// HTTP отображение: /yy_zz
// RPC отображение: YyZz
peer.RoutePushFunc(YyZz)
func XxxUnknownCall(ctx erpc.UnknownCallCtx) (interface{}, *erpc.Status) {
...
return r, nil
}
// зарегистрировать маршрут unkown call: /*
peer.SetUnknownCall(XxxUnknownCall)
func XxxUnknownPush(ctx erpc.UnknownPushCtx) *erpc.Status {
...
return nil
}
### Пример плагина
```go
// NewIgnoreCase Возвращает плагин IgnoreCase.
func NewIgnoreCase() *ignoreCase {
return &ignoreCase{}
}
type ignoreCase struct{}
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 {
// Динамическое преобразование пути в нижний регистр
ctx.UriObject().Path = strings.ToLower(ctx.UriObject().Path)
return nil
}
func (i *ignoreCase) PostReadPushHeader(ctx erpc.ReadCtx) *erpc.Status {
// Динамическое преобразование пути в нижний регистр
ctx.UriObject().Path = strings.ToLower(ctx.UriObject().Path)
return nil
}
// добавить группу маршрутов
group := peer.SubRoute("test")
// зарегистрировать в тестовой группе
group.RouteCall(new(Aaa), NewIgnoreCase())
peer.RouteCallFunc(XxZz, NewIgnoreCase())
group.RoutePush(new(Bbb))
peer.RoutePushFunc(YyZz)
peer.SetUnknownCall(XxxUnknownCall)
peer.SetUnknownPush(XxxUnknownPush)
```### Конфигурация```go
type PeerConfig struct {
Network string `yaml:"network" ini:"network" comment:"Сеть; tcp, tcp4, tcp6, unix, unixpacket, kcp или quic"`
LocalIP string `yaml:"local_ip" ini:"local_ip" comment:"Локальный IP"`
ListenPort uint16 `yaml:"listen_port" ini:"listen_port" comment:"Порт прослушивания; для роли сервера"`
DialTimeout time.Duration `yaml:"dial_timeout" ini:"dial_timeout" comment:"По умолчанию максимальное время для установки соединения; для роли клиента; ns, µs, ms, s, m, h"`
RedialTimes int32 `yaml:"redial_times" ini:"redial_times" comment:"Максимальное количество попыток повторной установки соединения после его непредвиденного разрыва; Без ограничений при значении меньше 0; для роли клиента"`
RedialInterval time.Duration `yaml:"redial_interval" ini:"redial_interval" comment:"Интервал между попытками повторной установки соединения, значение по умолчанию — 100 мс; для роли клиента; ns, µs, ms, s, m, h"`
DefaultBodyCodec string `yaml:"default_body_codec" ini:"default_body_codec" comment:"По умолчанию тип идентификатора кодировки тела"`
DefaultSessionAge time.Duration `yaml:"default_session_age" ini:"default_session_age" comment:"По умолчанию максимальный срок действия сессии, если значение меньше или равно 0, то нет временных ограничений; ns, µs, ms, s, m, h"`
DefaultContextAge time.Duration `yaml:"default_context_age" ini:"default_context_age" comment:"По умолчанию максимальный срок действия контекста вызова или отправки данных, если значение меньше или равно 0, то нет временных ограничений; ns, µs, ms, s, m, h"`
SlowCometDuration time.Duration `yaml:"slow_comet_duration" ini:"slow_comet_duration" comment:"Длительность медленного comet"`
}```Duration `yaml:"slow_comet_duration" ini:"slow_comet_duration" comment:"Пороговое значение для оповещения о медленной операции; нс, мкс, мс, с. . ."`
PrintDetail bool `yaml:"print_detail" ini:"print_detail" comment:"Отображение содержимого тела и метаданных?"`
CountTime bool `yaml:"count_time" ini:"count_time" comment:"Подсчет затраченного времени?"`
}
```### Оптимизация- SetMessageSizeLimit устанавливает максимальный размер сообщения.
Если maxSize ≤ 0, он устанавливается в максимальное значение uint32.
```go
func SetMessageSizeLimit(maxMessageSize uint32)
```
- SetSocketKeepAlive устанавливает, следует ли операционной системе отправлять
сообщения "keep alive" по соединению.
```go
func SetSocketKeepAlive(keepalive bool)
```
- SetSocketKeepAlivePeriod устанавливает период между сообщениями "keep alive".
```go
func SetSocketKeepAlivePeriod(d time.Duration)
```
- SetSocketNoDelay управляет тем, следует ли операционной системе откладывать
передачу данных в надежде отправить меньше сообщений (алгоритм Нейгла). По умолчанию это `true` (нет задержки),
что означает, что данные отправляются как можно быстрее после вызова метода `Write`.
```go
func SetSocketNoDelay(_noDelay bool)
```
- SetSocketReadBuffer устанавливает размер буфера приема операционной системы,
связанного с соединением.
```go
func SetSocketReadBuffer(bytes int)
```
- SetSocketWriteBuffer устанавливает размер буфера передачи операционной системы,
связанного с соединением.
```go
func SetSocketWriteBuffer(bytes int)
```
## Расширения
### Кодеки| пакет | импорт | описание |
| ---------------------------------------- | ---------------------------------------- | --------------------------- |
| [json](https://github.com/andeya/erpc/blob/master/codec/json_codec.go) | `"github.com/andeya/erpc/v7/codec"` | JSON кодек (собственный erpc) |
| [protobuf](https://github.com/andeya/erpc/blob/master/codec/protobuf_codec.go) | `"github.com/andeya/erpc/v7/codec"` | Protobuf кодек (собственный erpc) |
| [thrift](https://github.com/andeya/erpc/blob/master/codec/thrift_codec.go) | `"github.com/andeya/erpc/v7/codec"` | Thrift кодек (собственный erpc) |
| [xml](https://github.com/andeya/erpc/blob/master/codec/xml_codec.go) | `"github.com/andeya/erpc/v7/codec"` | XML кодек (собственный erpc) |
| [plain](https://github.com/andeya/erpc/blob/master/codec/plain_codec.go) | `"github.com/andeya/erpc/v7/codec"` | Простой текстовый кодек (собственный erpc) |
| [form](https://github.com/andeya/erpc/blob/master/codec/form_codec.go) | `"github.com/andeya/erpc/v7/codec"` | Кодек формы (URL-кодировка) (собственный erpc) |
### Плагины| пакет | импорт | описание |
| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- |
| [auth](https://github.com/andeya/erpc/tree/master/plugin/auth) | `"github.com/andeya/erpc/v7/plugin/auth"` | Плагин аутентификации для проверки партнёра впервые |
| [binder](https://github.com/andeya/erpc/tree/master/plugin/binder) | `"github.com/andeya/erpc/v7/plugin/binder"` | Проверка привязки параметров для обработчика структур |
| [heartbeat](https://github.com/andeya/erpc/tree/master/plugin/heartbeat) | `"github.com/andeya/erpc/v7/plugin/heartbeat"` | Универсальный плагин управления сердцебиением с таймером |
| [proxy](https://github.com/andeya/erpc/tree/master/plugin/proxy) | `"github.com/andeya/erpc/v7/plugin/proxy"` | Плагин прокси для обработки неизвестных вызовов или отправок |
| [secure](https://github.com/andeya/erpc/tree/master/plugin/secure) | `"github.com/andeya/erpc/v7/plugin/secure"` | Шифрование/расшифровка содержимого сообщений |
| [overloader](https://github.com/andeya/erpc/tree/master/plugin/overloader) | `"github.com/andeya/erpc/v7/plugin/overloader"` | Плагин защиты erpc от перегрузки |
### Протоколы| пакет | импорт | описание |
| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- |
| [rawproto](https://github.com/andeya/erpc/tree/master/proto/rawproto) | `"github.com/andeya/erpc/v7/proto/rawproto"` | Быстрый протокол сокетной связи (по умолчанию для erpc) |
| [jsonproto](https://github.com/andeya/erpc/tree/master/proto/jsonproto) | `"github.com/andeya/erpc/v7/proto/jsonproto"` | Протокол сокетной связи на основе JSON |
| [pbproto](https://github.com/andeya/erpc/tree/master/proto/pbproto) | `"github.com/andeya/erpc/v7/proto/pbproto"` | Протокол сокетной связи на основе Protobuf |
| [thriftproto](https://github.com/andeya/erpc/tree/master/proto/thriftproto) | `"github.com/andeya/erpc/v7/proto/thriftproto"` | Протокол связи на основе Thrift |
| [httproto](https://github.com/andeya/erpc/tree/master/proto/httproto) | `"github.com/andeya/erpc/v7/proto/httproto"` | Протокол сокетной связи в стиле HTTP |
### Трансфер-фильтры| пакет | импорт | описание |
| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- |
| [gzip](https://github.com/andeya/erpc/tree/master/xfer/gzip) | `"github.com/andeya/erpc/v7/xfer/gzip"` | Gzip (собственный erpc) |
| [md5](https://github.com/andeya/erpc/tree/master/xfer/md5) | `"github.com/andeya/erpc/v7/xfer/md5"` | Предоставляет фильтр проверки целостности передачи данных с использованием алгоритма MD5 |
### Миксер
| пакет | импорт | описание |
| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- |
| [multiclient](https://github.com/andeya/erpc/tree/master/mixer/multiclient) | `"github.com/andeya/erpc/v7/mixer/multiclient"` | Бассейн соединений клиента с высокой пропускной способностью при передаче больших сообщений (например, при скачивании файлов) |
| [websocket](https://github.com/andeya/erpc/tree/master/mixer/websocket) | `"github.com/andeya/erpc/v7/mixer/websocket"` | Делает фреймворк eRPC совместимым с протоколом WebSocket согласно спецификации RFC 6455 |
| [evio](https://github.com/andeya/erpc/tree/master/mixer/evio) | `"github.com/andeya/erpc/v7/mixer/evio"` | Быстрый сетевой фреймворк событийного цикла, использующий слой API erpc |
| [html](https://github.com/xiaoenai/tp-micro/tree/master/helper/mod-html) | `html "github.com/xiaoenai/tp-micro/helper/mod-html"` | Генерация HTML для HTTP-клиента |
## Проекты на основе eRPC| Проект | Описание |
| ---------------------------------------- | ---------------------------------------- |
| [TP-Micro](https://github.com/xiaoenai/tp-micro) | TP-Micro — это простой и мощный микросервисный фреймворк, основанный на eRPC. |
| [Pholcus](https://github.com/andeya/pholcus) | Pholcus — это распределенный веб-скрейпер с высокой пропускной способностью и мощными возможностями. |## Корпоративные пользователи
<a href="http://www.xiaoenai.com"><img src="https://raw.githubusercontent.com/andeya/imgs-repo/master/xiaoenai.png" height="50" alt="Shenzhen Mengzhidebo Information Technology Co., Ltd."/></a>
<a href="https://tech.pingan.com/index.html"><img src="http://pa-tech.hirede.com/templates/pa-tech/Images/logo.png" height="50" alt="Ping An Technology"/></a>
<br/>
<a href="http://www.fun.tv"><img src="http://static.funshion.com/open/static/img/logo.gif" height="70" alt="Beijing FengXing Online Technology Co., Ltd."/></a>
<a href="http://www.kejishidai.cn"><img src="http://simg.ktvms.com/picture/logo.png" height="70" alt="Beijing Keji Shidai Network Company"/></a>
<a href="https://www.kuaishou.com/"><img src="https://inews.gtimg.com/newsapp_bt/0/4400789257/1000" height="70" alt="KuaiShou Short Video Platform"/></a>
## Лицензия
eRPC распространяется под лицензией Apache v2. Полный текст лицензии доступен в файле [LICENSE](https://github.com/andeya/erpc/raw/master/LICENSE).
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )