TarsGo — это высокопроизводительный фреймворк RPC на языке программирования Go, использующий протокол Tars.
Go стал популярным с ростом контейнерных технологий, таких как Docker, k8s и etcd.
Механизм многопоточности Go (goroutine) делает его очень подходящим для разработки крупномасштабных серверов с высокой конкуренцией. Язык Go имеет производительность, близкую к C/C++, и продуктивность, близкую к Python.
В Tencent часть существующей команды разработчиков на C++ постепенно переходит на Go. Широко используемый фреймворк RPC Tars поддерживает C++, Java, NodeJS, PHP и теперь Go. Соединение с языком Go стало общей тенденцией. Поэтому по запросу пользователей мы запустили TarsGo, и он уже применяется в приложениях карты Tencent, YingYongbao, Интернете плюс и других проектах.
Подробнее о всей архитектуре и дизайне Tars можно узнать на введении.## Функции и возможности
Инструмент Tars2go: автоматическое генерирование и преобразование файлов Tars в Go, включая код RPC сервера/клиента;
Сериализация и десериализация протокола Tars на Go.
Автоматическое обнаружение сервисов.
Серверы и клиенты TCP/UDP/HTTP.
Поддержка локального и удалённого логирования.
Поддержка статистического отчёта, свойственных статистик и отчётов об аномалиях.
Поддержка разделения протоколов.
Поддержка протоколов buffers. Подробнее в pb2tarsgo
Поддержка фильтров.
Поддержка zipkin opentracing.## Установка
Для установки OSS и других базовых серверов, см. документ Установка. Для быстрой установки OSS и других базовых серверов, см. Развертывание
Требуется Go 1.9.x или выше (см. https://golang.org/doc/install для помощи в установке Go)
go get -u github.com/TarsCloud/TarsGo/tars
Создайте файл tars, например hello.tars, под $GOPATH/src (например, $GOPATH/src/TestApp/TestServer/hello.tars).
Для более подробной информации о протоколе tars, см. tars_protocol Протокол tars — это двоичный, IDL-подобный протокол, похожий на protocolbuffers.
модуль TestApp
{
интерфейс Hello
{
int test();
int testHello(string sReq, out string sRsp);
};
};
Скомпилировать и установить инструменты tars2go.
go install $GOPATH/src/github.com/TarsCloud/TarsGo/tars/tools/tars2go
tars2go --outdir=./vendor hello.tars
пакет main
импортировать (
"github.com/TarsCloud/TarsGo/tars"
```go
type serverConfig struct {
Node string
App string
Server string
LogPath string
LogSize string
LogLevel string
Version string
LocalIP string
BasePath string
DataPath string
config string
notify string
log string
netThread int
Adapters map[string]adapterConfig
Container string
Isdocker bool
Enableset bool
Setdivision string
}
иллюстрация:
HelloImp
— это структура, где вы реализуете интерфейсы Hello
и Test
. Обратите внимание, что Test
и Hello
должны начинаться с заглавной буквы для экспорта, что является единственным местом, отличающимся от определения в файле tars.TestApp.Hello
сгенерирован инструментами tar2go
и может быть найден в ./vendor/TestApp/Hello_IF.go
, с пакетом, названным TestApp
, который соответствует модулю TestApp
в файле tars.tars.GetServerConfig()
используется для получения конфигурации сервера.cfg.App + "." + cfg.Server + ".HelloObj"
— это имя объекта, связанного с службой, которое клиент будет использовать для доступа к серверу.tars.GetServerConfig()
возвращает конфигурацию сервера, которая определена следующим образом:
type serverConfig struct {
Node string
App string
Server string
LogPath string
LogSize string
LogLevel string
Version string
LocalIP string
BasePath string
DataPath string
config string
notify string
log string
netThread int
Adapters map[string]adapterConfig
Container string
Isdocker bool
Enableset bool
Setdivision string
}
type adapterConfig struct {
Host string
Port int
Protocol string
}
```xml
<tars>
<application>
enableset=Y
setdivision=gray.sz.*
<server>
node=tars.tarsnode.ServerObj@tcp -h OnClickListener 10.120.129.226 -p 19386 -t 60000
app=TestApp
server=HelloServer
localip=10.120.129.226
local=tcp -h 127.0.0.1 -p 20001 -t 3000
basepath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/bin/
datapath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/data/
logpath=/usr/local/app/tars/app_log/
logsize=10M
config=tars.tarsconfig.ConfigObj
notify=tars.tarsnotify.NotifyObj
log=tars.tarslog.LogObj
#timeout for deactivating, ms.
deactivating-timeout=2000
logLevel=DEBUG
</server>
</application>
</tars>
```#### 1.5 Адаптер
Адаптер представляет привязку IP-адреса и порта для определённого объекта.
Пример реализации сервера `app.AddServant(imp, cfg.App + "." + cfg.Server + ".HelloObj")` обеспечивает привязку конфигурации адаптера и реализации для объекта `HelloObj`.
Пример конфигурации адаптера приведён ниже:
```diff
+ Пример конфигурации адаптера:
<tars>
<application>
<server>
<!-- конфигурация каждого адаптера -->
<TestApp.HelloServer.HelloObjAdapter>
<!-- разрешенные IP для белого списка. -->
allow
<!-- IP и порт для прослушивания -->
endpoint=tcp -h 10.120.129.226 -p 20001 -t 60000
<!-- группа обработчиков -->
handlegroup=TestApp.HelloServer.HelloObjAdapter
<!-- максимальное количество подключений -->
maxconns=200000
<!-- протокол, только tars на данный момент -->
protocol=tars
<!-- максимальная емкость в очереди обработчиков -->
queuecap=10000
<!-- время ожидания в миллисекундах для запроса в очереди -->
queuetimeout=60000
<!-- сервант -->
servant=TestApp.HelloServer.HelloObj
<!-- потоки в обработчике серверной стороны реализации кода. goroutine для golang. -->
threads=5
</TestApp.HelloServer.HelloObjAdapter>
</server>
</application>
</tars>
Команда для запуска сервера:
./HelloServer --config=config.conf
Пример полного конфигурационного файла config.conf
приведен ниже. Конфигурация клиента будет рассмотрена позже.```xml
enableset=n
setdivision=NULL
node=tars.tarsnode.ServerObj@tcp -h 10.120.129.226 -p 19386 -t 60000
app=TestApp
server=HelloServer
localip=10.120.129.226
local=tcp -h 127.0.0.1 -p 20001 -t 3000
basepath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/bin/
datapath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/data/
logpath=/usr/local/app/tars/app_log/
logsize=10M
config=tars.tarsconfig.ConfigObj
notify=tars.tarsnotify.NotifyObj
log=tars.tarslog.LogObj
deactivating-timeout=2000
logLevel=DEBUG
<TestApp.HelloServer.HelloObjAdapter>
allow
endpoint=tcp -h 10.120.129.226 -p 20001 -t 60000
handlegroup=TestApp.HelloServer.HelloObjAdapter
maxconns=200000
protocol=tars
queuecap=10000
queuetimeout=60000
servant=TestApp.HelloServer.HelloObj
threads=5
</TestApp.HelloServer.HelloObjAdapter>
locator=tars.tarsregistry.QueryObj@tcp -h 10.120.129.226 -p 17890
syncInvokeTimeout=3000
asyncInvokeTimeout=5000
refreshEndpointInterval=60000
reportInterval=60000
sampleRate=100000
maxSampleCount=50
asyncThread=3
modulename=TestApp.HelloServer
Пользователь может легко написать код клиента без необходимости писать спецификацию протокола для коммуникации.
#### 2.1 Пример Клиента
Пример кода клиента:
```go
package main
import (
"fmt"
"github.com/TarsCloud/TarsGo/tars"
"TestApp"
)
// tars.Communicator должен инициализироваться только один раз и быть глобальным
var comm *tars.Communicator
func main() {
comm = tars.NewCommunicator()
obj := "TestApp.TestServer.HelloObj@tcp -h 127.0.0.1 -p 10015 -t 60000"
app := new(TestApp.Hello)
comm.StringToProxy(obj, app)
var req string = "Hello World"
var out string
ret, err := app.TestHello(req, &out)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret, out)
}
иллюстрация:
var comm *tars.Communicator
comm = tars.NewCommunicator()
comm.SetProperty("property", "tars.tarsproperty.PropertyObj")
comm.SetProperty("locator", "tars.tarsregistry.QueryObj@tcp -h ... -p ...")
```Описание:
> * Формат конфигурационного файла коммуникатора будет описан позже.
> * Коммуникаторы могут быть настроены без конфигурационного файла, и все параметры имеют значения по умолчанию.
> * Коммуникатор также может быть инициализирован напрямую через метод `SetProperty`.
> * Если вы не хотите использовать конфигурационный файл, вам необходимо самостоятельно задать параметр `locator`.
Описание атрибутов коммуникатора:
> * `locator`: Адрес службы реестра должен быть в формате `"ip:port"`. Если вам не нужно, чтобы реестр находил службу, настройка этого параметра не требуется.
> * `async-invoke-timeout`: Максимальное время ожидания (в миллисекундах) для клиентских вызовов. Значение по умолчанию для этой конфигурации равно 3000 миллисекундам.
> * `sync-invoke-timeout`: В настоящее время не используется в tarsgo.
> * `refresh-endpoint-interval`: Интервал (в миллисекундах) для периодического доступа к реестру для получения информации. Значение по умолчанию для этой конфигурации равно одной минуте.
> * `stat`: Адрес службы, вызываемой между модулями. Если этот параметр не настроен, это означает, что отчетные данные будут пропущены.
> * `property`: Адрес, по которому служба отчитывается о своих атрибутах. Если этот параметр не настроен, это означает, что отчетные данные будут пропущены.
> * `report-interval`: В настоящее время не используется в tarsgo.
> * `asyncthread`: В настоящее время не используется в tarsgo.> * modulename: Имя модуля, значение по умолчанию — имя исполняемого файла. Формат конфигурационного файла коммутирующего агента выглядит следующим образом:
```xml
<tars>
<application>
<! -- Конфигурация, требуемая прокси -->
<client>
<! -- Адрес -->
locator = tars. tarsregistry. QueryObj@tcp -h 127. 0. 0. 1 -p 17890
<! -- Максимальное время ожидания (в миллисекундах) для синхронных вызовов -->
sync-invoke-timeout = 3000
<! -- Максимальное время ожидания (в миллисекундах) для асинхронных вызовов -->
async-invoke-timeout = 5000
<! -- Максимальное время ожидания (в миллисекундах) для синхронных вызовов -->
refresh-endpoint-interval = 60000
<! -- Используется для межмодульных вызовов -->
stat = tars. tarsstat. StatObj
<! -- Адрес, используемый для отчета о свойствах -->
property = tars. tarsproperty. PropertyObj
<! -- Интервал отчета времени -->
report-interval = 60000
<! -- Количество потоков, обрабатывающих асинхронные ответы -->
asyncthread = 3
<! -- Имя модуля -->
modulename = Test. HelloServer
</client>
</application>
</tars>
если вы хотите использовать управление таймаутом на стороне клиента, используйте TarsSetTimeout, который измеряется в миллисекундах.
app := new(TestApp. Hello)
comm. StringToProxy(obj, app)
app. TarsSetTimeout(3000)
```#### 2.4 Интерфейс вызова
В этом разделе описывается, как клиент Tars вызывает сервер удаленно.
Сначала кратко описывается режим адресации клиента Tars. Затем будет введен метод вызова клиента, включая, но не ограничиваясь, односторонним вызовом, синхронным вызовом, асинхронным вызовом, хэш-вызовом и т. д.
##### 2.4.1 Введение в режим адресации
Режим адресации службы Tars обычно можно разделить на два способа: имя службы регистрируется в мастере, и имя службы не регистрируется в мастере. Мастер — это сервер имен (маршрутизационный сервер), предназначенный для регистрации информации о узлах службы.
Имя службы, добавленное в сервер имен, реализуется через платформу операционного управления.
Для служб, которые не зарегистрированы в мастере, их можно классифицировать как прямое адресование, то есть перед вызовом службы необходимо указать IP-адрес поставщика услуги. Клиенту необходимо указать конкретный адрес объекта HelloObj при вызове службы: то есть: Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985
Test.HelloServer.HelloObj: Имя объекта
tcp: Протокол TCP
-h: Указывает адрес хоста, здесь это 127.0.0.1
-p: Порт, здесь это 9985Если HelloServer запущен на двух серверах, приложение инициализируется следующим образом:
```go
obj := "Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985:tcp -h 192.168.1.1 -p 9983"
app := new(TestApp.Hello)
comm.StringToProxy(obj, app)
Адрес HelloObj
устанавливается на адреса двух серверов. В этом случае запрос будет распределяться между двумя серверами (метод распределения можно указать, но это не рассматривается здесь). Если один сервер недоступен, запрос будет автоматически перенаправлен на другой сервер, и недоступный сервер будет перезапускаться периодически.Для сервисов, зарегистрированных в мастере, сервис адресуется по имени сервиса. Когда клиент запрашивает сервис, ему не нужно указывать конкретный адрес HelloServer
, но ему нужно указать адрес registry
при создании или инициализации коммуникатора.
Вот пример адреса registry с настройкой параметров коммуникатора:
var *tars.Communicator
comm = tars.NewCommunicator()
comm.SetProperty("locator", "tars.tarsregistry.QueryObj@tcp -h ... -p ...")
Так как клиенту требуется полагаться на адрес registry, registry также должен быть надёжным. Метод обеспечения надёжности registry такой же, как и выше, указывается адрес двух registry.
TODO. Поддерживается в tarsgo.
package main
import (
"fmt"
"github.com/TarsCloud/TarsGo/tars"
"TestApp"
)
var *tars.Communicator
func main() {
comm = tars.NewCommunicator()
obj := "TestApp.TestServer.HelloObj@tcp -h 127.0.0.1 -p 10015 -t 60000"
app := new(TestApp.Hello)
comm.StringToProxy(obj, app)
var req string = "Hello World"
var out string
ret, err := app.TestHello(req, &out)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret, out)
}
tarsgo может легко использовать асинхронный вызов с помощью go-рутин. В отличие от C++, нам не нужно реализовывать обратный вызов.
package main
import (
"fmt"
"github.com/TarsCloud/TarsGo/tars"
"time"
"TestApp"
)
var *tars.Communicator
func main() {
comm = tars.NewCommunicator()
obj := "TestApp.TestServer.HelloObj@tcp -h 127.0.0.1 -p 10015 -t 60000"
app := new(TestApp.Hello)
comm.StringToProxy(obj, app)
go func() {
var req string = "Hello World"
var out string
ret, err := app.TestHello(req, &out)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret, out)
}()
time.Sleep(1)
}
```##### 2.4.5 вызов по множеству
Клиент может вызвать сервер по множеству через конфигурационный файл, упомянутый выше. Включённое множество будет `y`, а разделение множества будет выглядеть как `gray.sz.*`. См. https://github.com/TarsCloud/Tars/blob/master/docs-en/tars_idc_set.md для получения дополнительной информации.
Если вы хотите вызвать по множеству вручную, то tarsgo будет поддерживать эту функцию в ближайшее время.
##### 2.4.6 Хэш-вызов
Так как несколько серверов могут быть развернуты, клиентские запросы распределяются случайным образом между серверами, но в некоторых случаях желательно, чтобы определённые запросы всегда отправлялись на определённый сервер. В этом случае Tars предоставляет простой способ для этого, который называется хэш-вызовом. Tarsgo будет поддерживать эту функцию в ближайшее время.### 3 Определение кода возврата TARS.
```go
// Определение кода возврата, предоставленного TARS-сервисом
const int TARSSERVERSUCCESS = 0; // Успешное выполнение на стороне сервера
const int TARSSERVERDECODEERR = -1; // Исключение декодирования на стороне сервера
const int TARSSERVERENCODEERR = -2; // Исключение кодирования на стороне сервера
const int TARSSERVERNOFUNCERR = -3; // Такой функции нет на стороне сервера
const int TARSSERVERNOSERVANTERR = -4; // Сервер не имеет объекта Servant
const int TARSSERVERRESETGRID = -5; // Несоответствие состояния сервера
const int TARSSERVERQUEUETIMEOUT = -6; // Превышение лимита очереди сервера
const int TARSASYNCCALLTIMEOUT = -7; // Превышение времени ожидания асинхронного вызова
const int TARSINVOKETIMEOUT = -7; // Превышение времени ожидания вызова
const int TARSPROXYCONNECTERR = -8; // Исключение соединения прокси
const int TARSSERVEROVERLOAD = -9; // Перегрузка сервера, превышение длины очереди
const int TARSADAPTERNULL = -10; // Маршрутизация клиента пустая, сервис не существует или все сервисы недоступны
const int TARSINVOKEBYINVALIDESET = -11; // Нарушение правил вызова множества клиентом
const int TARSCLIENTDECODEERR = -12; // Исключение декодирования клиента
const int TARSSERVERUNKNOWNERR = -99; // Сервер находится в неизвестном состоянии
```### 4 Логи
Пример быстрого использования tarsgo вращающегося лога
```go
TLOG := tars.GetLogger("TLOG")
TLOG.Debug("Отладочное логирование")
Это создаст Logger.Logger
, который был определён в tars/util/rogger, и после вызова GetLogger будет создан лог-файл под путём Logpath, определённым в конфигурационном файле config.conf, имя которого будет cfg.App + "." + cfg.Server + "_" + name
, и он будет вращаться после достижения размера 100МБ (по умолчанию), и максимальное количество вращений файлов по умолчанию составляет 10.
```go
TLOG := tars.GetDayLogger("TLOG", 1)
TLOG.Debug("Отладочное логирование")
для вращения по часам, используйте GetHourLogger("TLOG", 1). Если вы хотите логировать на удалённый сервер, который определён в config.conf под названием tars.tarslog.LogObj. Полное определение tars файла можно найти в tars/protocol/res/LogF.tars. Вам нужно настроить сервер логирования перед этим. Пример сервера логирования можно найти в Tencent/Tars/cpp/framework/LogServer. Быстрый пример:
TLOG := GetRemoteLogger("TLOG")
TLOG.Debug("Отладочное логирование")
если вы хотите установить уровень логирования, вы можете сделать это с помощью платформы OSS, предоставляемой проектом Tars, под Tencent/Tars/web. Если вы хотите настроить свой собственный логгер, увидеть больше деталей в tars/util/rogger, tars/logger.go и tars/remotelogger.go
tarsgo в настоящее время имеет административные команды tars.viewversion / tars.setloglevel. Пользователь может отправить административную команду из OSS, чтобы увидеть, какая версия установлена, или установить уровень логирования, упомянутый выше.
если вы хотите определить свои собственные административные команды, увидеть этот пример
func helloAdmin(who string) (string, error) {
return who, nil
}
tars.RegisterAdmin("tars.helloAdmin", helloAdmin)
Затем вы можете отправить пользовательскую административную команду "tars.helloAdmin tarsgo" и tarsgo будет отображаться в браузере.
Пример:
// Функция должна быть в этом формате
type adminFn func(string) (string, error)
// затем вы должны зарегистрировать эту функцию с помощью
func RegisterAdmin(name string, fn adminFn)
Отчёт о статистической информации представляет собой логику отчёта о затраченном времени и других данных в tarsstat внутри фреймворка Tars. Не требуется пользовательское развитие. После того, как соответствующая информация правильно установлена при инициализации программы, она автоматически отчётируется внутри фреймворка (включая клиент и сервер).После того, как клиент вызывает интерфейс отчёта, он временно хранится в памяти. Когда достигается определённое время, он отчётируется в службе tarsstat (по умолчанию один раз в минуту). Мы называем временной промежуток между двумя моментами отчёта временным интервалом отчёта, и выполняем операции, такие как накопление и сравнение ключей в этом временно интервале отчёта.
Пример кода следующий:go // для ошибки ReportStat(msg, 0, 1, 0)
// для успеха
ReportStat(msg, 1, 0, 0)
//func ReportStat(msg *Message, succ int32, timeout int32, exec int32) //см. больше деталей в tars/statf.go
Описание:
> * Обычно нам не нужно беспокоиться о статистическом отчете, так как фреймворк tarsgo выполняет этот отчет после каждого вызова клиента к серверу, независимо от того, был ли вызов успешным или неудачным. Успешность, неудачность, среднее время выполнения и другие данные будут отображаться в системе веб-управления при правильной настройке.
> * Если основной сервис развернут в системе веб-управления, вам не нужно определять Communicator и настраивать конфигурации tarsregistry, tarsstat и т.д., сервис будет автоматически отчитываться.
> * Если основной сервис или программа не развернуты в системе веб-управления, вам нужно определить Communicator, настроить tarsregistry, tarsstat и т.д., чтобы вы могли просматривать мониторинг вызываемого сервиса в системе веб-управления.
> * Отчетные данные отчитываются регулярно и могут быть настроены в конфигурации Communicator.
### 7 Отчет об аномалиях
Для лучшего мониторинга, фреймворк TARS поддерживает прямое отчетное сообщение об аномалиях в tarsnotify в программе, которое можно просмотреть на странице веб-управления.Фреймворк предоставляет три макроса для отчета о различных исключениях:
```go
tars.reportNotifyInfo("Ошибка получения данных из MySQL!")
Info — это строка, которая может быть прямым отчетом строки в tarsnotify. Отчетная строка может быть просмотрена на странице, после чего можно отправлять уведомления на основе отчетной информации.### 8 Статистика атрибутов (свойств) Чтобы облегчить бизнес-статистику, фреймворк TARS также поддерживает отображение информации на платформе веб-управления.
Текущие поддерживаемые типы статистики включают следующее:
- Сумма (sum) //вычисляет сумму каждого отчетного значения.
- Среднее (avg) //вычисляет среднее каждого отчетного значения.
- Распределение (distr) //вычисляет распределение каждого отчета, параметр — это список, и вычисляет вероятностное распределение каждого интервала.
- Максимум (max) //вычисляет максимальное значение каждого отчетного значения.
- Минимум (min) //вычисляет минимальное значение каждого отчетного значения.
- Количество (count) //вычисляет количество отчетных вызовов.
```go
sum := tars.NewSum()
count := tars.NewCount()
max := tars.NewMax()
min := tars.NewMin()
d := []int{10, 20, 30, 50}
distr := tars.NewDistr(d)
p := tars.CreatePropertyReport("testproperty", sum, count, max, min, distr)
for i := 0; i < 5; i++ {
v := rand.Intn(100)
p.Report(v)
}
```Описание:
> * Данные отчитываются регулярно и могут быть настроены в конфигурации коммуникатора; в настоящее время отчеты создаются один раз в минуту;
> * Создайте функцию PropertyReportPtr: параметр createPropertyReport может быть любой коллекцией статистических методов; пример использует шесть статистических методов, обычно требуется только один или два;
> * Обратите внимание, что при вызове createPropertyReport вы должны создать и сохранить созданный объект после включения сервиса, а затем просто использовать объект для отчета, не создавая его каждый раз при использовании.### 9 удалённая конфигурация
Пользователь может настроить удалённую конфигурацию из OSS. Подробнее см. в https://github.com/TarsCloud/TarsFramework/blob/master/docs-en/tars_config.md.
Это пример, иллюстрирующий, как использовать этот API для получения конфигурационного файла из удалённого источника.
```go
import "github.com/TarsCloud/TarsGo/tars"
...
cfg := tars.GetServerConfig()
remoteConf := tars.NewRConf(cfg.App, cfg.Server, cfg.BasePath)
config, _ := remoteConf.GetConfig("test.conf")
...
Файл setting.go в пакете tars используется для управления производительностью и характеристиками tarsgo. Некоторые опции должны быть обновлены из GetServerConfig().
// количество рабочих потоков для обработки запросов от клиентов
// нулевое значение означает отсутствие контроля, один горутина для каждого запроса от клиента.
// runtime.NumCpu() обычно обеспечивает наилучшую производительность в тестах.
var MaxInvoke int = 0
const (
// в настоящее время некоторые опции должны быть обновлены из удалённой конфигурации
// версия
TarsVersion string = "1.0.0"
// сервер
)
``` AcceptTimeout time.Duration = 500 * time.Millisecond
//нулевое значение означает отсутствие установки read deadline для Conn (лучшая производительность)
ReadTimeout time.Duration = 0 * time.Millisecond
//нулевое значение означает отсутствие установки write deadline для Conn (лучшая производительность)
WriteTimeout time.Duration = 0 * time.Millisecond
//нулевое значение означает отсутствие установки deadline для вызова пользовательского интерфейса (лучшая производительность)
HandleTimeout time.Duration = 0 * time.Millisecond
IdleTimeout time.Duration = 600000 * time.Millisecond
ZombileTimeout time.Duration = time.Second * 10
QueueCap int = 10000000
``````md
### 11 Поддержка HTTP`tars.TarsHttpMux` похож на [http.ServeMux](https://golang.org/pkg/net/http/#ServeMux), параметр `pattern` используется как имя интерфейса в отчете мониторинга.
Вот пример HTTP-сервера:
```go
package main
import (
"net/http"
"github.com/TarsCloud/TarsGo/tars"
)
func main() {
mux := &tars.TarsHttpMux{}
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello tafgo"))
})
cfg := tars.GetServerConfig()
tars.AddHttpServant(mux, cfg.App+"."+cfg.Server+".HttpObj") // Регистрация HTTP-сервера
tars.Run()
}
В прошлом TarsGo не использовал контекст в сгенерированном клиентском коде или в реализации кода, предоставленного пользователем. Это делало передачу некоторой информации фреймворка, такой как IP-адрес клиента, порт и т.д., или передачу пользователем информации о цепочке вызовов в фреймворк затруднительной. После рефакторинга интерфейса поддержка контекста была добавлена, и эта информация будет реализована через контекст. Этот рефакторинг предназначен для совместимости с более старым поведением пользователей и полностью совместим.Использование контекста на сервере
type ContextTestImp struct {
}
// необходимо добавить параметр ctx context.Context
func (imp *ContextTestImp) Add(ctx context.Context, a int32, b int32, c *int32) (int32, error) {
// Мы можем использовать контекст для получения полезной информации, такой как Client, IP, Port и информацию о трассировке
// более подробно читайте в tars/util/current
ip, ok := current.GetClientIPFromContext(ctx)
if !ok {
logger.Error("Ошибка получения IP из контекста")
}
return 0, nil
}
// просто замените AddServant на AddServantWithContext
app.AddServantWithContext(imp, cfg.App+"."+cfg.Server+".ContextTestObj")
``Использование контекста клиента``````go
ctx := context.Background()
c := make(map[string]string)
c["a"] = "b"
// просто замените app.Add на app.AddWithContext, теперь вы можете передать контекст в фреймворк,
// если вы хотите установить контекст пакета запроса, вы можете передать опциональный параметр, такой как c, который является ...[string]string
ret, err := app.AddWithContext(ctx, i, i*2, &out, c)
```
Чтобы ознакомиться с полным примером клиента и сервера, перейдите в examples/ContextTestServer
### 13 Фильтры и плагин Zipkin
Для поддержки написания плагинов мы добавили фильтры в фреймворк. У нас есть фильтры для клиента и сервера.
```go
// ServerFilter, dispatch и f передаются как параметры для перехвата реализации пользователя.
// req и resp это
type ServerFilter func(ctx context.Context, d Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error)
//
type ClientFilter func(ctx context.Context, msg *Message, invoke Invoke, timeout time.Duration) (err error)
// RegisterServerFilter регистрирует фильтр серверной части
// func RegisterServerFilter(f ServerFilter)
// RegisterClientFilter регистрирует фильтр клиента
// func RegisterClientFilter(f ClientFilter)
```Имея эти фильтры, теперь мы можем добавлять opentracing для каждого запроса.
Давайте посмотрим на фильтр клиента для opentracing.
```go
// ZipkinClientFilter возвращает фильтр клиента tars для подключения zipking opentracing.
func ZipkinClientFilter() tars.ClientFilter {
return func(ctx context.Context, msg *tars.Message, invoke tars.Invoke, timeout time.Duration) (err error) {
var pCtx opentracing.SpanContext
req := msg.Req
// Если контекст span передан в контекст, мы используем этот контекст как родительский span, иначе начинаем новый span.
// Имя метода запроса rpc используется как имя span.
if parent := opentracing.SpanFromContext(ctx); parent != nil {
pCtx = parent.Context()
}
cSpan := opentracing.GlobalTracer().StartSpan(
req.SFuncName,
opentracing.ChildOf(pCtx),
ext.SpanKindRPCClient,
)
defer cSpan.Finish()
cfg := tars.GetServerConfig()
}
}
``` // Устанавливаем дополнительную информацию для span, такие как метод, интерфейс, протокол, версия, IP и порт и т.д.
cSpan.SetTag("client.ipv4", cfg.LocalIP)
cSpan.SetTag("tars.interface", req.SServantName)
cSpan.SetTag("tars.method", req.SFuncName)
cSpan.SetTag("tars.protocol", "tars")
cSpan.SetTag("tars.client.version", tars.TarsVersion)
``````md
// Внедряем контекст span в статус пакета запроса, который является map[string]string
if req.Status != nil {
err = opentracing.GlobalTracer().Inject(cSpan.Context(), opentracing.TextMap, opentracing.TextMapCarrier(req.Status))
if err != nil {
logger.Error("ошибка внедрения span в статус:", err)
}
} else {
s := make(map[string]string)
err = opentracing.GlobalTracer().Inject(cSpan.Context(), opentracing.TextMap, opentracing.TextMapCarrier(s))
if err != nil {
logger.Error("ошибка внедрения span в статус:", err)
} else {
req.Status = s
}
}
// Ничего не меняем, просто вызываем запрос.
err = invoke(ctx, msg, timeout)
if err != nil {
// Ошибка вызова, логируем информацию об ошибке в span.
ext.Error.Set(cSpan, true)
cSpan.LogFields(oplog.String("event", "error"), oplog.String("message", err.Error()))
}
return err
}
```
Сервер добавит фильтры, которые извлекают контекст span из статуса пакета запроса и начинают новый span.
Для примеров кода для сторон клиента и сервера, ознакомьтесь с ZipkinTraceClient и ZipkinTraceServer в разделе examples/TarsGo/tars/plugin/zipkintracing.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )