go get -u github.com/TarsCloud/TarsGo/tars
В папке $GOPATH/src создайте файл Tars, например hello.tars, в директории $GOPATH/src/TestApp/TestServer/hello.tars. Для получения дополнительной информации о протоколе Tars, см. https://github.com/TarsCloud/TarsTup/blob/master/docs-en/tars_tup.md.
module TestApp
{
interface 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
package main
import (
"github.com/TarsCloud/TarsGo/tars"
"TestApp"
)
type HelloImp struct {
}
// Реализация интерфейса Test
func (imp *HelloImp) Test() (int32, error) {
return 0, nil
}
// Реализация интерфейса TestHello
``````go
func (imp *HelloImp) TestHello(in string, out *string) (int32, error) {
*out = in
return 0, nil
}
func main() { // Инициализация служб
imp := new(HelloImp) // Создание реализации
app := new(TestApp.Hello) // Создание и инициализация приложения Tars
cfg := tars.GetServerConfig() // Получение объекта конфигурации сервера
app.AddServant(imp, cfg.App+"."+cfg.Server+".HelloObj") // Регистрация служб
tars.Run()
}
Описание:
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
}
```- Node: локальный адрес tarsnode, используется только при развертывании на платформе Tars.
- APP: имя приложения.
- Server: имя сервиса.
- LogPath: путь для сохранения логов.
- LogSize: размер для переключения логов.
- LogLevel: уровень для переключения логов.
- Version: версия Tarsg.
- LocalIP: локальный IP-адрес.
- BasePath: базовый путь для двоичных файлов.
- DataPath: путь для хранения кэшированных файлов.
- Config: центр конфигурации для получения конфигураций, например, tars. tarsconfig. ConfigObj
- Notify: центр уведомлений для отправки отчетов, например, tars. tarsnotify. NotifyObj
- Log: удалённый центр логов, например, tars. tarslog. LogObj
- NetThread: резервный поток Go для управления получением и отправкой пакетов.
- Adapters: специфическая конфигурация для каждого адаптера.
- Container: резервное поле для будущего использования, используется для хранения имени контейнера.
- Isdocker: резервное поле для будущего использования, используется для указания, запущен ли сервис в контейнере.
- Enableset: если используется set, то значение True.
- Setdivision: указывает, какой set используется, например, gray. sz. *Вот пример конфигурации сервера:
```xml
<tars>
<application>
enableset=Y
setdivision=gray. sz. *
<server>
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=10М
config=tars. tarsconfig. ConfigObj
notify=tars. tarsnotify. NotifyObj
log=tars. tarslog. LogObj
#тайм-аут для деактивации, мс.
deactivating-timeout=2000
logLevel=DEBUG
</server>
</application>
</tars>
```#### 1.5 Адаптер
Адаптер связывает IP и порт для каждого объекта. В примере реализации серверного кода,
`app.AddServant(imp, cfg.App + "." + cfg.Server + ".HelloObj")` выполняет настройку и связывает реализацию адаптера для `HelloObj`. Пример полной конфигурации адаптера приведен ниже:
```xml
<tars>
<application>
<server>
<!-- each adapter configuration -->
<TestApp.HelloServer.HelloObjAdapter>
<!-- allow Ip for white list -->
allow
<!-- ip and port to listen on -->
endpoint=tcp -h 10.120.129.226 -p 20001 -t 60000
<!-- handlegroup -->
handlegroup=TestApp.HelloServer.HelloObjAdapter
<!-- max connection -->
maxconns=200000
<!-- portocol, only tars for now -->
protocol=tars
<!-- max capbility in handle queue -->
queuecap=10000
<!-- timeout in ms for the request in the queue -->
queuetimeout=60000
<!-- servant -->
servant=TestApp.HelloServer.HelloObj
<!-- threads in handle server side implement code. goroutine for 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 sync-invoke-timeout=3000 async-invoke-timeout=5000 refresh-endpoint-interval=60000 report-interval=60000 sample-rate=100000 max-sample-count=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 Wold"
var res string
ret, err := app.TestHello(req, &res)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret, res)
Описание:
Коммуникатор представляет собой набор ресурсов для отправки и получения пакетов клиентом, который в конечном итоге управляет сокетной коммуникацией каждого объекта. В одном приложении требуется только один коммуникатор.
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". Если вам не требуется, чтобы главный сервис находил сервис, то это свойство не нужно настраивать.
> * important 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 запущен на двух серверах, то инициализация приложения выглядит следующим образом:
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`.
Вот пример, показывающий адрес мастера через установку параметров коммуникатора:
var *tars.Communicator comm = tars.NewCommunicator() comm.SetProperty("locator", "tars.tarsregistry.QueryObj@tcp -h ... -p ...")
Так как клиенту требуется зависеть от адреса мастера, мастер также должен обладать возможностью отказоустойчивости. Методы отказоустойчивости мастера такие же, как и выше, то есть указывается адрес двух мастеров.
##### 2.4.2. Односторонний вызов
TODO. tarsgo временно не поддерживает.
##### 2.4.3. Синхронный вызов
```go
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 Wold"
var res string
ret, err := app.TestHello(req, &res)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret, res)
tarsgo позволяет легко использовать асинхронные вызовы с помощью goroutine. В отличие от C++, нам не нужно реализовывать обратные вызовы.
package main```go
import (
"fmt"
"github.com/TarsCloud/TarsGo/tars"
"time"
"TestApp"
)
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)
go func() {
var req string = "Hello World"
var res string
ret, err := app.TestHello(req, &res)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret, res)
}()
time.Sleep(1 * time.Second)
}
```go
import (
"fmt"
"github.com/TarsCloud/TarsGo/tars"
"time"
"TestApp"
)
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)
go func() {
var req string = "Hello World"
var res string
ret, err := app.TestHello(req, &res)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret, res)
}()
time.Sleep(1 * time.Second)
}
Клиент может вызвать сервер через set, настроив соответствующий конфигурационный файл, где enableset установлен в "y", а setdivision, например, установлен в "gray.sz.*". Для получения дополнительной информации обратитесь к https://github.com/TarsCloud/Tars/blob/master/docs-en/tars_idc_set.md.
Если вы хотите выполнять вызовы через set вручную, 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; // Нарушение правил вызова set клиентом
const int TARSCLIENTDECODEERR = -12; // Исключение декодирования клиента
const int TARSSERVERUNKNOWNERR = -99; // Сервер находится в неизвестном состоянии
```### 4 Логирование
Быстрый пример использования tarsgo для переключения логов:
```go
TLOG := tars.GetLogger("TLOG")
TLOG.Debug("Debug logging")
Это создаст объект *tars.Logger
, определенный в tars/util/logger
, и после вызова GetLogger
создаст лог-файл в Logpath
, указанном в config.conf
. Имя файла будет cfg.App + "." + cfg.Server + "_" + имя
, и этот лог-файл будет переключаться после достижения размера 100МБ (по умолчанию), с максимальным количеством переключаемых файлов 10 (по умолчанию).
```go
TLOG := tars.GetDayLogger("TLOG", 1)
TLOG.Debug("Debug logging")
Используйте GetHourLogger("TLOG", 1)
для переключения логов по часам. Если вы хотите отправлять логи на удалённый сервер, определённый в config.conf
как tars.tarslog.LogObj
, вам нужно будет настроить лог-сервер. Полное определение TARS файла можно найти в tars/protocol/res/LogF.tars
, а сам лог-сервер можно найти в Tencent/Tars/cpp/framework/LogServer
. Быстрый пример:
TLOG := GetRemoteLogger("TLOG")
TLOG.Debug("Debug logging")
Если вы хотите настроить уровень логирования, вы можете сделать это на платформе OSS, предоставляемой проектом TARS в Tencent/Tars/web
.
Если вы хотите настроить свои собственные логи, вы можете найти больше информации в tars/util/logger
, tars/logger.go
и tars/remotelogger.go
.
Фреймворк TARS поддерживает динамическое получение команд для обработки бизнес-логики, например, динамическое обновление конфигурации.Текущая версия 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. Это не требует разработки пользователем, достаточно правильно настроить информацию при инициализации программы, чтобы автоматически отправлять отчёты (включая клиентскую и серверную части).
После вызова интерфейса отчёта клиентом, информация временно хранится в памяти, и при достижении определённого времени отправляется в tarsstat (по умолчанию каждую минуту). Временной интервал между двумя отправками называется интервалом отчёта, и в течение этого интервала выполняются операции агрегации и сравнения значений с одинаковым ключом.```go // Для ошибок ReportStat(msg, 0, 1, 0)
// Для успешных операций ReportStat(msg, 1, 0, 0)
## 7 Отчет об ошибках
Для улучшенного мониторинга, фреймворк TARS поддерживает прямую отправку информации об ошибках в tarsnotify, которую можно просмотреть на веб-странице управления.
Фреймворк предоставляет три макроса для отправки информации об ошибках различных типов:
```go
tars.reportNotifyInfo("Ошибка при получении данных из MySQL!")
Info — это строка, которую можно отправить напрямую в tarsnotify. Отправленная строка будет отображаться на странице, после чего можно будет использовать её для отправки уведомлений.
Для удобства статистического анализа бизнес-процессов, фреймворк TARS также поддерживает отображение информации на веб-странице управления.
Текущие поддерживаемые типы статистики включают:
- Sum(sum) // Вычисляет сумму всех отправленных значений
- Average(avg) // Вычисляет среднее значение всех отправленных значений
- Distribution(distr) // Вычисляет распределение всех отправленных значений, параметр — это список, который используется для вычисления вероятностного распределения для каждого интервала
- Maximum(max) // Вычисляет максимальное значение всех отправленных значений
- Minimum(min) // Вычисляет минимальное значение всех отправленных значений
- Count(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
// нулевое значение означает, что не установлено время ожидания чтения для Conn (лучшая производительность)
ReadTimeout time.Duration = 0 * time.Millisecond
// нулевое значение означает, что не установлено время ожидания записи для Conn (лучшая производительность)
WriteTimeout time.Duration = 0 * time.Millisecond
// нулевое значение означает, что не установлено время ожидания для вызова пользовательского интерфейса (лучшая производительность)
HandleTimeout time.Duration = 0 * time.Millisecond
IdleTimeout time.Duration = 600000 * time.Millisecond
ZombileTimeout time.Duration = time.Second * 10
QueueCap int = 10000000
// клиент
ClientQueueLen int = 10000
ClientIdleTimeout time.Duration = time.Second * 600
ClientReadTimeout time.Duration = time.Millisecond * 100
ClientWriteTimeout time.Duration = time.Millisecond * 3000
ReqDefaultTimeout int32 = 3000
ObjQueueMax int32 = 10000
// отчеты
PropertyReportInterval time.Duration = 10 * time.Second
StatReportInterval time.Duration = 10 * time.Second
// основной цикл
MainLoopTicker time.Duration = 10 * time.Second
// адаптер
AdapterProxyTicker time.Duration = 10 * time.Second
AdapterProxyResetCount int = 5
)
``` // значения по умолчанию для коммуникатора, обновляются из удаленного конфигурирования
refreshEndpointInterval int = 60000
reportInterval int = 10000
AsyncInvokeTimeout int = 3000
// настройки TCP-сети
TCPReadBuffer = 128 * 1024 * 1024
TCPWriteBuffer = 128 * 1024 * 1024
TCPNoDelay = false
)```
### 11 Поддержка HTTP
Текущий `tar.TarsHttpMux` и встроенный `golang` `http.ServeMux` используются одинаковым образом, где параметр `pattern` используется как имя интерфейса для мониторинга данных. В будущем планируется реализовать более мощные функции маршрутизации, вдохновленные `github.com/gorilla/mux`.
Для примера реализации см. ниже:
```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()
}
```
### 12 Поддержка Context
Ранее в сгенерированном клиентском коде или коде, переданном пользователем, не использовался `context`. Это затрудняло передачу информации о фреймворке, такой как IP-адрес клиента и порт, или передачу информации о вызове пользователем в фреймворк. После переработки интерфейса была добавлена поддержка `context`, что позволяет передавать все эти контекстные данные через `context`. Переработка была выполнена с полной совместимостью для старых пользовательских действий.
Использование `context` на стороне сервера```go
type ContextTestImp struct {
}
// Необходимо добавить параметр `ctx context.Context` в интерфейсе
func (imp *ContextTestImp) Add(ctx context.Context, a int32, b int32, c *int32) (int32, error) {
// Мы можем использовать `context` для получения информации, переданной фреймворком, например, получения IP-адреса клиента
ip, ok := current.GetClientIPFromContext(ctx)
if !ok {
logger.Error("Ошибка получения IP-адреса из контекста")
}
return 0, nil
}
// Ранее использовался `AddServant`, теперь следует использовать `AddServantWithContext`
app.AddServantWithContext(imp, cfg.App+"."+cfg.Server+".ContextTestObj")
```
Использование `context` на стороне клиента
```golang
ctx := context.Background()
c := make(map[string]string)
c["a"] = "b"
// Ранее использовался `app.Add` для вызова клиента, теперь следует использовать `app.AddWithContext`, чтобы передать `context` фреймворку
// Если необходимо установить `context` для запроса `tars`, можно передать дополнительные параметры, такие как `c`, где `c` является необязательным параметром, формат которого `...[string]string`
ret, err := app.AddWithContext(ctx, i, i*2, &out, c)
```
Полные примеры использования `context` на стороне сервера и клиента см. в `TarGo/examples`
```
### 13 Механизм фильтров (плагины) и zipkin opentracing
Для поддержки пользовательских плагинов мы реализовали механизм фильтров, который включает в себя серверные и клиентские фильтры.```go
// Серверный фильтр, который принимает dispatch, f (интерфейс для вызова пользовательского кода), req (пакет запроса пользователя) и resp (пакет ответа сервера)
type ServerFilter func(ctx context.Context, d Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error)
// Клиентский фильтр, который принимает msg (включающий информацию об obj, adapter, req и resp пакетах) и пользовательское значение таймаута
type ClientFilter func(ctx context.Context, msg *Message, invoke Invoke, timeout time.Duration) (err error)
// Регистрация серверного фильтра
//func RegisterServerFilter(f ServerFilter)
// Регистрация клиентского фильтра
//func RegisterClientFilter(f ClientFilter)
```С помощью фильтров мы можем выполнять фильтрацию запросов на стороне сервера и клиента, например, используя hook для распределённого отслеживания с использованием opentracing span.
Давайте рассмотрим пример клиентского фильтра:
```go
// Создание клиентского фильтра tars для внедрения span
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 с именем функции RPC-запроса
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()
``````go
// Устанавливаем информацию для 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)
``````markdown
// Вставляем span в поле Status запроса, где Status имеет структуру 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 в Status:", err)
}
} else {
s := make(map[string]string)
err = opentracing.GlobalTracer().Inject(cSpan.Context(), opentracing.TextMap, opentracing.TextMapCarrier(s))
if err != nil {
logger.Error("ошибка вставки span в Status:", 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()))
}
``````go
return err
}
```Сервер также регистрирует фильтр, основная функция которого — извлечение контекста вызова из поля `status` тела запроса. Этот контекст используется как родительский span для записи информации о вызовах.
Для более подробного изучения кода обратитесь к TarsGo/tars/plugin/zipkintracing.
Полные примеры клиентской и серверной сторон для zipkin tracing доступны в TarsGo/examples: ZipkinTraceClient и ZipkinTraceServer.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )