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
- 性能较好,官方测试 在8 CPU+16GB+50进程+16线程下,TPS可以达41w/s。性能数据
- 这套框架比较重,提供涉及到开发、运维、测试等一整套的解决方案。
- Tars协议只是实现该方案的高性能RPC协议而已。
- 在开源界里,涉及服务治理,多语言,暂时只有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
更新模板
- 找到运维管理
- 进入到模板管理
- 找到tars.tarsstat->编辑->修改内容为tars.tarsstat.md
- 保存
- 重启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加入到这套服务治理的体系里面来呢?这有点像鸡生蛋,蛋生鸡的问题了。
总结
- 安装时,多查看相关的服务日志。
- 根据日志搜索相关源代码,定位问题。
- 多看说明文档。
参考链接
- Tars 基本介绍
- Tars 详细介绍
- Tencent Tars 的Docker镜像脚本与使用
- TARS PHP TCP服务端与客户端开发
- Tencent Tars 的Docker镜像脚本与使用 GitHub 源代码
- TARS Kubernetes 部署
- 腾讯 Tars 基础框架手动搭建——填掉官方 Guide 的坑
- TARS 快速入门
- 解读 | TARS 开源项目发布 Go 语言版本
- Tars PHP Demo
- 源代码 Tars TarsPHP