Tars实践

什么是Tars

Tars这个名字取自于电影”星际穿越”中的机器人,它是基于名字服务使用Tars协议的高性能RPC开发框架,配套一体化的运营管理平台,并通过伸缩调度,实现运维半托管服务。

Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架TAF(Total Application Framework),目前支持C++,Java,PHP,Nodejs语言。该框架为用户提供了涉及到开发、运维、以及测试的一整套解决方案,帮助一个产品或者服务快速开发、部署、测试、上线。 它集可扩展协议编解码、高性能RPC通信框架、名字路由与发现、发布监控、日志统计、配置管理等于一体,通过它可以快速用微服务的方式构建自己的稳定可靠的分布式应用,并实现完整有效的服务治理。

目前支持的开发语言如下:

  • C++
  • Java
  • Nodejs
  • PHP
  • Go

协议支持的类型如下:

特点 类型
基本类型 void
bool
byte
short
int
long
float
double
string
unsigned byte
unsigned short
unsigned int
复杂类型 enum
const
struct
vector
map
struct、vector、map的嵌套

其中复杂类型可以嵌套使用,例如:

# map 
map<int,string>
# struct、vector、map的嵌套
vector<string>
vector<map<string,string>>
map<vector<string>,vector<string>>

为什么要用Tars

  1. 性能较好,官方测试 在8 CPU+16GB+50进程+16线程下,TPS可以达41w/s。性能数据
  2. 这套框架比较重,提供涉及到开发、运维、测试等一整套的解决方案。
  3. Tars协议只是实现该方案的高性能RPC协议而已。
  4. 在开源界里,涉及服务治理,多语言,暂时只有Tars一家。

怎么用Tars

架构图

架构拓扑图

核心基础服务

服务名 类型 功能
tarsAdminRegistry 核心 服务注册,接入管理服务
tarsregistry 核心 服务发现,也叫主控,名字服务路由
tarsnode 核心 服务管理,节点管理服务
tarsconfig 核心 配置中心,配置服务
tarspatch 核心 自动发布,发布服务
tarsnotify 普通 服务上报,异常上报统计服务
tarsstat 普通 服务统计,模调数据统计服务
tarsproperty 普通 业务属性统计服务
tarslog 普通 服务日志,日志服务
tarsqueryproperty 普通
tarsquerystat 普通

部署方法

Tars的Docker镜像并未打包MySQL,因此需要自行独立启动MySQL服务,然后再启动Web管理服务。

相关镜像

镜像名称 备注
mysql:5.7 MySQL 5.7官方镜像
tarscloud/tars:php7 开发环境镜像,包含php7.2/swoole/phptars等扩展

拉取相关镜像

docker pull mysql:5.7
docker pull tarscloud/tars:php7

启动MySQL

docker run --name mysql -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 -v /tars.data:/var/lib/mysql mysql:5.7 --sql_mode=NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION --innodb_use_native_aio=0

启动Web管理服务

docker run -d -it --name tars --link mysql --env MOUNT_DATA=true --env DBIP=mysql --env DBPort=3306 --env DBUser=root --env DBPassword=password -p 3000:3000 -v /tars.dev:/data tarscloud/tars:php7

进入运行环境,查看问题

docker exec -it tars bash

登录数据库,查看数据

mysql -hmysql -P3306 -uroot -p

访问Web管理后台,浏览器打开

http://0.0.0.0:3000/

遇到的问题

尽量优先查看相关的服务日志,然后阅读并搜索相关的源码,查找并定位问题。

Tars源代码阅读

cd dev
# 拉取Tars源代码
git clone git@github.com:TarsCloud/Tars.git
cd Tars
# 更新子模块代码
git submodule update --init --recursive

日志

