NOVA示例教程¶
- 编写nova服务thrift文件
- 生成nova存根代码, 发布到仓库
- tcp(nova服务端)项目 与 http(nova客户端)项目 composer.json 分别添加nova存根代码 依赖
- tcp(nova服务端)项目 实现 nova 服务接口, 配置发布服务
- http(nova客户端)项目 配置直接tcp-server,通过 nova存根代码调用nova服务
编写nova服务thrift文件¶
thrift 结构
- .
- └── thrifts
- ├── entity
- │ ├── BaseStruct.thrift
- │ ├── ErrorLevel.thrift
- │ └── MixedStruct.thrift
- ├── exception
- │ └── DemoServiceException.thrift
- └── service
- └── DemoService.thrift
BaseStruct.thrift
- namespace nova com.yourcompany.demo.entity
- include 'ErrorLevel.thrift'
- struct BaseStruct {
- 1:optional bool propBool,
- 2:optional byte propByte,
- 3:optional i16 propI16,
- 4:optional i32 propI32,
- 5:optional i64 propI64,
- 6:optional double propDouble,
- 7:optional string propString,
- 8:optional ErrorLevel.ErrorLevel errorLevel
- }
ErrorLevel.thrift
- namespace nova com.yourcompany.demo.entity
- enum ErrorLevel {
- DEBUG = 1,
- INFO = 2,
- WARN = 3,
- ERROR = 4
- }
MixedStruct.thrift
- namespace nova com.yourcompany.demo.entity
- include 'BaseStruct.thrift'
- struct MixedStruct {
- 1:optional string propString,
- 2:optional BaseStruct.BaseStruct baseStruct,
- 3:optional list<BaseStruct.BaseStruct> propList,
- 4:optional set<BaseStruct.BaseStruct> propSet,
- 5:optional map<string, BaseStruct.BaseStruct> propMap
- }
DemoServiceException.thrift
- namespace nova com.yourcompany.demo.exception
- exception DemoServiceException {
- 1: string message
- 2: i32 code
- }
DemoService.thrift
- namespace nova com.yourcompany.demo.service
- include '../entity/ErrorLevel.thrift'
- include '../entity/BaseStruct.thrift'
- include '../entity/MixedStruct.thrift'
- include '../exception/DemoServiceException.thrift'
- service DemoService {
- void throwException() throws (1:DemoServiceException.DemoServiceException e);
- void returnVoid();
- bool returnBool();
- i32 returnI32();
- double returnDouble();
- string returnString();
- ErrorLevel.ErrorLevel returnEnum();
- BaseStruct.BaseStruct returnBaseStruct();
- MixedStruct.MixedStruct returnMixedStruct();
- list<BaseStruct.BaseStruct> returnList();
- set<BaseStruct.BaseStruct> returnSet();
- map<string, BaseStruct.BaseStruct> returnMap();
- void paraBaseNoReturn(1:string paraString, 2:ErrorLevel.ErrorLevel errorLevel);
- void paraMixedNoReturn (
- 1:bool paraBool,
- 2:i32 paraI32,
- 3:double paraDouble,
- 4:string paraString,
- 5:BaseStruct.BaseStruct baseStruct,
- 6:list<BaseStruct.BaseStruct> returnList,
- 7:set<BaseStruct.BaseStruct> returnSet,
- 8:map<string, BaseStruct.BaseStruct> returnMap,
- 9:ErrorLevel.ErrorLevel errorLevel
- );
- map<string, BaseStruct.BaseStruct> complexMethod(
- 1:bool paraBool,
- 2:i32 paraI32,
- 3:double paraDouble,
- 4:string paraString,
- 5:BaseStruct.BaseStruct baseStruct,
- 6:list<BaseStruct.BaseStruct> returnList,
- 7:set<BaseStruct.BaseStruct> returnSet,
- 8:map<string, BaseStruct.BaseStruct> returnMap,
- 9:ErrorLevel.ErrorLevel errorLevel
- )
- }
生成nova存根代码, 发布到仓库¶
下载或者编译zan-thrift工具¶
- cd thrifts
- zan-thrift --gen php # 执行工具生成存根代码
执行结果:
- Processing: .../nova-demo/thrifts/entity/BaseStruct.thrift
- Processing: .../nova-demo/thrifts/entity/ErrorLevel.thrift
- Processing: .../nova-demo/thrifts/entity/MixedStruct.thrift
- Processing: .../nova-demo/thrifts/exception/DemoServiceException.thrift
- Processing: .../nova-demo/thrifts/service/DemoService.thrift
tree
- ├── sdk
- │ └── gen-php
- │ ├── Entity
- │ │ ├── BaseStruct.php
- │ │ ├── ErrorLevel.php
- │ │ └── MixedStruct.php
- │ ├── Exception
- │ │ └── DemoServiceException.php
- │ ├── Interfaces
- │ │ └── DemoService.php
- │ ├── Service
- │ │ └── DemoService.php
- │ └── Servicespecification
- │ └── DemoService.php
编写composer.json¶
- {
- "name": "nova-service/nova-demo",
- "repositories": [
- ],
- "require": {
- "packaged/thrift": "0.9.2.1"
- },
- "autoload": {
- "psr-4": {
- "Com\\Yourcompany\\Demo\\": "sdk/gen-php"
- },
- "classmap": []
- }
- }
注意 psr-4 命名空间要与thrift文件命名空间一致,遵守com.{company}.
{module}[…]规范
将生成的存根代码push到git仓库
tcp(nova服务端)项目 与 http(nova客户端)项目 composer.json 分别添加 nova存根代码 依赖¶
- {
- ...
- "repositories": {
- # 这里因为测试demo的缘故,存根代码放在本地,通过路径引用,composer会在vendor中建立软连接
- # 正常项目引用独立的nova-service package
- {
- "type": "path",
- "url": "nova-sdk/nova-demo/",
- "options": {
- "symlink": true
- }
- }
- },
- "require": {
- ...
- # require 添加
- "nova-service/nova-demo": "*"
- }
- ...
- }
tcp(nova服务端)项目 实现 nova 服务接口, 配置发布服务¶
tcp-demo/src/Service/DemoService.php
- <?php
- namespace Com\Youzan\TcpDemo\Service;
- use Com\Yourcompany\Demo\Entity\BaseStruct;
- use Com\Yourcompany\Demo\Entity\ErrorLevel;
- use Com\Yourcompany\Demo\Entity\MixedStruct;
- use Com\Yourcompany\Demo\Exception\DemoServiceException;
- class DemoService implements \Com\Yourcompany\Demo\Interfaces\DemoService
- {
- public function returnBool()
- {
- yield true;
- }
- public function returnI32()
- {
- yield rand() % 1024;
- }
- public function returnDouble()
- {
- yield rand(1, 100) / (double)100;
- }
- public function returnString()
- {
- yield str_repeat('a', rand(1, 20));
- }
- public function returnEnum()
- {
- yield ErrorLevel::INFO;
- }
- ......
- }
配置nova服务发布
tcp-demo/resource/config/${env}/nova.php
- <?php
- return [
- // 发布服务
- "novaApi" => [
- "path" => "vendor/nova-service/nova-demo/sdk/gen-php",
- // 注意namespace要与thrift声明一致
- "namespace" => "Com\\Yourcompany\\Demo\\",
- ],
- ];
http(nova客户端)项目 配置直接tcp-server,通过 nova 存根代码调用nova服务¶
配置拉取服务
http-demo/resource/config/${env}/service_discovery.php
- <?php
- return [
- # 服务Provider应用名
- "app_names" => [
- "tcp-demo"
- ],
- "novaApi" => [
- // 这里配置与client相同
- "tcp-demo" => [
- "path" => "vendor/nova-service/nova-demo/sdk/gen-php",
- "namespace" => "Com\\Yourcompany\\Demo\\",
- ]
- ],
- "connection" => [
- // 直连地址
- // 端口参见 tcp-demo/resource/config/online/server.php host & port 配置
- "tcp-demo" => [
- "host" => "127.0.0.1",
- "port" => 8100,
- ],
- ],
- ];
调用代码:
- <?php
- namespace Com\Youzan\ZanHttpDemo\Demo\Service;
- use Com\Yourcompany\Demo\Service\DemoService;
- class NovaCall
- {
- public function invokeRemoteNovaMethod()
- {
- $result = [];
- $service = new DemoService();
- $result['Bool'] = (yield $service->returnBool());
- $result['Void'] = (yield $service->returnVoid());
- $result['I32'] = (yield $service->returnI32());
- $result['Double'] = (yield $service->returnDouble());
- $result['String'] = (yield $service->returnString());
- $result['Enum'] = (yield $service->returnEnum());
- $result['BaseStruct'] = (yield $service->returnBaseStruct());
- $result['MixedStruct'] = (yield $service->returnMixedStruct());
- $result['List'] = (yield $service->returnList());
- $result['Set'] = (yield $service->returnSet());
- $result['Map'] = (yield $service->returnMap());
- yield $result;
- }
- }
分别启动tcp-demo、http-demo¶
tcp-demo
- [2017-06-05 12:31:02 #] Running in online mode
- [2017-06-05 20:31:02 #] server starting ..... [0.0.0.0:8100]
- [2017-06-05 20:31:02 #23827.0] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=0]
- [2017-06-05 20:31:02 #23827.1] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=1]
- [2017-06-05 20:31:02 #0] worker *0 starting .....
- [2017-06-05 20:31:02 #1] worker *1 starting .....
- [2017-06-05 20:31:02 #0] redis client connect to server [host=127.0.0.1, port=6379]
- [2017-06-05 20:31:02 #1] redis client connect to server [host=127.0.0.1, port=6379]
- [2017-06-05 20:31:02 #0] redis client connect to server [host=127.0.0.1, port=6379]
- [2017-06-05 20:31:02 #1] redis client connect to server [host=127.0.0.1, port=6379]
- [2017-06-05 20:31:02 #0] mysql client connect to server [host=127.0.0.1, port=3306]
- [2017-06-05 20:31:02 #0] mysql client connect to server [host=127.0.0.1, port=3306]
- [2017-06-05 20:31:02 #1] mysql client connect to server [host=127.0.0.1, port=3306]
- [2017-06-05 20:31:02 #1] mysql client connect to server [host=127.0.0.1, port=3306]
http-demo
- [2017-06-05 12:31:50 #] Running in online mode
- [2017-06-05 20:31:50 #23838.1] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=1]
- [2017-06-05 20:31:50 #23838.0] WARNING swReactorThread_onPipeReceive: [Master] set worker idle.[work_id=0]
- [2017-06-05 20:31:50 #] server starting .....[0.0.0.0:8030]
- [2017-06-05 20:31:51 #0] worker *0 starting .....
- [2017-06-05 20:31:51 #1] worker *1 starting .....
- [2017-06-05 20:31:51 #0] redis client connect to server [host=127.0.0.1, port=6379]
- [2017-06-05 20:31:51 #1] redis client connect to server [host=127.0.0.1, port=6379]
- [2017-06-05 20:31:51 #0] redis client connect to server [host=127.0.0.1, port=6379]
- [2017-06-05 20:31:51 #1] redis client connect to server [host=127.0.0.1, port=6379]
- # 这里观察日志,已经连接到tcp-demo
- [2017-06-05 20:31:51 #0] nova client connect to server [app_name=tcp-demo, host=127.0.0.1, port=8100, namespace=com.youzan.service, protocol=nova, status=1, weight=100]
- [2017-06-05 20:31:51 #1] nova client connect to server [app_name=tcp-demo, host=127.0.0.1, port=8100, namespace=com.youzan.service, protocol=nova, status=1, weight=100]
- [2017-06-05 20:31:51 #1] mysql client connect to server [host=127.0.0.1, port=3306]
- [2017-06-05 20:31:51 #0] mysql client connect to server [host=127.0.0.1, port=3306]
- [2017-06-05 20:31:51 #1] mysql client connect to server [host=127.0.0.1, port=3306]
- [2017-06-05 20:31:51 #0] mysql client connect to server [host=127.0.0.1, port=3306]
测试
curl (http)-> http-demo (nova)-> tcp-demo
curl http://127.0.0.1:8030/index/index/novaRemoteService
- {"code":0,"msg":"json string","data":{"Bool":true,"Void":null,"I32":768,"Double":0.17000000000000001,"String":"aaaa","Enum":2,"BaseStruct":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null},"MixedStruct":{"propString":"MixedStruct","baseStruct":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null},"propList":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"propSet":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"propMap":{"returnMixedStruct":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}}},"List":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"Set":[{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}],"Map":{"returnMap":{"propBool":true,"propByte":0,"propI16":10,"propI32":100,"propI64":1000,"propDouble":1000,"propString":"BaseStruct","errorLevel":null}}}}⏎