日志服务 日志路径 备注
服务日志 /usr/local/app/tars/app_log/ /usr/local/app/tars/app_log/应用名/服务名/目录下
Tars管理错误日志 /data/logs/tars-node-web-error.log
Tars管理日志 /data/logs/tars-node-web-out.log
核心服务日志 /data/tars/app_log/tars
./tarsAdminRegistry/tars.tarsAdminRegistry.log tarsAdminRegistry
./tarsregistry/tars.tarsregistry.log tarsregistry
./tarsnode/tars.tarsnode.log tarsnode
./tarsconfig/tars.tarsconfig.log tarsconfig
./tarspatch/tars.tarspatch.log tarspatch
./tarsnotify/tars.tarsnotify.log tarsnotify
./tarsstat/tars.tarsstat.log tarsstat
./tarsproperty/tars.tarsproperty.log tarsproperty
./tarslog/tars.tarslog.log tarslog
./tarsqueryproperty/tars.tarsqueryproperty.log tarsqueryproperty
./tarsquerystat/tars.tarsquerystat.log tarsquerystat
PHPTest /data/tars/app_log/PHPTest/PHPServer PHPTest Server
./log_debug.log debug日志
./PHPTest.PHPServer.log 服务启动日志

服务路径

服务 路径 IP/Port
核心服务路径 /usr/local/app/tars 1000X开头
Web管理服务 /usr/local/tarsweb 0.0.0.0:3000

内部错误的问题

现象:点击服务管理或者运维管理都是出现内部错。

error: 172.17.0.1||TreeController.js:30|[listTree] SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306

# 编辑Web管理配置文件
vim /usr/local/tarsweb/config/webConf.js
# 修改数据库链接
host: '127.0.0.1' => host: 'mysql'

出现这个错误的原因是MySQL链接失败。如果在docker内部已经link上MySQL,直接修改地址即可。否则,重新初始化安装Web管理服务,在docker 加入正确的MySQL参数。

--env DBIP=mysql --env DBPort=3306 --env DBUser=root --env DBPassword=password

数据库问题

发现数据库tars_stat和tars_property为空。执行模板相关的SQL,发现会提示下面这个问题。

ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead

继续 查找原因,发现部分PRIMARY KEY 不能为空,这个与MySQL5.7的SQL模式有关,开始不兼容这类SQL语句了。

PRIMARY KEY (`source_id`,`f_date`,`f_tflag`,`master_name`,`slave_name`,`interface_name`,`master_ip`,`slave_ip`,`slave_port`,`return_value`,`tars_version`)
# 举例
`source_id` varchar(15) default NULL
# 在MySQL5.7需要修改为下面的方式
`source_id` VARCHAR(15) NOT NULL DEFAULT ''

# 同理
`slave_port` int(10) default NULL
修改为
`slave_port` INT(10) NOT NULL DEFAULT 0

更新模板

  1. 找到运维管理
  2. 进入到模板管理
  3. 找到tars.tarsstat->编辑->修改内容为tars.tarsstat.md
  4. 保存
  5. 重启tarsstat服务,服务tarsproperty也一样处理。

这样数据库建表就成功了。

Connection refused

在相关日志中查看,发现下面的问题

2019-01-18 12:03:05|9262|ERROR|[TARS][CommunicatorEpoll::handleInputImp] connect error tcp -h 172.17.0.5 -p 10003,tars.tarslog.LogObj,_connExcCnt=6,Connection refused

2019-01-18 12:04:00|9262|ERROR|[TARS][CommunicatorEpoll::handleInputImp] connect error tcp -h 172.17.0.5 -p 10005,tars.tarsproperty.PropertyObj,_connExcCnt=1,Connection refused

解决方案是服务管理中重启相关的服务,如tarslog、tarsproperty等。

实战

根据官方文档TARS PHP TCP服务端与客户端开发,我已经把完成版本的代码,放在GitHub上,你可以直接下载到目录执行composer install即可。

PHP TCP服务端开发

由于版本库地址变更,导致一些代码的链接失效。可以直接替换成最新的地址。

将
https://github.com/TarsPHP/TarsPHP/blob
替换为
https://raw.githubusercontent.com/TarsPHP/TarsPHP

为了加速composer安装,将下面的repo加入composer.json

"repositories": [
    {
        "type": "composer",
        "url": "https://packagist.phpcomposer.com"
    },
    {
        "packagist": false
    }
]

代码发布

composer run-script deploy

PHP客户端开发

composer问题

在composer install时出现错误。

Your requirements could not be resolved to an installable set of packages.
Problem 1
    - The requested package phptars/tars-client 0.1.1 exists as phptars/tars-client[0.1.5, 0.1.6, 0.2.0, 0.2.1, 0.2.2, dev-master] but these are rejected by your constraint.

修改composer.json中的phptars/tars-client版本为0.1.5或者0.2.0。

"phptars/tars-client" : "0.2.0"

日志错误

PHP Notice:  Undefined index: iRequestId in /data/tarsnode_data/PHPTest.PHPServer/bin/src/vendor/phptars/tars-server/src/protocol/TARSProtocol.php on line 103

PHP Notice:  Undefined index: protocolName in /data/tarsnode_data/PHPTest.PHPServer/bin/src/vendor/phptars/tars-server/src/core/Server.php on line 68

# 对代码做下兼容处理
$iRequestId = isset[$unpackResult['iRequestId']]?$unpackResult['iRequestId']:0;

$this->protocolName = isset($this->tarsServerConfig['protocolName'])?$this->tarsServerConfig['protocolName']:'';

请求异常

如果你在请求的时候遇到下面的错误:

PHP Fatal error:  Uncaught Exception: Rout fail in /data/web/client/vendor/phptars/tars-client/src/Communicator.php:82
Stack trace:

首先尝试telnet下

yum install telnet
telnet 172.17.0.5 2019 #可以成功连接上,说明服务器程序已经运行了。
# 找到你的docker内网地址
ip addr

客户端需要针对服务请求做一些调整,服务发现采用指定服务地址,需要修改index.php。

# host 为docker的内网地址 port 为你的服务端口号
$host = "172.17.0.5";
$port = "2019";
$config = new \Tars\client\CommunicatorConfig();
$config->setLocator(sprintf('tars.tarsregistry.QueryObj@tcp -h %s -p %s',$host,$port));

修改为下面
$host = "172.17.0.5";
$port = "2019";
$routeInfo[] = [
'sIp' => $host,
'iPort' => $port,
];
$config = new \Tars\client\CommunicatorConfig();
$config->setRouteInfo($routeInfo);

执行测试

cd client
php index.php

你会发现了久违的Hello World,在相关的日志中也有了。

[2019-01-18 10:07:10] tars_logger.INFO: sayHelloWorld name:ted [] []

疑问

类似核心服务tarsAdminRegistry如何实现多接点部署呢?

如果加入到监控体系,那么核心服务类似于tarsAdminRegistry挂了,监控体系可以自动拉取服务?我能想到的方案是必须哟一个监控脚本实时监控服务吧。

那为什么没有把对核心服务tarsAdminRegistry加入到这套服务治理的体系里面来呢?这有点像鸡生蛋,蛋生鸡的问题了。

总结

  1. 安装时,多查看相关的服务日志。
  2. 根据日志搜索相关源代码,定位问题。
  3. 多看说明文档。

参考链接

  1. Tars 基本介绍
  2. Tars 详细介绍
  3. Tencent Tars 的Docker镜像脚本与使用
  4. TARS PHP TCP服务端与客户端开发
  5. Tencent Tars 的Docker镜像脚本与使用 GitHub 源代码
  6. TARS Kubernetes 部署
  7. 腾讯 Tars 基础框架手动搭建——填掉官方 Guide 的坑
  8. TARS 快速入门
  9. 解读 | TARS 开源项目发布 Go 语言版本
  10. Tars PHP Demo
  11. 源代码 Tars TarsPHP

打赏作者

您的支持将鼓励我们继续创作!

[微信] 扫描二维码打赏

[支付宝] 扫描二维码打赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注