├── .github └── workflows │ └── release_php_5_6_40.yaml ├── .gitignore ├── LICENSE ├── README.md ├── doc ├── ApiDoc.md ├── ApiDoc_ZH.md ├── HowToBuild.md └── HowToBuild_ZH.md ├── examples ├── circuitbreaker │ ├── README.md │ ├── README_ZH.md │ ├── circuitbreaker.php │ ├── image │ │ ├── create-php-consumer.png │ │ ├── create-php-provider-instance.png │ │ ├── create-php-provider-route-rule.png │ │ └── create-php-provider.png │ └── polaris.yaml ├── quickstart │ ├── README.md │ ├── README_ZH.md │ ├── consumer │ │ ├── Dockerfile │ │ ├── consumer.php │ │ └── polaris.yaml │ ├── image │ │ └── create_php_service.png │ └── provider │ │ ├── Dockerfile │ │ ├── polaris.yaml │ │ └── provider.php ├── ratelimit │ ├── README.md │ ├── README_ZH.md │ ├── image │ │ ├── create_php_service.png │ │ └── setting_ratelimit_rule.png │ ├── polaris.yaml │ └── ratelimit.php └── route │ ├── README.md │ ├── README_ZH.md │ ├── image │ ├── create-php-consumer.png │ ├── create-php-provider-instance.png │ ├── create-php-provider-route-rule.png │ └── create-php-provider.png │ ├── polaris.yaml │ └── route.php ├── include ├── polaris │ ├── accessors.h │ ├── consumer.h │ ├── context.h │ ├── defs.h │ ├── limit.h │ ├── log.h │ ├── model.h │ ├── noncopyable.h │ ├── plugin.h │ ├── polaris.h │ ├── polaris_api.h │ └── provider.h └── utils.hpp ├── polaris.class.php ├── polaris.yaml.template ├── polaris ├── .gitignore ├── CREDITS ├── EXPERIMENTAL ├── build_php74.sh ├── common.hpp ├── config.m4 ├── config.w32 ├── configure.ac ├── consumer_core.hpp ├── limit_core.hpp ├── php_polaris.h ├── polaris.cpp ├── polaris_core.hpp ├── polaris_provider.loT ├── polaris_test.php ├── provider_core.hpp └── tests │ └── 001.phpt └── sdk_class_example.php /.github/workflows/release_php_5_6_40.yaml: -------------------------------------------------------------------------------- 1 | name: Release_5_6_40 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | polaris_cpp_version: 7 | description: "tag version for polaris-cpp" 8 | required: true 9 | push: 10 | branches: [develop] 11 | pull_request: 12 | branches: [develop] 13 | 14 | jobs: 15 | laravel-tests: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: shivammathur/setup-php@15c43e89cdef867065b0213be354c2841860869e 20 | with: 21 | php-version: "5.6.40" 22 | - uses: actions/checkout@v2 23 | - name: Echo PHP Version 24 | run: php -version 25 | - name: Get Polaris-CPP 26 | env: 27 | POLARIS_CPP_VERSION: ${{ github.event.inputs.polaris_cpp_version }} 28 | run: | 29 | set -e 30 | cur_pwd=$(pwd) 31 | cd ../ 32 | git clone https://github.com/polarismesh/polaris-cpp.git 33 | cd polaris-cpp 34 | git checkout ${POLARIS_CPP_VERSION} 35 | 36 | # 构建 polaris-cpp 以及生成 polaris-cpp 对应的静态连接文件 37 | make && make package 38 | 39 | # 解压对应的文件 40 | tar -zxvf polaris_cpp_sdk.tar.gz 41 | 42 | # 拷贝 slib 目录下的文件到 polaris-php 中 43 | cd ${cur_pwd}/ 44 | mkdir -p lib/ 45 | mv ../polaris-cpp/slib/* ./lib 46 | - name: Build Polaris-PHP For 5.6.40 47 | run: | 48 | phpize --clean 49 | 50 | phpize 51 | 52 | ./configure --with-polaris 53 | 54 | make && make install 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build by php 2 | .deps 3 | *.lo 4 | *.la 5 | .libs 6 | acinclude.m4 7 | aclocal.m4 8 | autom4te.cache 9 | build 10 | config.guess 11 | config.h 12 | config.h.in 13 | config.log 14 | config.nice 15 | config.status 16 | config.sub 17 | configure 18 | configure.in 19 | install-sh 20 | libtool 21 | ltmain.sh 22 | Makefile 23 | Makefile.fragments 24 | Makefile.global 25 | Makefile.objects 26 | missing 27 | mkinstalldirs 28 | modules 29 | run-tests.php 30 | tests/*/*.diff 31 | tests/*/*.out 32 | tests/*/*.php 33 | tests/*/*.exp 34 | tests/*/*.log 35 | tests/*/*.sh 36 | 37 | # polaris-php 38 | *.a 39 | .vscode/ 40 | /php 41 | polaris.log 42 | build.sh 43 | polaris.so 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # polaris-php 2 | 3 | 4 | Polaris is an operation centre that supports multiple programming languages, with high compatibility to different application framework. Polaris-php is php SDK for Polaris. 5 | 6 | ## Overview 7 | 8 | Polaris-php provide features listed as below: 9 | 10 | * *Service instance registration, and health check* 11 | 12 | Provides API on/offline registration instance information, with regular report to inform caller server's healthy status. 13 | 14 | * *Service discovery* 15 | 16 | Provides multiple API, for users to get a full list of server instance, or get one server instance after route rule filtering and loadbalancing, which can be applied to srevice invocation soon. 17 | 18 | * *Service circuitbreaking* 19 | 20 | Provide API to report the invocation result, and conduct circuit breaker instance/group insolation based on collected data, eventually recover when the system allows. 21 | 22 | * *Service ratelimiting* 23 | 24 | Provides API for applications to conduct quota check and deduction, supports rate limit policies that are based on server level and port. 25 | 26 | ## Quick Guide 27 | 28 | ### Build Polaris-PHP 29 | 30 | You can see this document to build polaris-php: [BuildDoc](doc/HowToBuild.md) 31 | 32 | ### Using API 33 | 34 | API use guide,can reference:[ApiDoc](doc/ApiDoc.md) 35 | 36 | ### Example 37 | 38 | API quick start guide,can reference:[QuickStart](examples) 39 | -------------------------------------------------------------------------------- /doc/HowToBuild.md: -------------------------------------------------------------------------------- 1 | # How to build 2 | 3 | ## Preparation 4 | ### Build Polaris-CPP 5 | 6 | Put the `polaris-cpp` project `clone` to a directory on your local 7 | 8 | ```shell 9 | cd {One of your directories} 10 | 11 | # run git clone 12 | git clone git@github.com:polarismesh/polaris-cpp.git 13 | 14 | # run compile build 15 | 16 | make && make package 17 | ``` 18 | 19 | After executing make package, a polaris_cpp_sdk.tar.gz compressed file will be generated in the current directory. The content of the file is as follows: 20 | 21 | ``` 22 | |-- include/polaris # head File 23 | | |-- consumer.h provider.h limit.h config.h context.h log.h defs.h ... 24 | |-- dlib # Dynamic library 25 | | |-- libpolaris_api.so 26 | `-- slib # Static library 27 | |-- libpolaris_api.a libprotobuf.a 28 | ``` 29 | 30 | Unzip the file `polaris_cpp_sdk.tar.gz`, copy `libpolaris_api.a` and `libprotobuf.a` in the `slib` directory to the `lib` directory of this project (`polaris-php`) 31 | 32 | ```shell 33 | cd {One of your directories}/polaris-cpp 34 | ``` 35 | ### Build Polaris PHP 36 | 37 | Make sure that the local default `php` version is `5.6.x` or `7.4.x` 38 | 39 | ```shell 40 | cd ./polaris 41 | 42 | phpize --clean 43 | 44 | phpize 45 | 46 | ./configure --with-php-config=${php-config Full path information of the file} --with-polaris_provider 47 | 48 | make && make install 49 | ``` 50 | -------------------------------------------------------------------------------- /doc/HowToBuild_ZH.md: -------------------------------------------------------------------------------- 1 | # How to build 2 | 3 | ## 前期准备 4 | ### 构建 Polaris-CPP 5 | 6 | 将`polaris-cpp`项目`clone`到你本地的一个目录中 7 | 8 | ```shell 9 | cd {你的一个目录} 10 | # 下载 11 | git clone git@github.com:polarismesh/polaris-cpp.git 12 | 13 | # 执行编译构建 14 | 15 | make && make package 16 | ``` 17 | 18 | 执行make package后会在当前目录下生成一个polaris_cpp_sdk.tar.gz压缩文件。该文件的内容如下: 19 | 20 | ``` 21 | |-- include/polaris # 头文件 22 | | |-- consumer.h provider.h limit.h config.h context.h log.h defs.h ... 23 | |-- dlib # 动态库 24 | | |-- libpolaris_api.so 25 | `-- slib # 静态库 26 | |-- libpolaris_api.a libprotobuf.a 27 | ``` 28 | 29 | 对文件`polaris_cpp_sdk.tar.gz`进行解压,将`slib`目录下的`libpolaris_api.a`以及`libprotobuf.a`拷贝到本项目(`polaris-php`)的`lib`目录下 30 | 31 | ```shell 32 | cd {你的一个目录}/polaris-cpp 33 | ``` 34 | ### 构建 Polaris PHP 35 | 36 | 确保本地默认的`php`版本为`5.6.40`或者为`7.4.x` 37 | 38 | ```shell 39 | cd ./polaris 40 | 41 | phpize --clean 42 | 43 | phpize 44 | 45 | ./configure --with-php-config=${php-config 文件的全路径信息} --with-polaris_provider 46 | 47 | make && make install 48 | ``` 49 | -------------------------------------------------------------------------------- /examples/circuitbreaker/README.md: -------------------------------------------------------------------------------- 1 | # CircuitBreaker Example 2 | 3 | Based on a simple polaris-php usage example, demonstrate how a php application can quickly use Polaris' service CircuitBreaker. 4 | 5 | ## How to build 6 | 7 | - Build the corresponding polaris-php plugin [Build documentation](../../doc/HowToBuild.md) 8 | 9 | ## How to Use 10 | 11 | ### Create Service 12 | 13 | - Create the corresponding service through the Polaris console in advance. If it is installed through a local one-click installation package, open the console directly in the browser through 127.0.0.1:8091. 14 | - Create a service provider 15 | - ![create_provider_service](./image/create-php-provider.png) 16 | - Create service provider instance 17 | - ![create_provider_instance](./image/create-php-provider-instance.png) 18 | 19 | 20 | ### Execute program 21 | 22 | ```shell 23 | php circuitbreaker.php 24 | ``` 25 | 26 | Observe the output 27 | 28 | - Output expected value 29 | 30 | ``` 31 | array(3) { 32 | [0]=> 33 | array(19) { 34 | ["host"]=> string(9) "127.0.0.2" 35 | ["port"]=> int(8080) 36 | ... 37 | } 38 | [1]=> 39 | array(19) { 40 | ["host"]=> string(9) "127.0.0.1" 41 | ["port"]=> int(8080) 42 | ... 43 | } 44 | [2]=> 45 | array(19) { 46 | ["host"]=> string(9) "127.0.0.4" 47 | ["port"]=> int(8080) 48 | ... 49 | } 50 | } 51 | ``` -------------------------------------------------------------------------------- /examples/circuitbreaker/README_ZH.md: -------------------------------------------------------------------------------- 1 | # CircuitBreaker Example 2 | 3 | 根据简单的 polaris-php 使用示例,演示 php 应用如何快速使用北极星的服务熔断功能。 4 | 5 | ## 如何构建 6 | 7 | - 构建对应的 polaris-php 插件, [构建文档](../../doc/HowToBuild_ZH.md) 8 | 9 | ## 如何使用 10 | 11 | ### 创建服务 12 | 13 | - 预先通过北极星控制台创建对应的服务,如果是通过本地一键安装包的方式安装,直接在浏览器通过127.0.0.1:8091打开控制台。 14 | - 创建服务提供者 15 | - ![create_provider_service](./image/create-php-provider.png) 16 | - 创建服务提供这实例 17 | - ![create_provider_instance](./image/create-php-provider-instance.png) 18 | 19 | 20 | ### 执行程序 21 | 22 | ```shell 23 | php circuitbreaker.php 24 | ``` 25 | 26 | 观察输出结果 27 | 28 | - 输出期望值 29 | 30 | ``` 31 | array(3) { 32 | [0]=> 33 | array(19) { 34 | ["host"]=> string(9) "127.0.0.2" 35 | ["port"]=> int(8080) 36 | ... 37 | } 38 | [1]=> 39 | array(19) { 40 | ["host"]=> string(9) "127.0.0.1" 41 | ["port"]=> int(8080) 42 | ... 43 | } 44 | [2]=> 45 | array(19) { 46 | ["host"]=> string(9) "127.0.0.4" 47 | ["port"]=> int(8080) 48 | ... 49 | } 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /examples/circuitbreaker/circuitbreaker.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | "; 19 | 20 | if(!extension_loaded('polaris')) { 21 | dl('polaris.' . PHP_SHLIB_SUFFIX); 22 | } 23 | 24 | // 创建一个 polaris-provider 实例 25 | $polaris = new PolarisClient(array( 26 | "config_path" => "./polaris.yaml", 27 | "log_dir" => "./" 28 | )); 29 | $client_req = array( 30 | "namespace" => "default", 31 | "service" => "polaris-php-provider", 32 | ); 33 | 34 | $polaris->InitConsumer(); 35 | 36 | $res = $polaris->GetInstances($client_req, 5000, 1); 37 | var_dump($res); 38 | 39 | for ($i=1; $i<=10; $i++) 40 | { 41 | $call_service_result = array( 42 | "namespace" => "default", 43 | "service" => "polaris-php-provider", 44 | "host" => "127.0.0.3", 45 | "port" => "8080", 46 | "ret_status" => "error", 47 | ); 48 | 49 | $timeout = 500; 50 | $flow_id = 123456; 51 | $res = $polaris->UpdateServiceCallResult($call_service_result, $timeout, $flow_id); 52 | var_dump($res); 53 | sleep(1); 54 | } 55 | 56 | $res = $polaris->GetInstances($client_req, 5000, 1); 57 | $instances = $res["response"]["instances"]; 58 | var_dump($instances); 59 | ?> -------------------------------------------------------------------------------- /examples/circuitbreaker/image/create-php-consumer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/circuitbreaker/image/create-php-consumer.png -------------------------------------------------------------------------------- /examples/circuitbreaker/image/create-php-provider-instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/circuitbreaker/image/create-php-provider-instance.png -------------------------------------------------------------------------------- /examples/circuitbreaker/image/create-php-provider-route-rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/circuitbreaker/image/create-php-provider-route-rule.png -------------------------------------------------------------------------------- /examples/circuitbreaker/image/create-php-provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/circuitbreaker/image/create-php-provider.png -------------------------------------------------------------------------------- /examples/circuitbreaker/polaris.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | serverConnector: 3 | addresses: 4 | - 127.0.0.1:8091 5 | -------------------------------------------------------------------------------- /examples/quickstart/README.md: -------------------------------------------------------------------------------- 1 | # QuickStart 2 | 3 | Know a simple php socket application example, demonstrating how php application can quickly connect to Polaris. [中文文档](./README_ZH.md) 4 | 5 | ## Catalog Introduction 6 | 7 | > consumer 8 | 9 | An example of php-client, responsible for initiating socket requests. At startup, first pull a service address corresponding to php-server from Polaris and initiate a call 10 | 11 | > provider 12 | 13 | 14 | php-server example, responsible for processing socket requests. At startup, process 1 is responsible for processing 15 | socket requests, and process 2 registers the service instance and sends a heartbeat to maintain the health status of the 16 | instance 17 | 18 | ## How to build 19 | 20 | ### Build the corresponding polaris-php plugin 21 | 22 | [Build documentation](../../doc/HowToBuild.md) 23 | 24 | ### Build quickstart docker image 25 | 26 | - The polaris-php plugin for document building, [Build Document](../../doc/HowToBuild_ZH.md) 27 | - Move the polaris.so file to the directory of **consumer** and **provider** 28 | - Adjust the address of Polaris server in polaris.yaml 29 | - Mirror construction for the provider 30 | - docker build --build-arg localHost={your provider ip} 31 | ## How to use 32 | 33 | ### Create Service 34 | 35 | Create the corresponding service through the Polaris console in advance. If it is installed through a local one-click installation package, open the console directly in the browser through 127.0.0.1:8091. 36 | 37 | ![create_service](./image/create_php_service.png) 38 | 39 | ### Execute program 40 | 41 | run php-server 42 | 43 | ```shell 44 | cd provider 45 | export PHP_PROVIDER_IP={your provider ip} 46 | php provider.php 47 | ``` 48 | 49 | run php-client 50 | 51 | ```shell 52 | cd consumer 53 | php consumer.php 54 | ``` -------------------------------------------------------------------------------- /examples/quickstart/README_ZH.md: -------------------------------------------------------------------------------- 1 | # QuickStart 2 | 3 | 根据简单的 php socket 应用示例,演示 php 应用如何快速接入北极星。[English document](./README.md) 4 | 5 | ## 目录介绍 6 | 7 | > consumer 8 | 9 | php-client 端示例,负责发起 socket 请求。启动时先从北极星拉取一个对应 php-server 的服务地址并发起调用 10 | 11 | > provider 12 | 13 | php-server 端示例,负责处理 socket 请求。启动时进程1负责处理socket请求,进程2则进行服务实例的注册,并发送心跳维持 14 | 实例的健康状态 15 | 16 | ## 如何构建 17 | 18 | ### 构建对应的 polaris-php 插件 19 | 20 | [构建文档](../../doc/HowToBuild_ZH.md) 21 | 22 | ### 构建quickstart的docker镜像 23 | 24 | - 构建对应的 polaris-php 插件,[构建文档](../../doc/HowToBuild_ZH.md) 25 | - 将 polaris.so 文件移动到**consumer**以及**provider**的目录下 26 | - 调整 polaris.yaml 中北极星 server 的地址 27 | - 对于 provider 镜像的构建 28 | - docker build --build-arg localHost={your provider ip} 29 | 30 | ## 如何使用 31 | 32 | ### 创建服务 33 | 34 | 预先通过北极星控制台创建对应的服务,如果是通过本地一键安装包的方式安装,直接在浏览器通过127.0.0.1:8091打开控制台。 35 | 36 | ![create_service](./image/create_php_service.png) 37 | 38 | ### 执行程序 39 | 40 | 运行 php-server 41 | 42 | ```shell 43 | cd provider 44 | export PHP_PROVIDER_IP={your provider ip} 45 | php provider.php 46 | ``` 47 | 48 | 运行 php-client 49 | 50 | ```shell 51 | cd consumer 52 | php consumer.php 53 | ``` -------------------------------------------------------------------------------- /examples/quickstart/consumer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-cli 2 | 3 | # 确保可以编辑 polaris.yaml 4 | RUN apt-get update && apt-get install -y vim 5 | 6 | RUN docker-php-ext-install \ 7 | pcntl \ 8 | sockets 9 | 10 | COPY polaris.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/polaris.so 11 | 12 | COPY consumer.php /root/consumer.php 13 | COPY polaris.yaml /root/polaris.yaml 14 | 15 | EXPOSE 18090 16 | 17 | WORKDIR /root 18 | 19 | CMD ["php", "consumer.php"] -------------------------------------------------------------------------------- /examples/quickstart/consumer/consumer.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | "; 21 | 22 | if(!extension_loaded('polaris')) { 23 | dl('polaris.' . PHP_SHLIB_SUFFIX); 24 | } 25 | 26 | set_time_limit(0); 27 | 28 | class HttpServer 29 | { 30 | private $ip = '127.0.0.1'; 31 | private $port = 18090; 32 | 33 | private $_socket = null; 34 | // 创建一个 polaris-client 实例 35 | private $polaris = null; 36 | 37 | public function __construct() 38 | { 39 | $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 40 | if ($this->_socket === false) { 41 | die(socket_strerror(socket_last_error($this->_socket))); 42 | } 43 | $this->$polaris = new PolarisClient(array( 44 | "config_path" => "./polaris.yaml", 45 | "log_dir" => "./" 46 | )); 47 | $this->$polaris->InitConsumer(); 48 | 49 | } 50 | 51 | public function run() 52 | { 53 | socket_bind($this->_socket, '0.0.0.0', $this->port); 54 | socket_listen($this->_socket, 16); 55 | while(true) { 56 | $socketAccept = socket_accept($this->_socket); 57 | $request = socket_read($socketAccept, 1024); 58 | echo $request; 59 | socket_write($socketAccept, 'HTTP/1.1 200 OK'.PHP_EOL); 60 | socket_write($socketAccept, 'Date:'.date('Y-m-d H:i:s').PHP_EOL); 61 | 62 | $fileName = $this->getUri($request); 63 | 64 | $get_req = array( 65 | "namespace" => "default", 66 | "service" => "EchoServerPHP", 67 | ); 68 | $res = $this->$polaris->GetOneInstance($get_req, 5000, 1); 69 | $instances = $res["response"]["instances"]; 70 | $address = $instances[0]['host']; 71 | $service_port = (int)$instances[0]["port"]; 72 | 73 | // 创建并返回一个套接字(通讯节点) 74 | $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 75 | if ($socket === false) { 76 | echo "socket_create() failed, reason: ".socket_strerror(socket_last_error())."\n"; 77 | } 78 | 79 | echo "Attempting to connect to '$address' on port '$service_port'..."; 80 | // 发起socket连接请求 81 | $result = socket_connect($socket, $address, $service_port); 82 | if($result === false) { 83 | echo "socket_connect() failed, reason: ".socket_strerror(socket_last_error($socket))."\n"; 84 | exit(1); 85 | } else { 86 | echo "Connect success. \n"; 87 | } 88 | $input = "This is a message from client"."\n"; 89 | 90 | // 向socket服务器发送消息 91 | socket_write($socket, $input, strlen($input)); 92 | echo "Client send success \n"; 93 | echo "Reading response:\n"; 94 | 95 | //set content type 96 | socket_write($socketAccept, 'Content-Type: text/html'.PHP_EOL); 97 | socket_write($socketAccept, ''.PHP_EOL); 98 | // 读取socket服务器发送的消息 99 | while ($out = socket_read($socket, 8192)) {\ 100 | socket_write($socketAccept, $out, strlen($out)); 101 | echo $out; 102 | } 103 | socket_close($socket); // 关闭socket连接 104 | socket_close($socketAccept); 105 | 106 | } 107 | 108 | } 109 | 110 | protected function getUri($request = '') 111 | { 112 | $arrayRequest = explode(PHP_EOL, $request); 113 | $line = $arrayRequest[0]; 114 | $file = trim(preg_replace('/(\w+)\s\/(.*)\sHTTP\/1.1/i','$2', $line)); 115 | return $file; 116 | } 117 | 118 | 119 | public function close() 120 | { 121 | socket_close($this->_socket); 122 | } 123 | 124 | } 125 | $httpServer = new HttpServer(); 126 | 127 | echo "run http-server"; 128 | $httpServer->run(); 129 | 130 | ?> -------------------------------------------------------------------------------- /examples/quickstart/consumer/polaris.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | serverConnector: 3 | addresses: 4 | - 127.0.0.1:8091 5 | -------------------------------------------------------------------------------- /examples/quickstart/image/create_php_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/quickstart/image/create_php_service.png -------------------------------------------------------------------------------- /examples/quickstart/provider/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-cli 2 | 3 | # 确保可以编辑 polaris.yaml 4 | RUN apt-get update && apt-get install -y vim 5 | 6 | RUN docker-php-ext-install \ 7 | pcntl \ 8 | sockets 9 | 10 | COPY polaris.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/polaris.so 11 | 12 | COPY provider.php /root/provider.php 13 | COPY polaris.yaml /root/polaris.yaml 14 | 15 | # 本机 IP 信息 16 | ARG localHost=127.0.0.1 17 | 18 | ENV PHP_PROVIDER_IP=$localHost 19 | 20 | EXPOSE 9996 21 | 22 | WORKDIR /root 23 | 24 | CMD ["php", "provider.php"] -------------------------------------------------------------------------------- /examples/quickstart/provider/polaris.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | serverConnector: 3 | addresses: 4 | - 127.0.0.1:8091 5 | -------------------------------------------------------------------------------- /examples/quickstart/provider/provider.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | _socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 40 | if ($this->_socket === false) { 41 | die(socket_strerror(socket_last_error($this->_socket))); 42 | } 43 | } 44 | 45 | public function run() 46 | { 47 | $bind_ok = socket_bind($this->_socket, '0.0.0.0', $this->port); 48 | 49 | if ($bind_ok === false) { 50 | echo "socket_bind() failed, reason: ".socket_strerror(socket_last_error())."\n"; 51 | } else { 52 | echo "socket_bind() success"; 53 | } 54 | 55 | socket_listen($this->_socket, 5); 56 | while(true) { 57 | $socketAccept = socket_accept($this->_socket); 58 | $request = socket_read($socketAccept, 1024); 59 | echo "receive from client '$request'"; 60 | socket_write($socketAccept, 'hello. I`m provider', strlen('hello. I`m provider')); 61 | socket_close($socketAccept); 62 | } 63 | } 64 | 65 | public function close() 66 | { 67 | socket_close($this->_socket); 68 | } 69 | } 70 | 71 | 72 | $pid = pcntl_fork(); 73 | if ( $pid == 0 ) { 74 | $self_ip = getenv('PHP_PROVIDER_IP'); 75 | var_dump($self_ip); 76 | 77 | // 创建一个 polaris-provider 实例 78 | $polaris = new PolarisClient(array( 79 | "config_path" => "./polaris.yaml", 80 | "log_dir" => "./" 81 | )); 82 | 83 | $polaris->InitProvider(); 84 | 85 | // 实例注册信息 86 | $register_instance_info = array( 87 | "namespace" => "default", 88 | "service" => "EchoServerPHP", 89 | "host" => $self_ip, 90 | "port" => "9996", 91 | "heartbeat" => "true", 92 | "protocol" => "TCP", 93 | "vpc_id" => "", 94 | "weight" => "88", 95 | "ttl" => "5", 96 | "metadata" => array( 97 | "client" => "php" 98 | ) 99 | ); 100 | 101 | // 执行实例注册动作 102 | $res = $polaris->Register($register_instance_info, 5000, 1); 103 | var_dump($res); 104 | if ( $res['code'] != '0') { 105 | $err_msg = $res["err_msg"]; 106 | echo "register instance fail '$err_msg'"; 107 | } 108 | 109 | // 实例心跳信息 110 | $heartbeat_info = array( 111 | "namespace" => "default", 112 | "service" => "EchoServerPHP", 113 | "host" => $self_ip, 114 | "port" => "9996", 115 | ); 116 | while (true) { 117 | // 先进行一次心跳上报,触发实例租约计算任务 118 | $res = $polaris->Heartbeat($heartbeat_info); 119 | sleep(4); 120 | var_dump($res); 121 | } 122 | } else { 123 | echo "run tpc server\n"; 124 | $tcp_server = new TCPServer(); 125 | $tcp_server->run(); 126 | } 127 | ?> -------------------------------------------------------------------------------- /examples/ratelimit/README.md: -------------------------------------------------------------------------------- 1 | # RateLimit Example 2 | 3 | Based on a simple polaris-php usage example, demonstrate how a php application can quickly use Polaris' service RateLimit. 4 | 5 | ## How to build 6 | 7 | - Build the corresponding polaris-php plugin [Build documentation](../../doc/HowToBuild.md) 8 | 9 | ## How to Use 10 | 11 | ### Create Service 12 | 13 | - Create the corresponding service through the Polaris console in advance. If it is installed through a local one-click installation package, open the console directly in the browser through 127.0.0.1:8091. 14 | - ![create_service](./image/create_php_service.png) 15 | - Configure the current limiting parameters of the service 16 | - ![setting_ratelimit](./image/setting_ratelimit_rule.png) 17 | 18 | 19 | ### Execute program 20 | 21 | ```shell 22 | php ratelimit.php 23 | ``` 24 | 25 | Observe the output 26 | 27 | - Output expected value for the first time 28 | 29 | ``` 30 | array(3) { 31 | ["code"]=> int(0) 32 | ["err_msg"]=> string(9) "0-success" 33 | ["quota_result"]=> array(6) { 34 | ["quota_result_code"]=> int(0) // Quota is normal 35 | ["quota_duration"]=> int(1000) 36 | ["quota_left"]=> int(0) 37 | ["quota_all"]=> int(1) 38 | ["degrade"]=> bool(false) 39 | ["wait_time"]=> int(0) 40 | } 41 | } 42 | ``` 43 | 44 | - Output expected value for the second time 45 | 46 | ``` 47 | array(3) { 48 | ["code"]=> int(0) 49 | ["err_msg"]=> string(9) "0-success" 50 | ["quota_result"]=> array(6) { 51 | ["quota_result_code"]=> int(1) // Quota is restricted 52 | ["quota_duration"]=> int(1000) 53 | ["quota_left"]=> int(0) 54 | ["quota_all"]=> int(1) 55 | ["degrade"]=> bool(false) 56 | ["wait_time"]=> int(0) 57 | } 58 | } 59 | ``` -------------------------------------------------------------------------------- /examples/ratelimit/README_ZH.md: -------------------------------------------------------------------------------- 1 | # RateLimit Example 2 | 3 | 根据简单的 polaris-php 使用示例,演示 php 应用如何快速使用北极星的服务限流功能。 4 | 5 | ## 如何构建 6 | 7 | - 构建对应的 polaris-php 插件, [构建文档](../../doc/HowToBuild.md) 8 | 9 | ## 如何使用 10 | 11 | ### 创建服务 12 | 13 | - 预先通过北极星控制台创建对应的服务,如果是通过本地一键安装包的方式安装,直接在浏览器通过127.0.0.1:8091打开控制台。 14 | - ![create_service](./image/create_php_service.png) 15 | - 配置该服务的限流参数 16 | - ![setting_ratelimit](./image/setting_ratelimit_rule.png) 17 | 18 | 19 | ### 执行程序 20 | 21 | ```shell 22 | php ratelimit.php 23 | ``` 24 | 25 | 观察输出结果 26 | 27 | - 第一次输出期望值 28 | 29 | ``` 30 | array(3) { 31 | ["code"]=> int(0) 32 | ["err_msg"]=> string(9) "0-success" 33 | ["quota_result"]=> array(6) { 34 | ["quota_result_code"]=> int(0) // 配额正常 35 | ["quota_duration"]=> int(1000) 36 | ["quota_left"]=> int(0) 37 | ["quota_all"]=> int(1) 38 | ["degrade"]=> bool(false) 39 | ["wait_time"]=> int(0) 40 | } 41 | } 42 | ``` 43 | 44 | - 第二次输出期望值 45 | 46 | ``` 47 | array(3) { 48 | ["code"]=> int(0) 49 | ["err_msg"]=> string(9) "0-success" 50 | ["quota_result"]=> array(6) { 51 | ["quota_result_code"]=> int(1) // 配额被限流 52 | ["quota_duration"]=> int(1000) 53 | ["quota_left"]=> int(0) 54 | ["quota_all"]=> int(1) 55 | ["degrade"]=> bool(false) 56 | ["wait_time"]=> int(0) 57 | } 58 | } 59 | ``` -------------------------------------------------------------------------------- /examples/ratelimit/image/create_php_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/ratelimit/image/create_php_service.png -------------------------------------------------------------------------------- /examples/ratelimit/image/setting_ratelimit_rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/ratelimit/image/setting_ratelimit_rule.png -------------------------------------------------------------------------------- /examples/ratelimit/polaris.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | serverConnector: 3 | addresses: 4 | - 127.0.0.1:8091 5 | -------------------------------------------------------------------------------- /examples/ratelimit/ratelimit.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | "; 18 | 19 | if(!extension_loaded('polaris')) { 20 | dl('polaris.' . PHP_SHLIB_SUFFIX); 21 | } 22 | 23 | // 创建一个 polaris-provider 实例 24 | $polaris = new PolarisClient(array( 25 | "config_path" => "./polaris.yaml", 26 | "log_dir" => "./" 27 | )); 28 | 29 | $polaris->InitLimit(); 30 | 31 | $client_req = array( 32 | "namespace" => "default", 33 | "service" => "polaris_php_test", 34 | "labels" => array( 35 | "env" => "pre", 36 | "method" => "GetUserInfo" 37 | ), 38 | ); 39 | 40 | // FetchRuleLabelKeys 41 | $res = $polaris->GetQuota($client_req); 42 | var_dump($res); 43 | 44 | $res = $polaris->GetQuota($client_req); 45 | var_dump($res); 46 | ?> -------------------------------------------------------------------------------- /examples/route/README.md: -------------------------------------------------------------------------------- 1 | # Route Example 2 | 3 | Based on a simple polaris-php usage example, demonstrate how a php application can quickly use the service routing function of Polaris. 4 | 5 | ## How To Build 6 | 7 | - Build the corresponding polaris-php plugin [Build documentation](../../doc/HowToBuild.md) 8 | 9 | ## How To Use 10 | 11 | ### 创建服务 12 | 13 | - Create the corresponding service through the Polaris console in advance. If it is installed through a local one-click installation package, open the console directly in the browser through 127.0.0.1:8080 14 | - Create a service provider 15 | - ![create_provider_service](./image/create-php-provider.png) 16 | - Create service provider instance 17 | - ![create_provider_instance](./image/create-php-provider-instance.png) 18 | - Create service consumers 19 | - ![create_provider_service](./image/create-php-consumer.png) 20 | - Configure routing rules for service providers 21 | - Set up the service being called rules 22 | - ![setting_ratelimit](./image/create-php-provider-route-rule.png) 23 | 24 | 25 | ### Execute program 26 | 27 | ```shell 28 | php route.php 29 | ``` 30 | 31 | Observe the output 32 | 33 | - Output expected value 34 | 35 | ``` 36 | array(1) { 37 | [0]=> 38 | array(19) { 39 | ["host"]=> string(9) "127.0.0.4" 40 | ["container_name"]=> string(0) "" 41 | ["internal_set_name"]=> string(0) "" 42 | ["logic_set"]=> string(0) "" 43 | ["region"]=> string(0) "" 44 | ["zone"]=> string(0) "" 45 | ["campus"]=> string(0) "" 46 | ["vpc_id"]=> string(0) "" 47 | ["protocol"]=> string(0) "" 48 | ["version"]=> string(0) "" 49 | ["port"]=> int(8080) 50 | ["weight"]=> int(100) 51 | ["priority"]=> int(0) 52 | ["dynamic_weight"]=> int(100) 53 | ["hash_key"]=> int(2926897704236617270) 54 | ["locality_aware_info"]=> int(0) 55 | ["healthy"]=> ool(true) 56 | ["isolate"]=> bool(false) 57 | ["metadata"]=> array(3) { 58 | ["env"]=> string(3) "pre" 59 | ["protocol"]=> string(0) "" 60 | ["version"]=> string(0) "" 61 | } 62 | } 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /examples/route/README_ZH.md: -------------------------------------------------------------------------------- 1 | # Route Example 2 | 3 | 根据简单的 polaris-php 使用示例,演示 php 应用如何快速使用北极星的服务路由功能。 4 | 5 | ## 如何构建 6 | 7 | - 构建对应的 polaris-php 插件, [构建文档](../../doc/HowToBuild_ZH.md) 8 | 9 | ## 如何使用 10 | 11 | ### 创建服务 12 | 13 | - 预先通过北极星控制台创建对应的服务,如果是通过本地一键安装包的方式安装,直接在浏览器通过127.0.0.1:8091打开控制台。 14 | - 创建服务提供者 15 | - ![create_provider_service](./image/create-php-provider.png) 16 | - 创建服务提供这实例 17 | - ![create_provider_instance](./image/create-php-provider-instance.png) 18 | - 创建服务消费者 19 | - ![create_provider_service](./image/create-php-consumer.png) 20 | - 配置服务提供者的路由规则 21 | - 设置服务的被调规则 22 | - ![setting_ratelimit](./image/create-php-provider-route-rule.png) 23 | 24 | 25 | ### 执行程序 26 | 27 | ```shell 28 | php route.php 29 | ``` 30 | 31 | 观察输出结果 32 | 33 | - 输出期望值 34 | 35 | ``` 36 | array(1) { 37 | [0]=> 38 | array(19) { 39 | ["host"]=> string(9) "127.0.0.4" 40 | ["container_name"]=> string(0) "" 41 | ["internal_set_name"]=> string(0) "" 42 | ["logic_set"]=> string(0) "" 43 | ["region"]=> string(0) "" 44 | ["zone"]=> string(0) "" 45 | ["campus"]=> string(0) "" 46 | ["vpc_id"]=> string(0) "" 47 | ["protocol"]=> string(0) "" 48 | ["version"]=> string(0) "" 49 | ["port"]=> int(8080) 50 | ["weight"]=> int(100) 51 | ["priority"]=> int(0) 52 | ["dynamic_weight"]=> int(100) 53 | ["hash_key"]=> int(2926897704236617270) 54 | ["locality_aware_info"]=> int(0) 55 | ["healthy"]=> ool(true) 56 | ["isolate"]=> bool(false) 57 | ["metadata"]=> array(3) { 58 | ["env"]=> string(3) "pre" 59 | ["protocol"]=> string(0) "" 60 | ["version"]=> string(0) "" 61 | } 62 | } 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /examples/route/image/create-php-consumer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/route/image/create-php-consumer.png -------------------------------------------------------------------------------- /examples/route/image/create-php-provider-instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/route/image/create-php-provider-instance.png -------------------------------------------------------------------------------- /examples/route/image/create-php-provider-route-rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/route/image/create-php-provider-route-rule.png -------------------------------------------------------------------------------- /examples/route/image/create-php-provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/examples/route/image/create-php-provider.png -------------------------------------------------------------------------------- /examples/route/polaris.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | serverConnector: 3 | addresses: 4 | - 127.0.0.1:8091 -------------------------------------------------------------------------------- /examples/route/route.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | "; 18 | 19 | if(!extension_loaded('polaris')) { 20 | dl('polaris.' . PHP_SHLIB_SUFFIX); 21 | } 22 | 23 | // 创建一个 polaris-provider 实例 24 | $polaris = new PolarisClient(array( 25 | "config_path" => "./polaris.yaml", 26 | "log_dir" => "./" 27 | )); 28 | 29 | $polaris->InitConsumer(); 30 | 31 | $client_req = array( 32 | "namespace" => "default", 33 | "service" => "polaris-php-provider", 34 | "source_service" => array( 35 | "metadata" => array( 36 | "env" => "prod", 37 | ), 38 | ) 39 | ); 40 | 41 | $res = $polaris->GetOneInstance($client_req, 5000, 1); 42 | $instances = $res["response"]["instances"]; 43 | var_dump($instances); 44 | ?> -------------------------------------------------------------------------------- /include/polaris/accessors.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | /// @file accessors.h 15 | /// @brief 定义接口请求和应答对象的属性存取器,用于插件实现 16 | /// 17 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_ACCESSORS_H_ 18 | #define POLARIS_CPP_INCLUDE_POLARIS_ACCESSORS_H_ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include "defs.h" 26 | 27 | namespace polaris 28 | { 29 | 30 | class GetOneInstanceRequest; 31 | class GetOneInstanceRequestImpl; 32 | 33 | class GetOneInstanceRequestAccessor 34 | { 35 | public: 36 | explicit GetOneInstanceRequestAccessor(const GetOneInstanceRequest &request) 37 | : request_(request) {} 38 | 39 | const ServiceKey &GetServiceKey(); 40 | 41 | const Criteria &GetCriteria(); 42 | 43 | bool HasSourceService(); 44 | ServiceInfo *GetSourceService(); 45 | ServiceInfo *DumpSourceService(); 46 | 47 | bool HasFlowId(); 48 | uint64_t GetFlowId(); 49 | void SetFlowId(uint64_t flow_id); 50 | 51 | bool HasTimeout(); 52 | uint64_t GetTimeout(); 53 | void SetTimeout(uint64_t timeout); 54 | 55 | GetOneInstanceRequest *Dump(); 56 | 57 | const std::map &GetLabels() const; 58 | 59 | MetadataRouterParam *GetMetadataParam() const; 60 | 61 | LoadBalanceType GetLoadBalanceType(); 62 | 63 | uint32_t GetBackupInstanceNum(); 64 | 65 | private: 66 | const GetOneInstanceRequest &request_; 67 | }; 68 | 69 | class GetInstancesRequest; 70 | class GetInstancesRequestImpl; 71 | 72 | class GetInstancesRequestAccessor 73 | { 74 | public: 75 | explicit GetInstancesRequestAccessor(const GetInstancesRequest &request) : request_(request) {} 76 | 77 | const ServiceKey &GetServiceKey(); 78 | 79 | bool HasSourceService(); 80 | ServiceInfo *GetSourceService(); 81 | ServiceInfo *DumpSourceService(); 82 | 83 | bool GetIncludeCircuitBreakerInstances(); 84 | 85 | bool GetIncludeUnhealthyInstances(); 86 | 87 | bool GetSkipRouteFilter(); 88 | 89 | bool HasFlowId(); 90 | uint64_t GetFlowId(); 91 | void SetFlowId(uint64_t flow_id); 92 | 93 | bool HasTimeout(); 94 | uint64_t GetTimeout(); 95 | void SetTimeout(uint64_t timeout); 96 | 97 | MetadataRouterParam *GetMetadataParam() const; 98 | 99 | GetInstancesRequest *Dump(); 100 | 101 | private: 102 | const GetInstancesRequest &request_; 103 | }; 104 | 105 | class ServiceCallResult; 106 | class ServiceCallResultImpl; 107 | 108 | class ServiceCallResultGetter 109 | { 110 | public: 111 | explicit ServiceCallResultGetter(const ServiceCallResult &result) : result_(result) {} 112 | 113 | const std::string &GetServiceName(); 114 | 115 | const std::string &GetServiceNamespace(); 116 | 117 | const std::string &GetInstanceId(); 118 | 119 | const std::string &GetHost(); 120 | 121 | int GetPort(); 122 | 123 | CallRetStatus GetRetStatus(); 124 | 125 | const ServiceKey &GetSource(); 126 | 127 | const std::map &GetSubset(); 128 | 129 | const std::map &GetLabels(); 130 | 131 | int GetRetCode(); 132 | 133 | uint64_t GetDelay(); 134 | 135 | uint64_t GetLocalityAwareInfo(); 136 | 137 | private: 138 | const ServiceCallResult &result_; 139 | }; 140 | 141 | class Instance; 142 | class InstanceLocalValue; 143 | class InstanceSetter 144 | { 145 | public: 146 | explicit InstanceSetter(Instance &instance) : instance_(instance) {} 147 | 148 | void SetVpcId(const std::string &vpc_id); 149 | 150 | void SetProtocol(const std::string &protocol); 151 | 152 | void SetVersion(const std::string &version); 153 | 154 | void SetPriority(int priority); 155 | 156 | void SetHealthy(bool healthy); 157 | 158 | void SetIsolate(bool isolate); 159 | 160 | void AddMetadataItem(const std::string &key, const std::string &value); 161 | 162 | void SetLogicSet(const std::string &logic_set); 163 | 164 | void SetDynamicWeight(uint32_t dynamic_weight); 165 | 166 | void SetRegion(const std::string ®ion); 167 | 168 | void SetZone(const std::string &zone); 169 | 170 | void SetCampus(const std::string &campus); 171 | 172 | void SetHashValue(uint64_t hashVal); 173 | 174 | void SetLocalId(uint64_t local_id); 175 | 176 | void SetLocalValue(InstanceLocalValue *localValue); 177 | 178 | void CopyLocalValue(const InstanceSetter &setter); 179 | 180 | void SetLocalityAwareInfo(uint64_t locality_aware_info); 181 | 182 | private: 183 | Instance &instance_; 184 | }; 185 | 186 | class InstancesResponse; 187 | class InstancesResponseImpl; 188 | class InstancesResponseSetter 189 | { 190 | public: 191 | explicit InstancesResponseSetter(InstancesResponse &response) : response_(response) {} 192 | 193 | void SetFlowId(const uint64_t flow_id); 194 | 195 | void SetServiceName(const std::string &service_name); 196 | 197 | void SetServiceNamespace(const std::string &service_namespace); 198 | 199 | void SetMetadata(const std::map &metadata); 200 | 201 | void SetWeightType(WeightType weight_type); 202 | 203 | void SetRevision(const std::string &revision); 204 | 205 | void AddInstance(const Instance &instance); 206 | 207 | void SetSubset(const std::map &subset); 208 | 209 | private: 210 | InstancesResponse &response_; 211 | }; 212 | 213 | } // namespace polaris 214 | 215 | #endif // POLARIS_CPP_INCLUDE_POLARIS_ACCESSORS_H_ 216 | -------------------------------------------------------------------------------- /include/polaris/consumer.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_CONSUMER_H_ 15 | #define POLARIS_CPP_INCLUDE_POLARIS_CONSUMER_H_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "context.h" 22 | #include "defs.h" 23 | #include "noncopyable.h" 24 | 25 | namespace polaris 26 | { 27 | 28 | class GetOneInstanceRequestImpl; 29 | 30 | /// @brief 获取单个服务实例请求 31 | class GetOneInstanceRequest : Noncopyable 32 | { 33 | public: 34 | /// @brief 构建获取单个服务实例请求对象 35 | /// 36 | /// @param service_key 命名空间和服务名 37 | explicit GetOneInstanceRequest(const ServiceKey &service_key); 38 | 39 | /// @brief 析构获取单个服务实例请求对象 40 | ~GetOneInstanceRequest(); 41 | 42 | /// @brief 设置hash key,用于一致性哈希负载均衡算法选择服务实例。其他负载均衡算法不用设置 43 | void SetHashKey(uint64_t hash_key); 44 | 45 | /// @brief 设置 hash 字符串, sdk 会用 hash_string 算出一个 uint64_t 46 | /// 的哈希值用于一致性哈希负载均衡算法选择服务实例。其他负载均衡算法不用设置 47 | void SetHashString(const std::string &hash_string); 48 | 49 | /// @brief 设置是否略过跳过半开探测节点 50 | /// @note 只在重试业务时设置为true。如果一直设置为true,则熔断节点在网络探测成功后也一直无法恢复 51 | void SetIgnoreHalfOpen(bool ignore_half_open); 52 | 53 | /// @brief 设置源服务信息,用于服务路由计算。可选 54 | /// 55 | /// @param source_service 源服务信息,包括源服务命名空间和用于过滤的metadata 56 | void SetSourceService(const ServiceInfo &source_service); 57 | 58 | /// @brief 设置调用哪个set下的服务 59 | /// 60 | /// @param set_name 主调指定的被调服务的set名 61 | bool SetSourceSetName(const std::string &set_name); 62 | 63 | /// @brief 设置调用哪个金丝雀服务实例 64 | /// 65 | /// @param canary 主调指定的金丝雀 66 | void SetCanary(const std::string &canary); 67 | 68 | /// @brief 设置请求流水号。可选,默认随机流水号 69 | /// 70 | /// @param flow_id 用于跟踪请求的流水号 71 | void SetFlowId(uint64_t flow_id); 72 | 73 | /// @brief 设置请求超时时间。可选,默认为全局配置的API超时时间 74 | /// 75 | /// @param timeout 设置请求超时时间,可选,单位ms 76 | void SetTimeout(uint64_t timeout); 77 | 78 | /// @brief 设置请求标签,用于接口级别熔断 79 | /// 80 | /// @param labels 请求标签 81 | void SetLabels(const std::map &labels); 82 | 83 | /// @brief 设置元数据,用于元数据路由 84 | /// 85 | /// @param metadata 元数据 86 | void SetMetadata(std::map &metadata); 87 | 88 | /// @brief 设置元数据路由匹配失败时的降级策略,默认不降级 89 | /// 90 | /// @param metadata_failover_type 元数据路由降级策略 91 | void SetMetadataFailover(MetadataFailoverType metadata_failover_type); 92 | 93 | /// @brief 设置负载均衡类型。可选,默认使用配置文件中设置的类型 94 | /// 95 | /// @param load_balance_type 负载均衡类型 96 | void SetLoadBalanceType(LoadBalanceType load_balance_type); 97 | 98 | /// @brief 设置用于重试的实例数。可选,默认不返回用于重试的实例 99 | /// 100 | /// @note 第一个实例由负载均衡器给出,外加backup_instance_num个实例,实例不重复,但不保证数量 101 | /// 内部的一致性环hash负载均衡返回实例后方相邻的实例,其他返回随机实例 102 | /// 从GetOneInstance的InstancesResponse获取实例 103 | /// 104 | /// @param backup_instance_num 重试(备份)实例数 105 | void SetBackupInstanceNum(uint32_t backup_instance_num); 106 | 107 | /// @brief 用于一致性hash算法时获取副本实例 108 | /// 109 | /// @param replicate_index 副本索引,默认为0表示当前hash实例本身 110 | /// 大于0表示从hash实例后面的第几个副本 111 | void SetReplicateIndex(int replicate_index); 112 | 113 | private: 114 | friend class GetOneInstanceRequestAccessor; 115 | GetOneInstanceRequestImpl *impl; 116 | }; 117 | 118 | class GetInstancesRequestImpl; 119 | 120 | /// @brief 获取批量服务实例请求 121 | class GetInstancesRequest : Noncopyable 122 | { 123 | public: 124 | /// @brief 构造获取批量服务实例请求 125 | /// 126 | /// @param service_key 命名空间和服务名 127 | explicit GetInstancesRequest(const ServiceKey &service_key); 128 | 129 | /// @brief 析构获取批量服务实例请求 130 | ~GetInstancesRequest(); 131 | 132 | /// @brief 设置服务路由时否包含不健康的服务实例。可选,默认不包含 133 | /// 134 | /// @note 即使设置不包含的情况下仍然可能降级返回不健康实例 135 | /// @param include_unhealthy_instances 是否包含不健康服务实例 136 | void SetIncludeUnhealthyInstances(bool include_unhealthy_instances); 137 | 138 | /// @brief 设置服务路由时是否包含熔断的服务实例。可选,默认不包含。 139 | /// 140 | /// @note 即使设置不包含的情况下仍然可能降级返回熔断实例 141 | /// @param include_circuit_breaker_instances 是否包含熔断实例 142 | void SetIncludeCircuitBreakInstances(bool include_circuit_breaker_instances); 143 | 144 | /// @brief 设置是否跳过服务路由。可选,默认不跳过服务路由 145 | /// 146 | /// @param skip_route_filter 是否跳过服务路由 147 | void SetSkipRouteFilter(bool skip_route_filter); 148 | 149 | /// @brief 设置源服务信息,用于服务路由计算。可选 150 | /// 151 | /// @param source_service 源服务信息,包括源服务命名空间和用于过滤的metadata 152 | void SetSourceService(const ServiceInfo &source_service); 153 | 154 | /// @brief 设置调用哪个set下的服务 155 | /// 156 | /// @param set_name 主调指定的被调服务的set名 157 | bool SetSourceSetName(const std::string &set_name); 158 | 159 | /// @brief 设置调用哪个金丝雀服务实例 160 | /// 161 | /// @param canary 主调指定的金丝雀 162 | void SetCanary(const std::string &canary); 163 | 164 | /// @brief 设置元数据,用于元数据路由 165 | /// 166 | /// @param metadata 元数据 167 | void SetMetadata(std::map &metadata); 168 | 169 | /// @brief 设置元数据路由匹配失败时的降级策略,默认不降级 170 | /// 171 | /// @param metadata_failover_type 元数据路由降级策略 172 | void SetMetadataFailover(MetadataFailoverType metadata_failover_type); 173 | 174 | /// @brief 设置请求流水号。可选,默认随机流水号 175 | /// 176 | /// @param flow_id 用于跟踪请求的流水号 177 | void SetFlowId(uint64_t flow_id); 178 | 179 | /// @brief 设置请求超时时间。可选,默认为全局配置的API超时时间 180 | /// 181 | /// @param timeout 设置请求超时时间,可选,单位ms 182 | void SetTimeout(uint64_t timeout); 183 | 184 | private: 185 | friend class GetInstancesRequestAccessor; 186 | GetInstancesRequestImpl *impl; 187 | }; 188 | 189 | class ServiceCallResultImpl; 190 | 191 | /// @brief 服务实例调用结果上报 192 | class ServiceCallResult : Noncopyable 193 | { 194 | public: 195 | /// @brief 构造服务实例调用结果上报对象 196 | ServiceCallResult(); 197 | 198 | /// @brief 析构服务实例调用结果上报对象 199 | ~ServiceCallResult(); 200 | 201 | /// @brief 设置服务实例的服务名 202 | /// 203 | /// @param service_name 服务名 204 | void SetServiceName(const std::string &service_name); 205 | 206 | /// @brief 设置服务实例的命名空间 207 | /// 208 | /// @param service_namespace 命名空间 209 | void SetServiceNamespace(const std::string &service_namespace); 210 | 211 | /// @brief 设置服务实例ID 212 | /// 213 | /// @param instance_id 服务实例ID 214 | void SetInstanceId(const std::string &instance_id); 215 | 216 | /// @brief 设置服务实例Host和Port,可选,如果设置了服务实例ID,则这个可不设置,优先使用服务实例ID 217 | /// 218 | /// @param host 服务实例Host 219 | /// @param port 服务实例Port 220 | void SetInstanceHostAndPort(const std::string &host, int port); 221 | 222 | /// @brief 设置调用返回状态码 223 | /// 224 | /// @param ret_status 调用返回状态码 225 | void SetRetStatus(CallRetStatus ret_status); 226 | 227 | /// @brief 设置调用返回码。可选,用于支持根据返回码实现自己的插件 228 | /// 229 | /// @param ret_code 230 | void SetRetCode(int ret_code); 231 | 232 | /// @brief 设置服务实例调用时延 233 | /// 234 | /// @param delay 调用时延 235 | void SetDelay(uint64_t delay); 236 | 237 | /// @brief 设置主调服务ServiceKey 238 | /// 239 | /// @param ServiceKey 主调服务ServiceKey 240 | void SetSource(ServiceKey &source); 241 | 242 | /// @brief 设置被调服务subset信息 243 | /// 244 | /// @param subset subset信息 245 | void SetSubset(const std::map &subset); 246 | 247 | /// @brief 设置被调服务labels信息 248 | /// 249 | /// @param labels labels信息 250 | void SetLabels(const std::map &labels); 251 | 252 | /// @brief 设置需要传递的LocalityAware的信息 253 | /// 254 | /// @param locality_aware_info LocalityAware的信息 255 | void SetLocalityAwareInfo(uint64_t locality_aware_info); 256 | 257 | private: 258 | friend class ServiceCallResultGetter; 259 | ServiceCallResultImpl *impl; 260 | }; 261 | 262 | class InstancesResponseImpl; 263 | 264 | /// @brief 服务实例查询应答 265 | class InstancesResponse : Noncopyable 266 | { 267 | public: 268 | /// @brief 构造服务实例查询应答对象 269 | InstancesResponse(); 270 | 271 | /// @brief 析构服务实例查询应答对象 272 | ~InstancesResponse(); 273 | 274 | /// @brief 获取应答对应请求流水号 275 | /// 276 | /// @return uint64_t 请求流水号 277 | uint64_t GetFlowId(); 278 | 279 | /// @brief 获取服务名 280 | /// 281 | /// @return std::string& 服务名 282 | std::string &GetServiceName(); 283 | 284 | /// @brief 获取命名空间 285 | /// 286 | /// @return std::string& 命名空间 287 | std::string &GetServiceNamespace(); 288 | 289 | /// @brief 获取服务元数据 290 | /// 291 | /// @return std::map& 服务元数据 292 | std::map &GetMetadata(); 293 | 294 | /// @brief 获取权重类型 295 | /// 296 | /// @return WeightType 权重类型 297 | WeightType GetWeightType(); 298 | 299 | /// @brief 获取服务版本信息 300 | /// 301 | /// @return std::string& 版本信息 302 | std::string &GetRevision(); 303 | 304 | /// @brief 获取服务实例列表 305 | /// 306 | /// @return std::vector& 服务实例列表 307 | std::vector &GetInstances(); 308 | 309 | /// @brief 获取subset信息 310 | /// 311 | /// @return const std::map& 实例所属的subset 312 | const std::map &GetSubset(); 313 | 314 | private: 315 | friend class InstancesResponseSetter; 316 | InstancesResponseImpl *impl; 317 | }; 318 | 319 | class InstancesFutureImpl; 320 | 321 | /// @brief 服务数据就绪通知对象接口 322 | class ServiceCacheNotify 323 | { 324 | public: 325 | virtual ~ServiceCacheNotify() {} 326 | 327 | /// @brief 等待的服务数据准备就绪时执行 328 | virtual void NotifyReady() = 0; 329 | 330 | /// @brief 等待的服务数据超时时执行 331 | virtual void NotifyTimeout() = 0; 332 | }; 333 | 334 | /// @brief 异步获取服务实例对象 335 | class InstancesFuture : Noncopyable 336 | { 337 | public: 338 | /// @brief 构造异步获取服务实例对象 339 | explicit InstancesFuture(InstancesFutureImpl *impl); 340 | 341 | /// @brief 析构异步获取服务实例对象 342 | ~InstancesFuture(); 343 | 344 | /// @brief 查询异步获取服务实例是否完成 345 | bool IsDone(bool use_disk_data = true); 346 | 347 | /// @brief 获取服务实例结果,假如异步调用未完成,则阻塞 348 | /// 349 | /// @param wait_time 等待时间,单位为毫秒,为0则立即返回 350 | /// @param result 异步操作返回的实例信息 351 | /// @return ReturnCode 操作结果 352 | /// kReturnOk 表示获取结果成功,结果在result中 353 | /// kReturnTimeout 表示获取结果超时,不设置result 354 | ReturnCode Get(uint64_t wait_time, InstancesResponse *&result); 355 | 356 | /// @brief 设置服务就绪回调,当需要的服务拉取到缓存时执行该回调 357 | void SetServiceCacheNotify(ServiceCacheNotify *service_cache_notify); 358 | 359 | private: 360 | InstancesFutureImpl *impl_; 361 | }; 362 | 363 | class ConsumerApiImpl; 364 | 365 | /// @brief 服务消费端API主接口 366 | class ConsumerApi : Noncopyable 367 | { 368 | public: 369 | ~ConsumerApi(); 370 | 371 | /// @brief 用于提前初始化服务数据 372 | /// 373 | /// @param req 获取单个服务实例请求 374 | /// @return ReturnCode 调用结果 375 | ReturnCode InitService(const GetOneInstanceRequest &req); 376 | 377 | /// @brief 同步获取单个服务实例 378 | /// 379 | /// @param req 获取单个服务实例请求 380 | /// @param instance 服务实例 381 | /// @return ReturnCode 调用结果 382 | ReturnCode GetOneInstance(const GetOneInstanceRequest &req, Instance &instance); 383 | 384 | /// @brief 同步获取单个服务实例 385 | /// 386 | /// @param req 获取单个服务实例请求 387 | /// @param resp 服务实例获取结果,其中只包含一个服务实例 388 | /// @return ReturnCode 调用结果 389 | ReturnCode GetOneInstance(const GetOneInstanceRequest &req, InstancesResponse *&resp); 390 | 391 | /// @brief 同步获取批量服务实例 392 | /// 393 | /// @note 该接口不会返回熔断半开实例,实例熔断后,进入半开如何没有请求一段时间后会自动恢复 394 | /// @param req 批量获取服务实例请求 395 | /// @param resp 服务实例获取结果 396 | /// @return ReturnCode 调用结果 397 | ReturnCode GetInstances(const GetInstancesRequest &req, InstancesResponse *&resp); 398 | 399 | /// @brief 同步获取服务下全部服务实例,返回的实例与控制台看到的一致 400 | /// 401 | /// @param req 批量获取服务实例请求 402 | /// @param resp 服务实例获取结果 403 | /// @return ReturnCode 调用结果 404 | ReturnCode GetAllInstances(const GetInstancesRequest &req, InstancesResponse *&resp); 405 | 406 | /// @brief 异步获取单个服务路由 407 | /// 408 | /// @param req 获取单个服务实例请求 409 | /// @param future 异步操作future对象,可用于查询和获取操作结果 410 | /// @return ReturnCode 调用结果 411 | ReturnCode AsyncGetOneInstance(const GetOneInstanceRequest &req, InstancesFuture *&future); 412 | 413 | /// @brief 异步获取服务路由表 414 | /// 415 | /// @param req 批量获取服务实例请求 416 | /// @param future 异步操作future对象,可用于查询和获取操作结果 417 | /// @return ReturnCode 调用结果 418 | ReturnCode AsyncGetInstances(const GetInstancesRequest &req, InstancesFuture *&future); 419 | 420 | /// @brief 上报服务调用结果,用于服务实例熔断和监控统计 421 | /// @note 本调用没有网络操作,只是将数据写入内存 422 | /// 423 | /// @param req 服务实例调用结果 424 | /// @return ReturnCode 调用结果 425 | ReturnCode UpdateServiceCallResult(const ServiceCallResult &req); 426 | 427 | /// @brief 拉取路由规则配置的所有key 428 | /// 429 | /// @param service_key 需要预拉取规则的服务 430 | /// @param timeout 预拉取请求超时时间,单位为ms 431 | /// @param keys 规则里配置的所有key 432 | /// @return ReturnCode 拉取结果,拉取失败可重试 433 | ReturnCode GetRouteRuleKeys(const ServiceKey &service_key, uint64_t timeout, 434 | const std::set *&keys); 435 | 436 | /// @brief 通过Context创建Consumer API对象 437 | /// 438 | /// @param Context SDK上下文对象 439 | /// @return ConsumerApi* 创建失败返回NULL 440 | static ConsumerApi *Create(Context *context); 441 | 442 | /// @brief 通过配置创建Consumer API对象 443 | /// 444 | /// @param config 配置对象 445 | /// @return Consumer* 创建失败则返回NULL 446 | static ConsumerApi *CreateFromConfig(Config *config); 447 | 448 | /// @brief 通过配置文件创建Consumer API对象 449 | /// 450 | /// @param file 配置文件 451 | /// @return Consumer* 创建失败返回NULL 452 | static ConsumerApi *CreateFromFile(const std::string &file); 453 | 454 | /// @brief 通过配置字符串创建Consumer API对象 455 | /// 456 | /// @param content 配置字符串 457 | /// @return Consumer* 创建失败返回NULL 458 | static ConsumerApi *CreateFromString(const std::string &content); 459 | 460 | /// @brief 从默认文件创建配置对象,默认文件为./polaris.yaml,文件不存在则使用默认配置 461 | /// 462 | /// @return ConsumerApi* 创建失败返回NULL 463 | static ConsumerApi *CreateWithDefaultFile(); 464 | 465 | private: 466 | explicit ConsumerApi(ConsumerApiImpl *impl); 467 | ConsumerApiImpl *impl_; 468 | }; 469 | 470 | } // namespace polaris 471 | 472 | #endif // POLARIS_CPP_INCLUDE_POLARIS_CONSUMER_H_ 473 | -------------------------------------------------------------------------------- /include/polaris/context.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_CONTEXT_H_ 15 | #define POLARIS_CPP_INCLUDE_POLARIS_CONTEXT_H_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "config.h" 22 | #include "defs.h" 23 | #include "noncopyable.h" 24 | #include "plugin.h" 25 | 26 | namespace polaris 27 | { 28 | 29 | /// @brief Context模式,用于控制Context对象的初始化及释放规则 30 | enum ContextMode 31 | { 32 | kNotInitContext = 0, // 创建未初始化 33 | kPrivateContext, // 私有模式,是否API对象会析构Context 34 | kShareContext, // 共享模式,析构API对象不释放Context,需显式释放Context 35 | kLimitContext, // 限流模式,会创建限流线程,并校验限流配置 36 | kShareContextWithoutEngine // 共享模式,只初始化插件,不创建执行引擎 37 | }; 38 | 39 | /// @brief SDK API 模式 40 | /// 41 | /// 通过配置文件指定API的运行模式 42 | enum ApiMode 43 | { 44 | kServerApiMode, ///< Server模式,SDK与Server交互,SDK运行全部逻辑 45 | kAgentApiMode ///< Agent模式,SDK与Agent交互,SDK只运行部分逻辑,由Agent运行一部分逻辑 46 | }; 47 | 48 | class RouteInfoNotifyImpl; 49 | /// @brief 用于获取服务路由模块需要的数据 50 | class RouteInfoNotify 51 | { 52 | public: 53 | /// @brief 创建对象,只能通过 @see ServiceRouterChain.PrepareRouteInfoWithNotify 54 | /// 方法在数据未准备就绪时创建 55 | explicit RouteInfoNotify(RouteInfoNotifyImpl *impl); 56 | ~RouteInfoNotify(); 57 | 58 | /// @brief 检查是否所有数据已经就绪,可控制是否使用磁盘数据 59 | /// 60 | /// @param use_disk_data 是否使用磁盘加载的数据 61 | /// @return true 数据就绪,可使用 @see SetDataToRouteInfo 方法设置到 @see RouteInfo 对象中 62 | /// @return false 数据未就绪 63 | bool IsDataReady(bool use_disk_data); 64 | 65 | /// @brief 等待服务路由所需要的数据就绪 66 | /// 67 | /// @param ts 时间对象,用于传入超时deadline 68 | /// @return ReturnCode kReturnOk:表示数据在超时前就绪 69 | /// kReturnTimeout:表示达到超时时间数据未就绪 70 | ReturnCode WaitData(timespec &ts); 71 | 72 | /// @brief 设置的服务数据到路由信息对象 73 | /// 74 | /// @param route_info 75 | /// @return ReturnCode kReturnOk:数据就绪且设置成功 76 | /// kReturnServiceNotFound:服务发现返回服务不存在 77 | ReturnCode SetDataToRouteInfo(RouteInfo &route_info); 78 | 79 | private: 80 | RouteInfoNotifyImpl *impl_; 81 | }; 82 | 83 | class ServiceRouterChainImpl; 84 | class ServiceRouterChain 85 | { 86 | public: 87 | explicit ServiceRouterChain(const ServiceKey &service_key); 88 | ~ServiceRouterChain(); 89 | 90 | ReturnCode Init(Config *config, Context *context); 91 | 92 | /// @brief 准备服务路由数据,如果数据未就绪,则创建通知对象用于异步等待服务数据 93 | /// 94 | /// @param route_info 服务路由数据对象 95 | /// @return RouteInfoNotify* 路由数据通知对象。如果为NULL则表示数据准备就绪 96 | RouteInfoNotify *PrepareRouteInfoWithNotify(RouteInfo &route_info); 97 | 98 | /// @brief 阻塞方式准备服务路由数据 99 | /// 100 | /// @param route_info 服务路由数据对象 101 | /// @param timeout 超时等待时间,用于控制该方法最多阻塞的时间 102 | /// @return ReturnCode kReturnOk:数据就绪 103 | /// kReturnTimeout:数据未就绪 104 | ReturnCode PrepareRouteInfo(RouteInfo &route_info, uint64_t timeout); 105 | 106 | /// @brief 返回规则路由插件是否开启 107 | bool IsRuleRouterEnable(); 108 | 109 | /// @brief 执行服务路由链 110 | /// 111 | /// @param route_info 准备就绪的服务数据 112 | /// @param route_result 服务路由执行结果 113 | /// @return ReturnCode kReturnOk:执行成功 114 | ReturnCode DoRoute(RouteInfo &route_info, RouteResult *route_result); 115 | 116 | /// @brief 收集调用统计信息 117 | /// 118 | /// @param service_key 调用服务 119 | /// @param stat_data 调用统计信息 120 | void CollectStat(ServiceKey &service_key, std::map &stat_data); 121 | 122 | private: 123 | ServiceRouterChainImpl *impl_; 124 | }; 125 | 126 | class CircuitBreakerChain 127 | { 128 | public: 129 | virtual ~CircuitBreakerChain() {} 130 | 131 | virtual ReturnCode Init(Config *config, Context *context) = 0; 132 | 133 | virtual ReturnCode RealTimeCircuitBreak(const InstanceGauge &instance_gauge) = 0; 134 | 135 | virtual ReturnCode TimingCircuitBreak() = 0; 136 | 137 | virtual std::vector GetCircuitBreakers() = 0; 138 | 139 | virtual ReturnCode TranslateStatus(const std::string &instance_id, 140 | CircuitBreakerStatus from_status, 141 | CircuitBreakerStatus to_status) = 0; 142 | 143 | virtual void PrepareServicePbConfTrigger() = 0; 144 | }; 145 | 146 | class HealthCheckerChain 147 | { 148 | public: 149 | virtual ~HealthCheckerChain() {} 150 | 151 | virtual ReturnCode Init(Config *config, Context *context) = 0; 152 | 153 | virtual ReturnCode DetectInstance(CircuitBreakerChain &circuit_breaker_chain) = 0; 154 | 155 | virtual std::vector GetHealthCheckers() = 0; 156 | }; 157 | 158 | class ServiceContextImpl; 159 | /// @brief 服务级别上下文 160 | class ServiceContext : public ServiceBase 161 | { 162 | public: 163 | explicit ServiceContext(ServiceContextImpl *impl); 164 | ~ServiceContext(); 165 | 166 | LoadBalancer *GetLoadBalancer(LoadBalanceType load_balance_type); 167 | 168 | WeightAdjuster *GetWeightAdjuster(); 169 | 170 | CircuitBreakerChain *GetCircuitBreakerChain(); 171 | 172 | HealthCheckerChain *GetHealthCheckerChain(); 173 | 174 | ServiceRouterChain *GetServiceRouterChain(); 175 | 176 | ServiceContextImpl *GetServiceContextImpl(); 177 | 178 | private: 179 | ServiceContextImpl *impl_; 180 | }; 181 | 182 | class ContextImpl; 183 | class Context : Noncopyable 184 | { 185 | public: 186 | ~Context(); 187 | 188 | ContextMode GetContextMode(); 189 | 190 | ApiMode GetApiMode(); 191 | 192 | /// @brief 获取或创建服务级别的上下文对象 193 | /// 194 | /// @param service_key 需要创建服务对象的服务 195 | /// @return ServiceContext* 获取或创建成功:返回之前创建或新创建的服务对象 196 | /// 创建失败:返回NULL,通过日志查看创建失败的原因 197 | ServiceContext *GetOrCreateServiceContext(const ServiceKey &service_key); 198 | 199 | ServerConnector *GetServerConnector(); 200 | 201 | LocalRegistry *GetLocalRegistry(); 202 | 203 | ContextImpl *GetContextImpl(); 204 | 205 | /// @brief 创建上下文对象 206 | /// 207 | /// @param config 配置对象 208 | /// @param mode 上下文模式,默认共享模式。 @see ContextMode 209 | /// @return Context* 创建成功:返回创建的上下文对象 210 | /// 创建失败:返回NULL,可通过日志查看创建失败的原因 211 | static Context *Create(Config *config, ContextMode mode = kShareContext); 212 | 213 | private: 214 | explicit Context(ContextImpl *impl); 215 | 216 | ContextImpl *impl_; 217 | }; 218 | 219 | } // namespace polaris 220 | 221 | #endif // POLARIS_CPP_INCLUDE_POLARIS_CONTEXT_H_ 222 | -------------------------------------------------------------------------------- /include/polaris/defs.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | /// @file defs.h 15 | /// @brief 本文件定义返回码和一些基本类型 16 | /// 17 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_DEFS_H_ 18 | #define POLARIS_CPP_INCLUDE_POLARIS_DEFS_H_ 19 | 20 | #ifndef __STDC_FORMAT_MACROS 21 | #define __STDC_FORMAT_MACROS 22 | #endif 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace polaris { 29 | 30 | /// @brief 接口返回错误码 31 | enum ReturnCode { 32 | kReturnOk = 0, ///< 成功 33 | kReturnUnknownError = 1000, ///< 未知错误 34 | kReturnInvalidArgument = 1001, ///< 参数非法,客户端和服务端都会检查参数的正确性 35 | kReturnInvalidConfig = 1002, ///< 配置不正确 36 | kReturnPluginError = 1003, ///< 插件获取相关错误 37 | kReturnTimeout = 1004, ///< 请求超时 38 | kReturnInvalidState = 1005, ///< 程序状态非法错误 39 | kReturnServerError = 1006, ///< 服务调用返回错误 40 | kReturnNetworkFailed = 1007, ///< 网络调用错误 41 | kReturnInstanceNotFound = 1010, ///< 服务实例不存在 42 | kReturnInvalidRouteRule = 1011, ///< 路由规则非法 43 | kReturnRouteRuleNotMatch = 1012, ///< 路由规则匹配失败 44 | kReturnServiceNotFound = 1015, ///< 服务不存在 45 | kReturnExistedResource = 1200, ///< 资源已存在,用于服务实例重复注册的返回码 46 | kReturnUnauthorized = 1201, ///< 请求未授权,token错误 47 | kReturnHealthyCheckDisable = 1202, ///< 服务端或实例健康检查未开启 48 | kRetrunRateLimit = 1203, ///< 请求被限频 49 | kReturnNotInit = 1288, ///< 资源未初始化 50 | kReturnResourceNotFound = 1289, // 资源未找到 51 | kReturnServerUnknownError = 1299, ///< 服务端返回客户端未知的错误 52 | kReturnSystemServiceNotConfigured = 1300, ///< 没有配置系统服务名字 53 | }; 54 | 55 | /// @brief 返回码转换为字符串消息 56 | /// 57 | /// @param return_code 需要转换的返回码 58 | /// @return std::string 返回码对应的字符串信息 59 | std::string ReturnCodeToMsg(ReturnCode return_code); 60 | 61 | /// @组合service的namespace和name用于唯一确定一个服务 62 | struct ServiceKey { 63 | std::string namespace_; 64 | std::string name_; 65 | }; 66 | 67 | /// @brief 实现比较函数用于ServiceKey作为map的key 68 | bool operator<(ServiceKey const &lhs, ServiceKey const &rhs); 69 | 70 | bool operator==(const ServiceKey &lhs, const ServiceKey &rhs); 71 | 72 | /// @brief 定义源服务信息,用于服务路由执行过滤 73 | struct ServiceInfo { 74 | ServiceKey service_key_; 75 | std::map metadata_; 76 | }; 77 | 78 | /// @brief 负载均衡类型 79 | /// 80 | /// @note 添加负载均衡插件时必须添加一个类型,并定义该插件的 GetLoadBalanceType 方法返回该值 81 | typedef std::string LoadBalanceType; 82 | // 权重随机 83 | const static LoadBalanceType kLoadBalanceTypeWeightedRandom = "weightedRandom"; 84 | // 一致性hash负载均衡 85 | const static LoadBalanceType kLoadBalanceTypeRingHash = "ringHash"; 86 | // 一致性Hash: maglev 算法 87 | const static LoadBalanceType kLoadBalanceTypeMaglevHash = "maglev"; 88 | // 兼容L5的一致性Hash 89 | const static LoadBalanceType kLoadBalanceTypeL5CstHash = "l5cst"; 90 | // hash_key%总实例数 选择服务实例 91 | const static LoadBalanceType kLoadBalanceTypeSimpleHash = "simpleHash"; 92 | // 兼容brpc c_murmur的一致性哈希 93 | const static LoadBalanceType kLoadBalanceTypeCMurmurHash = "cMurmurHash"; 94 | // 兼容brpc locality_aware的负载均衡 95 | const static LoadBalanceType kLoadBalanceTypeLocalityAware = "localityAware"; 96 | // 使用全局配置的负载均衡算法 97 | const static LoadBalanceType kLoadBalanceTypeDefaultConfig = "default"; 98 | 99 | /// @brief 元数据路由匹配失败时降级策略 100 | enum MetadataFailoverType { 101 | kMetadataFailoverNone, // 默认不降级 102 | kMetadataFailoverAll, // 降级返回所有节点 103 | kMetadataFailoverNotKey, // 返回不包含元数据路由key的节点 104 | }; 105 | 106 | struct MetadataRouterParam { 107 | MetadataRouterParam() : failover_type_(kMetadataFailoverNone) {} 108 | std::map metadata_; 109 | MetadataFailoverType failover_type_; 110 | }; 111 | 112 | /// @brief 负载均衡参数 113 | struct Criteria { 114 | Criteria() : hash_key_(0), ignore_half_open_(false), replicate_index_(0) {} 115 | uint64_t hash_key_; 116 | bool ignore_half_open_; 117 | std::string hash_string_; 118 | int replicate_index_; 119 | }; 120 | 121 | /// @brief 服务实例状态,用于上报服务实例状态 122 | /// 123 | /// 服务实例超时和错误会用于实例熔断 @note 调用服务实例返回业务错误不要上报错误 124 | enum CallRetStatus { 125 | kCallRetOk = 0, ///< 服务实例正常 126 | kCallRetTimeout, ///< 服务实例超时 127 | kCallRetError ///< 服务实例错误 128 | }; 129 | 130 | /// @brief 三级位置信息 131 | struct Location { 132 | std::string region; 133 | std::string zone; 134 | std::string campus; 135 | }; 136 | 137 | /// @brief 权重类型 138 | enum WeightType { 139 | kStaticWeightType = 0, ///< 静态权重,实例注册或用户在控制台设置的实例权重 140 | kDynamicWeightType ///< 动态权重,权重调整插件计算的权重 141 | }; 142 | 143 | /// @brief 健康检查类型 144 | enum HealthCheckType { 145 | kHeartbeatHealthCheck = 0, ///< 根据心跳上报进行健康检查 146 | }; 147 | 148 | } // namespace polaris 149 | 150 | #endif // POLARIS_CPP_INCLUDE_POLARIS_DEFS_H_ 151 | -------------------------------------------------------------------------------- /include/polaris/limit.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_LIMIT_H_ 15 | #define POLARIS_CPP_INCLUDE_POLARIS_LIMIT_H_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "polaris/context.h" 22 | #include "polaris/noncopyable.h" 23 | 24 | namespace polaris { 25 | 26 | class QuotaRequestImpl; 27 | /// @brief 限流配额请求 28 | class QuotaRequest { 29 | public: 30 | /// @brief 构造配额限流请求 31 | QuotaRequest(); 32 | 33 | /// @brief 析构限流配额请求 34 | ~QuotaRequest(); 35 | 36 | /// @brief 设置服务命名空间 37 | void SetServiceNamespace(const std::string& service_namespace); 38 | 39 | /// @brief 设置服务名 40 | void SetServiceName(const std::string& service_name); 41 | 42 | /// @brief 设置标签用于选择限流配置 43 | /// 44 | /// @param labels 标签 45 | void SetLabels(const std::map& labels); 46 | 47 | /// @brief 设置请求需要分配的配额数量,可选,默认为1 48 | /// 49 | /// @param amount 请求的配额数量 50 | void SetAcquireAmount(int amount); 51 | 52 | /// @brief 设置请求超时时间,可选,单位ms,默认1000ms 53 | void SetTimeout(uint64_t timeout); 54 | 55 | /// @brief 设置请求的所属服务子集,可选 56 | /// 57 | /// @param subset 服务子集 58 | void SetSubset(const std::map& subset); 59 | 60 | private: 61 | friend class QuotaRequestAccessor; 62 | QuotaRequestImpl* impl_; 63 | }; 64 | 65 | /// @brief 配额获取结果 66 | enum QuotaResultCode { 67 | kQuotaResultOk = 0, // 配额正常 68 | kQuotaResultLimited, // 配额被限流 69 | kQuotaResultWait // 需求需要等待重试 70 | }; 71 | 72 | struct QuotaResultInfo { 73 | int64_t left_quota_; // 剩余配额 74 | int64_t all_quota_; // 配置的配额 75 | uint64_t duration_; // 配置周期 76 | bool is_degrade_; // 是否降级 77 | }; 78 | 79 | class QuotaResponseImpl; 80 | /// @brief 限流配额应答 81 | class QuotaResponse { 82 | public: 83 | /// @brief 构造配额应答 84 | explicit QuotaResponse(QuotaResponseImpl* impl); 85 | 86 | /// @brief 析构配额应答 87 | ~QuotaResponse(); 88 | 89 | /// @brief 获取限流配额结果 90 | /// 91 | /// @return QuotaResultCode 限流配额结果 92 | QuotaResultCode GetResultCode() const; 93 | 94 | /// @brief 获取服务实例 95 | /// 96 | /// @return const QuotaResultInfo& 97 | const QuotaResultInfo& GetQuotaResultInfo() const; 98 | 99 | /// @brief 请求需要获取多长时间才能使用配额 100 | /// 101 | /// @return uint64_t 等待时间,单位ms 102 | uint64_t GetWaitTime() const; 103 | 104 | private: 105 | QuotaResponseImpl* impl_; 106 | }; 107 | 108 | enum LimitCallResultType { 109 | kLimitCallResultLimited, // 配额被限制使用 110 | kLimitCallResultFailed, // 配额使用失败 111 | kLimitCallResultOk // 配额使用成功 112 | }; 113 | 114 | class LimitCallResultImpl; 115 | /// @brief 配额使用结果 116 | class LimitCallResult { 117 | public: 118 | /// @brief 构造配额使用结果 119 | LimitCallResult(); 120 | 121 | /// @brief 析构限流配额使用结果 122 | ~LimitCallResult(); 123 | 124 | /// @brief 设置服务命名空间 125 | void SetServiceNamespace(const std::string& service_namespace); 126 | 127 | /// @brief 设置服务名 128 | void SetServiceName(const std::string& service_name); 129 | 130 | /// @brief 设置请求的所属服务子集 131 | /// 132 | /// @param subset 服务子集 133 | void SetSubset(const std::map& subset); 134 | 135 | /// @brief 设置标签 136 | void SetLabels(const std::map& labels); 137 | 138 | /// @brief 设置接口调用结果 139 | void SetResponseResult(LimitCallResultType result_type); 140 | 141 | /// @brief 设置接口调用时间 142 | void SetResponseTime(uint64_t response_time); 143 | 144 | /// @brief 设置应答返回码 145 | void SetResponseCode(int response_code); 146 | 147 | private: 148 | friend class LimitCallResultAccessor; 149 | LimitCallResultImpl* impl_; 150 | }; 151 | 152 | class LimitApiImpl; 153 | class LimitApi : Noncopyable { 154 | public: 155 | ~LimitApi(); 156 | 157 | /// @brief 预拉取服务配置的限流规则,默认超时时间1000ms 158 | /// 159 | /// @param service_key 需要预拉取限流规则的服务 160 | /// @param json_rule json格式的限流规则 161 | /// @return ReturnCode 拉取结果,拉取失败可重试 162 | ReturnCode FetchRule(const ServiceKey& service_key, std::string& json_rule); 163 | 164 | /// @brief 预拉取服务配置的限流规则 165 | /// 166 | /// @param service_key 需要预拉取限流规则的服务 167 | /// @param timeout 预拉取请求超时时间,单位为ms 168 | /// @param json_rule json格式的限流规则 169 | /// @return ReturnCode 拉取结果,拉取失败可重试 170 | ReturnCode FetchRule(const ServiceKey& service_key, uint64_t timeout, std::string& json_rule); 171 | 172 | /// @brief 拉取服务配置的限流规则配置的所有key 173 | /// 174 | /// @param service_key 需要预拉取限流规则的服务 175 | /// @param timeout 预拉取请求超时时间,单位为ms 176 | /// @param label_keys 限流规则里配置的label的所有key 177 | /// @return ReturnCode 拉取结果,拉取失败可重试 178 | ReturnCode FetchRuleLabelKeys(const ServiceKey& service_key, uint64_t timeout, 179 | const std::set*& label_keys); 180 | 181 | /// @brief 获取配额应答 182 | /// 183 | /// @param quota_request 获取配额请求 184 | /// @param quota_response 获取配额应答 185 | /// @return ReturnCode 获取返回码 186 | ReturnCode GetQuota(const QuotaRequest& quota_request, QuotaResponse*& quota_response); 187 | 188 | /// @brief 获取配额 189 | /// 190 | /// @param quota_request 获取配额请求 191 | /// @param quota_result 获取配额结果 192 | /// @return ReturnCode 获取返回码 193 | ReturnCode GetQuota(const QuotaRequest& quota_request, QuotaResultCode& quota_result); 194 | 195 | /// @brief 获取配额 196 | /// 197 | /// @param quota_request 获取配额请求 198 | /// @param quota_result 获取配额结果 199 | /// @param quota_info 当前配额信息 200 | /// @return ReturnCode 获取返回码 201 | ReturnCode GetQuota(const QuotaRequest& quota_request, QuotaResultCode& quota_result, 202 | QuotaResultInfo& quota_info); 203 | 204 | /// @brief 获取配额 205 | /// 206 | /// @param quota_request 获取配额请求 207 | /// @param quota_result 获取配额结果 208 | /// @param wait_time 等待时间,单位ms,请求需要排队时间,匀速排队时使用 209 | /// @return ReturnCode 获取返回码 210 | ReturnCode GetQuota(const QuotaRequest& quota_request, QuotaResultCode& quota_result, 211 | uint64_t& wait_time); 212 | 213 | /// @brief 更新请求配额调用结果 214 | /// 215 | /// @param call_result 配额调用结果 216 | /// @return ReturnCode 返回码 217 | ReturnCode UpdateCallResult(const LimitCallResult& call_result); 218 | 219 | /// @brief 初始化配额窗口,可选调用,用于提前初始化配窗口减小首次配额延迟 220 | /// 221 | /// @param quota_request 配额请求 222 | /// @return ReturnCode 获取返回码 223 | ReturnCode InitQuotaWindow(const QuotaRequest& quota_request); 224 | 225 | /// @brief 通过Context创建Limit API对象 226 | /// 227 | /// @param Context SDK上下文对象 228 | /// @return LimitApi* 创建失败返回NULL 229 | static LimitApi* Create(Context* Context); 230 | 231 | /// @brief 通过Context创建Limit API对象 232 | /// 233 | /// @param Context SDK上下文对象 234 | /// @param err_msg 创建失败时的错误原因 235 | /// @return LimitApi* 创建失败返回NULL 236 | static LimitApi* Create(Context* Context, std::string& err_msg); 237 | 238 | /// @brief 通过配置创建Limit API对象 239 | /// 240 | /// @param config 配置对象 241 | /// @return LimitApi* 创建失败则返回NULL 242 | static LimitApi* CreateFromConfig(Config* config); 243 | 244 | /// @brief 通过配置创建Limit API对象 245 | /// 246 | /// @param config 配置对象 247 | /// @param err_msg 创建失败时的错误原因 248 | /// @return LimitApi* 创建失败返回NULL 249 | static LimitApi* CreateFromConfig(Config* config, std::string& err_msg); 250 | 251 | /// @brief 通过配置文件创建Limit API对象 252 | /// 253 | /// @param file 配置文件 254 | /// @return LimitApi* 创建失败返回NULL 255 | static LimitApi* CreateFromFile(const std::string& file); 256 | 257 | /// @brief 通过配置文件创建Limit API对象 258 | /// 259 | /// @param file 配置文件 260 | /// @param err_msg 创建失败时的错误原因 261 | /// @return LimitApi* 创建失败返回NULL 262 | static LimitApi* CreateFromFile(const std::string& file, std::string& err_msg); 263 | 264 | /// @brief 通过配置字符串创建Limit API对象 265 | /// 266 | /// @param content 配置字符串 267 | /// @return LimitApi* 创建失败返回NULL 268 | static LimitApi* CreateFromString(const std::string& content); 269 | 270 | /// @brief 通过配置字符串创建Limit API对象 271 | /// 272 | /// @param content 配置字符串 273 | /// @param err_msg 创建失败时的错误原因 274 | /// @return LimitApi* 创建失败返回NULL 275 | static LimitApi* CreateFromString(const std::string& content, std::string& err_msg); 276 | 277 | /// @brief 从默认文件创建配置对象,默认文件为./polaris.yaml,文件不存在则使用默认配置 278 | /// 279 | /// @return LimitApi* 创建失败返回NULL 280 | static LimitApi* CreateWithDefaultFile(); 281 | 282 | /// @brief 从默认文件创建配置对象,默认文件为./polaris.yaml,文件不存在则使用默认配置 283 | /// 284 | /// @param err_msg 创建失败时的错误原因 285 | /// @return LimitApi* 创建失败返回NULL 286 | static LimitApi* CreateWithDefaultFile(std::string& err_msg); 287 | 288 | private: 289 | explicit LimitApi(LimitApiImpl* impl); 290 | 291 | LimitApiImpl* impl_; 292 | }; 293 | 294 | } // namespace polaris 295 | 296 | #endif // POLARIS_CPP_INCLUDE_POLARIS_LIMIT_H_ 297 | -------------------------------------------------------------------------------- /include/polaris/log.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | /// @file log.h 15 | /// @brief 本文件定义SDK日志接口 16 | /// 17 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_LOG_H_ 18 | #define POLARIS_CPP_INCLUDE_POLARIS_LOG_H_ 19 | 20 | #include 21 | 22 | namespace polaris { 23 | 24 | /// @brief 日志接口中使用的日志级别定义 25 | /// 26 | /// @note Trace和Debug级别会同时输出到stdout和文件,Info及以上级别只输出到文件 27 | enum LogLevel { 28 | kTraceLogLevel = 0, 29 | kDebugLogLevel, 30 | kInfoLogLevel, 31 | kWarnLogLevel, 32 | kErrorLogLevel, 33 | kFatalLogLevel 34 | }; 35 | 36 | /// @brief 日志级别相关宏定义 37 | #define POLARIS_TRACE __FILE__, __LINE__, kTraceLogLevel 38 | #define POLARIS_DEBUG __FILE__, __LINE__, kDebugLogLevel 39 | #define POLARIS_INFO __FILE__, __LINE__, kInfoLogLevel 40 | #define POLARIS_WARN __FILE__, __LINE__, kWarnLogLevel 41 | #define POLARIS_ERROR __FILE__, __LINE__, kErrorLogLevel 42 | #define POLARIS_FATAL __FILE__, __LINE__, kFatalLogLevel 43 | 44 | /// @brief 日志接口,用于用户实现自己的日志输出逻辑 45 | /// 46 | /// SDK默认有日志实现,但仍然建议用户实现自己的业务接口 47 | class Logger { 48 | public: 49 | virtual ~Logger() {} 50 | 51 | /// @brief 用于判断指定日志级别是否输出 52 | /// 53 | /// SDK中有些日志相对复杂,在调用 @see Log 54 | /// 方法之前先判断对应日志级别是否开启来决定是否进行内容组装 55 | /// @param log_level 需要判断是否输出的日志级别 56 | /// @return true 对应日志级别需要输出 57 | /// @return false 对应日志级别无需输出 58 | virtual bool isLevelEnabled(LogLevel log_level) = 0; 59 | 60 | /// @brief 设置日志的输出级别 61 | /// 62 | /// 大于等于该日志级别的相关日志会输出 63 | /// @param log_level 目标日志级别 64 | virtual void SetLogLevel(LogLevel log_level) = 0; 65 | 66 | /// @brief 设置日志输出目录 67 | /// 68 | /// @param log_dir 日志输出目录 69 | virtual void SetLogDir(const std::string& log_dir) = 0; 70 | 71 | /// @brief 日志输出执行方法 72 | /// 73 | /// @param file 日志输出点所在文件 74 | /// @param line 日志输出点所在文件行号 75 | /// @param log_level 日志输出级别 76 | /// @param format 日志输出格式 77 | /// @param ... 日志输出可变长参数 78 | virtual void Log(const char* file, int line, LogLevel log_level, const char* format, ...) 79 | __attribute__((format(printf, 5, 6))) = 0; 80 | }; 81 | 82 | /// @brief 设置SDK全局日志对象 83 | /// 84 | /// @note SDK只使用该对象进行日志输出,需要用户自己管理该对象的析构 85 | /// @param logger 需要设置的日志对象,为NULL时会将日志重置成默认日志对象 86 | void SetLogger(Logger* logger); 87 | 88 | /// @brief 设置SDK统计日志对象 89 | /// 90 | /// @note SDK只使用该对象进行统计相关日志输出,需要用户自己管理该对象的析构 91 | /// @param logger 需要设置的日志对象,为NULL时会将日志重置成默认日志对象 92 | void SetStatLogger(Logger* logger); 93 | 94 | /// @brief 设置所有Logger的日志输出目录 95 | /// 96 | /// @param log_dir 日志输出目录 97 | void SetLogDir(const std::string& log_dir); 98 | 99 | /// @brief 获取SDK全局日志对象 100 | Logger* GetLogger(); 101 | 102 | /// @brief 获取SDK统计日志对象 103 | Logger* GetStatLogger(); 104 | 105 | } // namespace polaris 106 | 107 | #endif // POLARIS_CPP_INCLUDE_POLARIS_LOG_H_ 108 | -------------------------------------------------------------------------------- /include/polaris/model.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | /// @file model.h 15 | /// @brief define the service model and service's data 16 | /// 17 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_MODEL_H_ 18 | #define POLARIS_CPP_INCLUDE_POLARIS_MODEL_H_ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "defs.h" 29 | #include "noncopyable.h" 30 | 31 | namespace polaris 32 | { 33 | 34 | /////////////////////////////////////////////////////////////////////////////// 35 | /// @brief 服务实例 36 | /// 37 | /// 包含服务实例的所有信息 38 | /// 其中实例动态权重由动态权重调整模块设置 39 | /// 除此之外,其他属性均从服务端获取 40 | class InstanceLocalValue; 41 | class Instance 42 | { 43 | public: 44 | Instance(); 45 | 46 | Instance(const std::string &id, const std::string &host, const int &port, const uint32_t &weight); 47 | 48 | Instance(const Instance &other); 49 | 50 | const Instance &operator=(const Instance &other); 51 | 52 | ~Instance(); 53 | 54 | std::string &GetId() const; ///< 服务实例ID 55 | 56 | std::string &GetHost() const; ///< 服务的节点IP或者域名 57 | 58 | int GetPort() const; ///< 节点端口号 59 | 60 | uint64_t GetLocalId(); /// 本地生成的唯一ID 61 | 62 | std::string &GetVpcId(); ///< 获取服务实例所在VIP ID 63 | 64 | uint32_t GetWeight(); ///< 实例静态权重值, 0-1000 65 | 66 | std::string &GetProtocol(); ///< 实例协议信息 67 | 68 | std::string &GetVersion(); ///< 实例版本号信息 69 | 70 | int GetPriority(); ///< 实例优先级 71 | 72 | bool isHealthy(); ///< 实例健康状态 73 | 74 | bool isIsolate(); ///< 实例隔离状态 75 | 76 | std::map &GetMetadata(); ///< 实例元数据信息 77 | 78 | std::string &GetContainerName(); ///< 实例元数据信息中的容器名 79 | 80 | std::string &GetInternalSetName(); ///< 实例元数据信息中的set名 81 | 82 | std::string &GetLogicSet(); ///< 实例LogicSet信息 83 | 84 | uint32_t GetDynamicWeight(); ///< 实例动态权重 85 | 86 | std::string &GetRegion(); ///< location region 87 | 88 | std::string &GetZone(); ///< location zone 89 | 90 | std::string &GetCampus(); ///< location campus 91 | 92 | uint64_t GetHash(); 93 | 94 | InstanceLocalValue *GetLocalValue(); 95 | 96 | uint64_t GetLocalityAwareInfo(); // locality_aware_info 97 | 98 | private: 99 | friend class InstanceSetter; 100 | class InstanceImpl; 101 | InstanceImpl *impl; 102 | }; 103 | 104 | /////////////////////////////////////////////////////////////////////////////// 105 | // 服务数据相关定义 106 | 107 | /// @brief 服务数据类型 108 | enum ServiceDataType 109 | { 110 | kServiceDataInstances, ///< 服务实例数据 111 | kServiceDataRouteRule, ///< 服务路由规则数据 112 | kServiceDataRateLimit, ///< 服务限流规则数据 113 | kCircuitBreakerConfig, /// < 熔断规则 114 | }; 115 | 116 | /// @brief 服务数据状态 117 | enum ServiceDataStatus 118 | { 119 | kDataNotInit = 0, 120 | kDataInitFromDisk, ///< 表示服务数据从磁盘加载,向服务端更新服务失败时降级使用磁盘加载的数据 121 | kDataIsSyncing, ///< 表示该服务数据时从服务器返回的,大于该值的数据都是从服务器端返回的 122 | kDataNotFound, ///< 服务端返回未找到服务数据 123 | }; 124 | 125 | class ServiceBaseImpl; 126 | /// @brief 线程安全的引用计数基类 127 | class ServiceBase : Noncopyable 128 | { 129 | public: 130 | ServiceBase(); 131 | 132 | virtual ~ServiceBase(); 133 | 134 | /// @brief 原子增加一次引用计数 135 | void IncrementRef(); 136 | 137 | /// @brief 原子减少一次引用计数 138 | void DecrementRef(); 139 | 140 | /// @brief 原子减少一次引用计数并返回,主要用于测试 141 | uint64_t DecrementAndGetRef(); 142 | 143 | private: 144 | ServiceBaseImpl *impl_; 145 | }; 146 | 147 | /// @brief 实例分组,用于记录路由计算的结果 148 | class Selector; 149 | class InstancesSetImpl; 150 | class InstancesSet : public ServiceBase 151 | { 152 | public: 153 | explicit InstancesSet(const std::vector &instances); 154 | 155 | InstancesSet(const std::vector &instances, 156 | const std::map &subset); 157 | 158 | InstancesSet(const std::vector &instances, 159 | const std::map &subset, const std::string &recover_info); 160 | 161 | virtual ~InstancesSet(); 162 | 163 | const std::vector &GetInstances() const; 164 | 165 | const std::map &GetSubset() const; 166 | 167 | const std::string &GetRecoverInfo() const; 168 | 169 | void SetSelector(Selector *selector); 170 | 171 | Selector *GetSelector(); 172 | 173 | void AcquireSelectorCreationLock(); 174 | 175 | void ReleaseSelectorCreationLock(); 176 | 177 | InstancesSetImpl *GetInstancesSetImpl(); 178 | 179 | private: 180 | InstancesSetImpl *impl_; 181 | }; 182 | 183 | class Service; 184 | class ServiceDataImpl; 185 | 186 | /// @brief 服务数据,作为 @ref Service 的属性,用于表示加载的各种类型的服务数据 187 | /// 188 | /// ServiceData 一旦创建则不会修改。新版本的的数据创建成ServiceData对象后原子替换到Service中 189 | /// 被替换的旧的同类型的服务数据会加入垃圾回收列表,垃圾回收使用引用计数方便判断是否可回收 190 | class ServiceData : public ServiceBase 191 | { 192 | public: 193 | virtual ~ServiceData(); 194 | 195 | ServiceKey &GetServiceKey(); 196 | 197 | const std::string &GetRevision() const; 198 | 199 | uint64_t GetCacheVersion(); 200 | 201 | ServiceDataType GetDataType(); 202 | 203 | ServiceDataStatus GetDataStatus(); 204 | 205 | /// @brief 返回服务数据所属服务,只有更新到本地缓存的数据对象,才会关联对应的服务 206 | Service *GetService(); 207 | 208 | const std::string &ToJsonString(); 209 | 210 | ServiceDataImpl *GetServiceDataImpl(); 211 | 212 | bool IsAvailable(); 213 | 214 | static ServiceData *CreateFromJson(const std::string &content, ServiceDataStatus data_status, 215 | uint64_t available_time); 216 | 217 | static ServiceData *CreateFromPb(void *content, ServiceDataStatus data_status, 218 | uint64_t cache_version = 0); 219 | 220 | private: 221 | static ServiceData *CreateFromPbJson(void *pb_content, const std::string &json_content, 222 | ServiceDataStatus data_status, uint64_t cache_version); 223 | 224 | explicit ServiceData(ServiceDataType data_type); 225 | ServiceDataImpl *impl_; 226 | }; 227 | 228 | class ServiceDataNotifyImpl; 229 | /// @brief 用于通知数据首次完成从服务器同步 230 | class ServiceDataNotify : Noncopyable 231 | { 232 | public: 233 | ServiceDataNotify(const ServiceKey &service_key, ServiceDataType data_type); 234 | 235 | ~ServiceDataNotify(); 236 | 237 | bool hasData(); 238 | 239 | /// @brief 通知回调 240 | ReturnCode WaitDataWithRefUtil(const timespec &ts, ServiceData *&service_data); 241 | 242 | void Notify(ServiceData *service_data); 243 | 244 | private: 245 | ServiceDataNotifyImpl *impl_; 246 | }; 247 | 248 | class ServiceInstancesImpl; 249 | class InstancesSet; 250 | /// @brief 服务实例数据:将类型为服务实例集合的服务数据封装成可选择的服务实例数据 251 | class ServiceInstances : Noncopyable 252 | { 253 | public: 254 | explicit ServiceInstances(ServiceData *service_data); 255 | ~ServiceInstances(); 256 | 257 | /// @brief 获取服务metadata 258 | std::map &GetServiceMetadata(); 259 | 260 | /// @brief 获取所有服务实例列表 261 | std::map &GetInstances(); 262 | 263 | /// @brief 获取不健康的实例列表 264 | std::set &GetUnhealthyInstances(); 265 | 266 | /// @brief 获取半开实例数据 267 | void GetHalfOpenInstances(std::set &half_open_instances); 268 | 269 | /// @brief 获取可用的服务实例列表 270 | InstancesSet *GetAvailableInstances(); 271 | 272 | /// @brief 保留部分实例 273 | void UpdateAvailableInstances(InstancesSet *available_instances); 274 | 275 | /// @brief 获取服务实例所属的服务 276 | Service *GetService(); 277 | 278 | /// @brief 获取封装的服务数据 279 | ServiceData *GetServiceData(); 280 | 281 | /// @brief 返回服务是否开启就近路由 282 | bool IsNearbyEnable(); 283 | 284 | /// @brief 返回服务是否开启金丝雀路由 285 | bool IsCanaryEnable(); 286 | 287 | /// @brief 返回隔离实例和权重为0的实例列表 288 | std::set &GetIsolateInstances(); 289 | 290 | private: 291 | ServiceInstancesImpl *impl_; 292 | }; 293 | 294 | /// @brief 服务路由:封装类型为服务路由的服务数据提供服务路由接口 295 | class ServiceRouteRule : Noncopyable 296 | { 297 | public: 298 | explicit ServiceRouteRule(ServiceData *data); 299 | 300 | ~ServiceRouteRule(); 301 | 302 | void *RouteRule(); 303 | 304 | const std::set &GetKeys() const; 305 | 306 | /// @brief 获取封装的服务数据 307 | ServiceData *GetServiceData(); 308 | 309 | private: 310 | ServiceData *service_data_; 311 | }; 312 | 313 | /////////////////////////////////////////////////////////////////////////////// 314 | struct CircuitBreakerData; 315 | struct DynamicWeightData; 316 | struct CircuitBreakUnhealthySetsData; 317 | struct SetCircuitBreakerUnhealthyInfo; 318 | 319 | class ServiceImpl; 320 | /// @brief 服务缓存 321 | /// 322 | /// 用于在内存中管理服务数据,包含以下部分: 323 | /// - 服务加载通知对象 324 | /// - 服务端下发的服务数据:服务和服务下实例信息 325 | /// - 动态权重调整数据:由动态权重插件更新 326 | /// - 服务实例熔断数据:由熔断插件更新 327 | /// 328 | /// 每个服务的服务缓存在 @ref LocalRegistry 插件中只有一个对象。从用户首次请求开始创建, 329 | /// 到一定时间不再访问后过期删除,期间其他插件只会更新服务缓存中的数据。 330 | class Service : Noncopyable 331 | { 332 | public: 333 | Service(const ServiceKey &service_key, uint32_t service_id); 334 | ~Service(); 335 | 336 | ServiceKey &GetServiceKey(); 337 | 338 | /// @brief 将服务关联到服务数据 339 | /// 340 | /// @param service_data 服务数据 341 | void UpdateData(ServiceData *service_data); 342 | 343 | void SetDynamicWeightData(const DynamicWeightData &dynamic_weight_data); 344 | 345 | uint64_t GetDynamicWeightDataVersion(); 346 | 347 | std::map GetDynamicWeightData(); 348 | 349 | void SetCircuitBreakerData(const CircuitBreakerData &circuit_breaker_data); 350 | 351 | uint64_t GetCircuitBreakerDataVersion(); 352 | 353 | std::map GetCircuitBreakerHalfOpenInstances(); 354 | 355 | std::set GetCircuitBreakerOpenInstances(); 356 | 357 | ReturnCode TryChooseHalfOpenInstance(std::set &instances, Instance *&instance); 358 | 359 | ReturnCode WriteCircuitBreakerUnhealthySets( 360 | const CircuitBreakUnhealthySetsData &unhealthy_sets_data); 361 | 362 | uint64_t GetCircuitBreakerSetUnhealthyDataVersion(); 363 | std::map GetCircuitBreakerSetUnhealthySets(); 364 | 365 | private: 366 | ServiceImpl *impl_; 367 | }; 368 | 369 | /////////////////////////////////////////////////////////////////////////////// 370 | 371 | class RouteInfoImpl; 372 | // 路由插件链入参 373 | class RouteInfo : Noncopyable 374 | { 375 | public: 376 | /// @brief 根据用户请求构造路由执行信息 377 | /// 378 | /// @param service_key 被调服务 379 | /// @param source_service_info 主调服务及相关metadata。不需要设置则传入NULL 380 | RouteInfo(const ServiceKey &service_key, ServiceInfo *source_service_info); 381 | 382 | /// @brief 析构路由执行信息 383 | /// @note 此方法会析构所有设置的入参 384 | ~RouteInfo(); 385 | 386 | /// @brief 设置路由插件链执行需要的被调服务实例数据 387 | /// 388 | /// @note 路由插件链执行前必须设置被调服务实例 389 | /// @param service_instances 被调服务实例 390 | void SetServiceInstances(ServiceInstances *service_instances); 391 | 392 | /// @brief 设置路由插件链执行需要的被调服务路由数据 393 | /// 394 | /// @note 如果路由插件链开启了规则路由,则在执行前必须设置被调服务路由规则 395 | /// @param service_route_rule 被调服务路由规则 396 | void SetServiceRouteRule(ServiceRouteRule *service_route_rule); 397 | 398 | /// @brief 设置路由插件链执行需要的主调服务路由数据 399 | /// 400 | /// @note 如果路由插件开启了规则路由,且用户传入了主调服务信息,则在执行前必须设置主调服务路由规则 401 | /// @param source_service_route_rule 主调服务路由规则 402 | void SetSourceServiceRouteRule(ServiceRouteRule *source_service_route_rule); 403 | 404 | /// @brief 更新路由插件所需的被调服务实例数据 405 | /// 406 | /// 该方法在路由插件链执行过程中调用,将上一个插件执行结果设置给下一个插件使用 407 | /// 并释放上一个插件使用的服务实例 408 | /// @param service_instances 新的被调服务实例 409 | void UpdateServiceInstances(ServiceInstances *service_instances); 410 | 411 | /// @brief 获取被调服务 412 | /// 413 | /// @return const ServiceKey& 被调服务 414 | const ServiceKey &GetServiceKey(); 415 | 416 | /// @brief 获取主调服务 417 | /// 418 | /// @return ServiceInfo* 主调服务信息 419 | ServiceInfo *GetSourceServiceInfo(); 420 | 421 | /// @brief 获取本次路由执行的服务实例 422 | /// 423 | /// @return ServiceInstances* 被调服务实例 424 | ServiceInstances *GetServiceInstances(); 425 | 426 | /// @brief 获取被调路由规则 427 | /// 428 | /// @return ServiceRouteRule* 被调路由规则 429 | ServiceRouteRule *GetServiceRouteRule(); 430 | 431 | /// @brief 获取主调路由规则 432 | /// 433 | /// @return ServiceRouteRule* 主调路由规则 434 | ServiceRouteRule *GetSourceServiceRouteRule(); 435 | 436 | /// @brief 设置是否包含不健康实例,默认不包含 437 | void SetIncludeUnhealthyInstances(); 438 | 439 | /// @brief 设置是否包含熔断实例,默认不包含 440 | void SetIncludeCircuitBreakerInstances(); 441 | 442 | /// @brief 路由结果是否包含不健康实例 443 | bool IsIncludeUnhealthyInstances(); 444 | 445 | /// @brief 路由结果是否包含熔断实例 446 | bool IsIncludeCircuitBreakerInstances(); 447 | 448 | /// @brief 路由结果标志是否包含不健康和熔断实例 449 | uint8_t GetRequestFlags(); 450 | 451 | /// @brief 设置是否启用指定路由插件 452 | /// 453 | /// @param router_name 路由插件名字 454 | /// @param enable true为开启,false为关闭 455 | void SetRouterFlag(const char *router_name, bool enable); 456 | 457 | /// @brief 设置结束执行路由链中其他路由插件 458 | void SetRouterChainEnd(bool value); 459 | 460 | /// @brief 获取是否结束路由链标志 461 | bool IsRouterChainEnd(); 462 | 463 | /// @brief 查询路由插件是否启用 464 | bool IsRouterEnable(const char *router_name); 465 | 466 | /// @brief 设置请求标签信息 467 | void SetLables(const std::map &lables); 468 | 469 | /// @brief 获取请求标签信息 470 | const std::map &GetLabels(); 471 | 472 | /// @brief 设置请求元数据路由参数 473 | void SetMetadataPara(const MetadataRouterParam &metadata_param); 474 | 475 | /// @brief 获取请求元数据 476 | const std::map &GetMetadata(); 477 | 478 | /// @brief 获取元数据路由降级类型 479 | MetadataFailoverType GetMetadataFailoverType(); 480 | 481 | private: 482 | ServiceKey service_key_; 483 | ServiceInfo *source_service_info_; 484 | 485 | ServiceInstances *service_instances_; 486 | ServiceRouteRule *service_route_rule_; 487 | ServiceRouteRule *source_service_route_rule_; 488 | uint8_t route_flag_; 489 | 490 | /// @brief const char* 比较函数 491 | struct less_for_c_strings 492 | { 493 | bool operator()(const char *p1, const char *p2) const { return strcmp(p1, p2) < 0; } 494 | }; 495 | std::set *disable_routers_; 496 | 497 | bool end_route_; // 表示不再执行后续的路由插件 498 | 499 | std::map *labels_; 500 | MetadataRouterParam *metadata_param_; 501 | }; 502 | 503 | class RouteResultImpl; 504 | // 路由插件执行结果 505 | class RouteResult : Noncopyable 506 | { 507 | public: 508 | /// @brief 构造路由执行结果对象 509 | RouteResult(); 510 | 511 | /// @brief 析构路由执行结果对象 512 | ~RouteResult(); 513 | 514 | /// @brief 设置路由结果为服务实例类型并设置路由计算得到的服务实例 515 | /// 516 | /// @param service_instances 服务实例 517 | void SetServiceInstances(ServiceInstances *service_instances); 518 | 519 | /// @brief 获取路由计算出的服务实例信息 520 | /// 521 | /// @return ServiceInstances* 路由计算出的服务实例信息 522 | ServiceInstances *GetServiceInstances(); 523 | 524 | /// @brief 获取服务实例结果并清空服务路由结果 525 | /// 526 | /// @return ServiceInstances* 路由计算出的服务实例信息 527 | ServiceInstances *GetAndClearServiceInstances(); 528 | 529 | /// @brief 路由结果是否为需要转发 530 | /// 531 | /// @return true 需要转发,通过可获取转发服务 532 | /// @return false 无需转发,则可获取路由计算出的服务实例信息 533 | bool isRedirect(); 534 | 535 | /// @brief 获取需要转发到的新服务 536 | /// 537 | /// @return ServiceKey& 需要转发到的新服务 538 | const ServiceKey &GetRedirectService(); 539 | 540 | /// @brief 设置路由结果为转发类型并设置需要转发的服务 541 | /// 542 | /// @param service 需要转发到的新服务 543 | void SetRedirectService(const ServiceKey &service); 544 | 545 | /// @brief 设置路由结果所属subset 546 | /// 547 | /// @param subset subset信息 548 | void SetSubset(const std::map &subset); 549 | 550 | /// @brief 获取路由结果subset信息 551 | /// 552 | /// @return const std::map& subset信息 553 | const std::map &GetSubset(); 554 | 555 | private: 556 | ServiceInstances *service_instances_; 557 | ServiceKey *redirect_service_key_; 558 | 559 | std::map subset_; 560 | }; 561 | 562 | } // namespace polaris 563 | 564 | #endif // POLARIS_CPP_INCLUDE_POLARIS_MODEL_H_ 565 | -------------------------------------------------------------------------------- /include/polaris/noncopyable.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_NONCOPYABLE_H_ 15 | #define POLARIS_CPP_INCLUDE_POLARIS_NONCOPYABLE_H_ 16 | 17 | namespace polaris { 18 | 19 | /// @brief 用于屏蔽拷贝构造函数和赋值函数 20 | class Noncopyable { 21 | protected: 22 | Noncopyable() {} 23 | ~Noncopyable() {} 24 | 25 | private: 26 | Noncopyable(const Noncopyable&); 27 | const Noncopyable& operator=(const Noncopyable&); 28 | }; 29 | 30 | } // namespace polaris 31 | 32 | #endif // POLARIS_CPP_INCLUDE_POLARIS_NONCOPYABLE_H_ 33 | -------------------------------------------------------------------------------- /include/polaris/plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | /// @file plugin.h 15 | /// @brief this file define all plugin interface 16 | /// 17 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_PLUGIN_H_ 18 | #define POLARIS_CPP_INCLUDE_POLARIS_PLUGIN_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "accessors.h" 26 | #include "config.h" 27 | #include "defs.h" 28 | #include "model.h" 29 | 30 | namespace polaris 31 | { 32 | 33 | /// @brief 扩展点类型 34 | /// 35 | /// 扩展点有两种级别: 36 | /// 1. API级别:根据每个API配置进行初始化 37 | /// 2. Service级别:根据每个服务配置进行初始化 38 | enum PluginType 39 | { 40 | kPluginServerConnector, ///< server代理扩展点 41 | kPluginLocalRegistry, ///< 本地缓存扩展点 42 | kPluginServiceRouter, ///< 服务路由扩展点 43 | kPluginLoadBalancer, ///< 负载均衡扩展点 44 | kPluginHealthChecker, ///< 健康探测扩展点 45 | kPluginCircuitBreaker, ///< 节点熔断扩展点 46 | kPluginWeightAdjuster, ///< 动态权重调整扩展点 47 | kPluginStatReporter, ///< 统计上报扩展点 48 | kPluginAlertReporter, ///< 告警扩展点 49 | kPluginServerMetric, ///< SDK与Server请求结果统计 50 | 51 | kPluginTypeMaxCount // 插件类型数量 52 | }; 53 | 54 | /// @brief 路由插件事件回调 55 | class InstancesData; 56 | typedef void (*InstancePreUpdateHandler)(const InstancesData *oldInsts, InstancesData *newInsts); 57 | 58 | /// @brief 路由插件事件类型 59 | enum PluginEventType 60 | { 61 | kPluginEvtInstancePreUpdate = 100, // 实例数据更新前 62 | kPluginEvtInstancePostUpdate = 101, // 实例数据更新后 63 | kPluginEvtServiceRoutePreUpdate = 200, // 服务路由数据更新前 64 | kPluginEvtServiceRoutePostUpdate = 201, // 服务路由数据更新后 65 | }; 66 | 67 | class Context; 68 | class InstancesData; 69 | 70 | /// @brief 扩展点接口 71 | class Plugin 72 | { 73 | public: 74 | virtual ~Plugin() {} 75 | 76 | /// @brief 初始化插件 77 | /// 78 | /// @param config 配置信息 79 | /// @return ReturnCode 操作返回码 80 | virtual ReturnCode Init(Config *config, Context *context) = 0; 81 | }; 82 | 83 | /// @brief 插件工厂方法函数指针 84 | typedef Plugin *(*PluginFactory)(); 85 | 86 | /// @brief 注册插件 87 | ReturnCode RegisterPlugin(std::string name, PluginType plugin_type, PluginFactory plugin_factory); 88 | 89 | /// @brief 事件处理回调接口 90 | class ServiceEventHandler 91 | { 92 | public: 93 | /// @brief 析构函数 94 | virtual ~ServiceEventHandler() {} 95 | 96 | /// @brief 事件处理逻辑 97 | /// 98 | /// @param type 事件监听类型 99 | /// @param service_key 需要监听的服务 100 | /// @param data 事件的数据,如果是NULL表示未找到该服务数据 101 | virtual void OnEventUpdate(const ServiceKey &service_key, ServiceDataType data_type, 102 | void *data) = 0; 103 | 104 | /// @brief 同步成功事件回调 105 | virtual void OnEventSync(const ServiceKey &service_key, ServiceDataType data_type) = 0; 106 | }; 107 | 108 | class InstanceRegisterRequest; 109 | class InstanceDeregisterRequest; 110 | class InstanceHeartbeatRequest; 111 | class ProviderCallback; 112 | 113 | /// @brief 扩展点接口:对接Server/Agent的代理,封装了网络通信逻辑 114 | /// 115 | /// 接口分为两部分: 116 | /// 1. 服务事件监听、反监听,用于定时同步服务实例和服务路由 117 | /// 2. 服务注册、反注册、心跳上报、Client上报 118 | class ServerConnector : public Plugin 119 | { 120 | public: 121 | /// @brief 析构函数 122 | virtual ~ServerConnector() {} 123 | 124 | /// @brief 通过配置进行初始化 125 | virtual ReturnCode Init(Config *config, Context *context) = 0; 126 | 127 | /// @brief 注册服务事件监听器 128 | /// 129 | /// @param type 事件类型,目前支持两种类型:服务实例和服务路由 130 | /// @param service_key 要监听的服务 131 | /// @param handler 事件处理回调 132 | /// @return ReturnCode 调用返回码 133 | virtual ReturnCode RegisterEventHandler(const ServiceKey &service_key, ServiceDataType data_type, 134 | uint64_t sync_interval, ServiceEventHandler *handler) = 0; 135 | 136 | /// @brief 反注册事件监听器 137 | /// 138 | /// @param type 事件类型 139 | /// @param service_key 反监听的服务 140 | /// @return ReturnCode 调用返回码 141 | virtual ReturnCode DeregisterEventHandler(const ServiceKey &service_key, 142 | ServiceDataType data_type) = 0; 143 | 144 | /// @brief 实现具体的注册服务请求 145 | /// 146 | /// @param req 服务实例注册请求,已经被校验为合法 147 | /// @param timeout_ms 超时时间(毫秒) 148 | /// @param instance_id 注册成功后服务端返回的实例ID 149 | /// @return int 调用返回码 150 | virtual ReturnCode RegisterInstance(const InstanceRegisterRequest &req, uint64_t timeout_ms, 151 | std::string &instance_id) = 0; 152 | 153 | /// @brief 发送同步反注册服务 154 | /// 155 | /// @param req 反注册请求,已经被校验为合法 156 | /// @param timeout_ms 超时时间(毫秒) 157 | /// @return ReturnCode 调用返回码 158 | virtual ReturnCode DeregisterInstance(const InstanceDeregisterRequest &req, 159 | uint64_t timeout_ms) = 0; 160 | 161 | /// @brief 发送心跳上报请求 162 | /// 163 | /// @param req 心跳请求,已经被校验为合法 164 | /// @param timeout_ms 超时时间(毫秒) 165 | /// @return ReturnCode 调用返回码 166 | virtual ReturnCode InstanceHeartbeat(const InstanceHeartbeatRequest &req, 167 | uint64_t timeout_ms) = 0; 168 | 169 | /// @brief 异步发送心跳上报请求 170 | /// 171 | /// @param req 心跳请求,已经被校验为合法 172 | /// @param timeout_ms 超时时间(毫秒) 173 | /// @param callback 请求完成时结果回调,由SDK回调完成后释放 174 | /// @return ReturnCode 调用返回码 175 | virtual ReturnCode AsyncInstanceHeartbeat(const InstanceHeartbeatRequest &req, 176 | uint64_t timeout_ms, ProviderCallback *callback) = 0; 177 | 178 | /// @brief 发送Client上报请求 179 | /// @param host client端的ip地址 180 | /// @param timeout_ms 超时时间(毫秒) 181 | /// @param location 上报成功后,返回的client端的location 182 | /// @return ReturnCode 调用返回码 183 | virtual ReturnCode ReportClient(const std::string &host, uint64_t timeout_ms, 184 | Location &location) = 0; 185 | }; 186 | 187 | enum CircuitBreakerStatus 188 | { 189 | kCircuitBreakerClose = 0, 190 | kCircuitBreakerHalfOpen, 191 | kCircuitBreakerOpen, 192 | kCircuitBreakerPreserved, 193 | }; 194 | 195 | struct CircuitBreakerData 196 | { 197 | uint64_t version; 198 | std::set open_instances; 199 | std::map half_open_instances; 200 | }; 201 | 202 | struct SetCircuitBreakerUnhealthyInfo 203 | { 204 | // 只坑能是 熔断、保持、半开 205 | CircuitBreakerStatus status; 206 | float half_open_release_percent; 207 | uint64_t open_status_begin_time; 208 | uint64_t last_half_open_release_time; 209 | }; 210 | 211 | struct CircuitBreakUnhealthySetsData 212 | { 213 | uint64_t version; 214 | std::map subset_unhealthy_infos; 215 | }; 216 | 217 | struct DynamicWeightData 218 | { 219 | uint64_t version; 220 | std::map dynamic_weights; 221 | }; 222 | 223 | // 服务数据加载完成通知 224 | class DataNotify 225 | { 226 | public: 227 | virtual ~DataNotify() {} 228 | 229 | // 通知服务数据加载完成 230 | virtual void Notify() = 0; 231 | 232 | // 等待服务数据加载完成 233 | virtual bool Wait(uint64_t timeout) = 0; 234 | }; 235 | 236 | // 服务数据加载通知对象工厂方法 237 | typedef DataNotify *(*DataNotifyFactory)(); 238 | 239 | // 设置服务数据加载通知对象工程方法 240 | class ConsumerApi; 241 | bool SetDataNotifyFactory(ConsumerApi *consumer, DataNotifyFactory factory); 242 | 243 | /// @brief 扩展点接口:本地缓存扩展点 244 | /// 245 | /// 数据的状态转换如下: 246 | /// 初始状态为: InitFromDisk(使用磁盘数据初始化)和NotInit(刚创建未初始化) 247 | /// Get方法获取到的数据可能是InitFromDisk状态。 248 | /// 对于InitFromDisk和NotInit状态的数据首次访问时,需要向ServerConnector注册Handler 249 | /// 并将状态转换为FirstAccessed,在ServerConnector中更新到数据后,将状态转换为IsSyncing 250 | class LocalRegistry : public Plugin 251 | { 252 | public: 253 | /// @brief 析构函数 254 | virtual ~LocalRegistry() {} 255 | 256 | /// @brief 通过配置进行初始化 257 | virtual ReturnCode Init(Config *config, Context *context) = 0; 258 | 259 | virtual void RunGcTask() = 0; 260 | 261 | /// @brief 检查并删除过期服务数据 262 | /// 263 | /// @note 必须在函数内部删除并取消注册到ServerConnector的Handler 264 | /// 如果返回在外部删除,则可能删除过期后新的请求触发的handler 265 | virtual void RemoveExpireServiceData(uint64_t current_time) = 0; 266 | 267 | /// @brief 非阻塞获取服务缓存,只读缓存中的信息 268 | /// 269 | /// @param service_name 服务名 270 | /// @param service_namespace 服务命名空间 271 | /// @param service 返回的服务缓存 272 | /// @return ReturnCode 调用返回码 273 | virtual ReturnCode GetServiceDataWithRef(const ServiceKey &service_key, ServiceDataType data_type, 274 | ServiceData *&service_data) = 0; 275 | 276 | /// @brief 非阻塞触发加载服务,并获取Notify用来等待服务数据首次更新 277 | /// 278 | /// 如果首次获取服务,则会返回码为kReturnNotInit, 279 | /// 表示需要向ServerConnector注册service_key对应的Handler 280 | /// @param service_name 服务名 281 | /// @param service_namespace 服务命名空间 282 | /// @param notify 缓存加载完毕时回调通知对象 283 | /// @return ReturnCode 调用返回码 284 | virtual ReturnCode LoadServiceDataWithNotify(const ServiceKey &service_key, 285 | ServiceDataType data_type, 286 | ServiceData *&service_data, 287 | ServiceDataNotify *¬ify) = 0; 288 | 289 | virtual ReturnCode UpdateServiceData(const ServiceKey &service_key, ServiceDataType data_type, 290 | ServiceData *service_data) = 0; 291 | 292 | virtual ReturnCode UpdateServiceSyncTime(const ServiceKey &service_key, 293 | ServiceDataType data_type) = 0; 294 | 295 | virtual ReturnCode UpdateCircuitBreakerData(const ServiceKey &service_key, 296 | const CircuitBreakerData &circuit_breaker_data) = 0; 297 | 298 | virtual ReturnCode UpdateSetCircuitBreakerData( 299 | const ServiceKey &service_key, const CircuitBreakUnhealthySetsData &unhealthy_sets) = 0; 300 | 301 | virtual ReturnCode GetCircuitBreakerInstances(const ServiceKey &service_key, 302 | ServiceData *&service_data, 303 | std::vector &open_instances) = 0; 304 | 305 | /// @brief 更新服务实例状态,properties存放的是状态值,当前支持2个key 306 | /// 307 | /// 1. ReadyToServe: 故障熔断标识,true or false 308 | /// 2. DynamicWeight:动态权重值 309 | /// @param instance_id 服务实例ID 310 | /// @param properties 属性信息 311 | /// @return ReturnCode 调用返回码 312 | virtual ReturnCode UpdateDynamicWeight(const ServiceKey &service_key, 313 | const DynamicWeightData &dynamic_weight_data) = 0; 314 | 315 | // @brief 用于查看缓存中有多少个service的接口 316 | /// 317 | /// @param service_key_set 输出参数:用于存放ServiceKey信息 318 | /// @return ReturnCode 调用返回码 319 | virtual ReturnCode GetAllServiceKey(std::set &service_key_set) = 0; 320 | }; 321 | 322 | struct RouterStatData; 323 | /// @brief 扩展点接口:服务路由 324 | class ServiceRouter : public Plugin 325 | { 326 | public: 327 | /// @brief 析构函数 328 | virtual ~ServiceRouter() {} 329 | 330 | /// @brief 通过配置进行初始化 331 | virtual ReturnCode Init(Config *config, Context *context) = 0; 332 | 333 | /// @brief 执行服务路由 334 | /// 335 | /// @param router_context 路由上限文,作为路由的输入 336 | /// @param router_result 路由结果,作为路由的输出 337 | /// @return ReturnCode 338 | virtual ReturnCode DoRoute(RouteInfo &route_info, RouteResult *route_result) = 0; 339 | 340 | /// @brief 收集路由统计数据 341 | virtual RouterStatData *CollectStat() = 0; 342 | }; 343 | 344 | /// @brief 扩展点接口:负载均衡 345 | class LoadBalancer : public Plugin 346 | { 347 | public: 348 | /// @brief 析构函数 349 | virtual ~LoadBalancer() {} 350 | 351 | /// @brief 通过配置进行初始化 352 | virtual ReturnCode Init(Config *config, Context *context) = 0; 353 | 354 | /// @brief 获取负载均衡插件对应的类型 355 | virtual LoadBalanceType GetLoadBalanceType() = 0; 356 | 357 | /// @brief 通过负载均衡算法选择一个服务实例 358 | /// 359 | /// @param service 过滤后的服务缓存信息 360 | /// @param criteria 负载均衡信息 361 | /// @param instace 被选择的服务实例 362 | /// @return ReturnCode 调用返回码 363 | virtual ReturnCode ChooseInstance(ServiceInstances *instances, const Criteria &criteria, 364 | Instance *&instance) = 0; 365 | }; 366 | 367 | /// @brief 368 | struct InstanceGauge 369 | { 370 | InstanceGauge() 371 | : call_ret_status(kCallRetOk), call_ret_code(0), call_daley(0), locality_aware_info(0) {} 372 | std::string service_name; 373 | std::string service_namespace; 374 | std::string instance_id; 375 | CallRetStatus call_ret_status; 376 | int call_ret_code; 377 | uint64_t call_daley; 378 | uint64_t locality_aware_info; 379 | 380 | ServiceKey source_service_key; 381 | std::map subset_; 382 | std::map labels_; 383 | }; 384 | 385 | class InstancesCircuitBreakerStatus 386 | { 387 | public: 388 | virtual ~InstancesCircuitBreakerStatus() {} 389 | 390 | virtual bool TranslateStatus(const std::string &instance_id, CircuitBreakerStatus from, 391 | CircuitBreakerStatus to) = 0; 392 | 393 | virtual bool AutoHalfOpenEnable() = 0; 394 | }; 395 | 396 | // 通用的CircuitBreakerStatus 抽象类 397 | class AbstractCircuitBreakerStatus 398 | { 399 | public: 400 | virtual ~AbstractCircuitBreakerStatus() {} 401 | 402 | virtual bool TranslateStatus(const std::string &id, CircuitBreakerStatus from, 403 | CircuitBreakerStatus to) = 0; 404 | 405 | virtual bool AutoHalfOpenEnable() = 0; 406 | 407 | virtual ReturnCode SetAfterHalfOpenRequestRate(float percent) = 0; 408 | virtual ReturnCode GetAfterHalfOpenRequestRate(float *percent) = 0; 409 | }; 410 | 411 | /// @brief 扩展点接口:节点熔断 412 | class CircuitBreaker : public Plugin 413 | { 414 | public: 415 | /// @brief 析构函数 416 | virtual ~CircuitBreaker() {} 417 | 418 | /// @brief 通过配置进行初始化 419 | virtual ReturnCode Init(Config *config, Context *context) = 0; 420 | 421 | virtual int RequestAfterHalfOpen() = 0; 422 | 423 | virtual ReturnCode RealTimeCircuitBreak(const InstanceGauge &instance_gauge, 424 | InstancesCircuitBreakerStatus *instances_status) = 0; 425 | /// @brief 进行节点的熔断 426 | /// 427 | /// @param service 服务缓存 428 | /// @param stat_info 服务统计信息 429 | /// @param instances 返回被熔断的节点 430 | /// @return ReturnCode 调用返回码 431 | virtual ReturnCode TimingCircuitBreak(InstancesCircuitBreakerStatus *instances_status) = 0; 432 | }; 433 | 434 | // @brief 扩展点接口:Set熔断 435 | class SetCircuitBreaker : public Plugin 436 | { 437 | public: 438 | /// @brief 析构函数 439 | virtual ~SetCircuitBreaker() {} 440 | 441 | /// @brief 通过配置进行初始化 442 | virtual ReturnCode Init(Config *config, Context *context) = 0; 443 | 444 | virtual ReturnCode RealTimeCircuitBreak(const InstanceGauge &instance_gauge) = 0; 445 | 446 | virtual ReturnCode TimingCircuitBreak() = 0; 447 | }; 448 | 449 | /// @brief 探测结果 450 | struct DetectResult 451 | { 452 | std::string detect_type; 453 | int return_code; 454 | uint64_t elapse; 455 | }; 456 | 457 | /// @brief 扩展点接口:主动健康探测策略 458 | class HealthChecker : public Plugin 459 | { 460 | public: 461 | /// @brief 析构函数 462 | virtual ~HealthChecker() {} 463 | 464 | /// @brief 通过配置进行初始化 465 | virtual ReturnCode Init(Config *config, Context *context) = 0; 466 | 467 | /// @brief 添加待探测节点 468 | /// 469 | /// @param instance 待探测节点 470 | /// @return ReturnCode 调用返回码 471 | virtual ReturnCode DetectInstance(Instance &instance, DetectResult &detect_result) = 0; 472 | }; 473 | 474 | /// @brief 动态权重调整接口 475 | class WeightAdjuster : public Plugin 476 | { 477 | public: 478 | /// @brief 析构函数 479 | virtual ~WeightAdjuster() {} 480 | 481 | /// @brief 通过配置进行初始化 482 | virtual ReturnCode Init(Config *config, Context *context) = 0; 483 | 484 | virtual ReturnCode RealTimeAdjustDynamicWeight(const InstanceGauge &instance_gauge, 485 | bool &need_adjuster) = 0; 486 | /// @brief 进行动态权重调整,返回调整后的动态权重 487 | /// 488 | /// @param service 服务信息 489 | /// @param stat_info 服务统计信息 490 | /// @return int 操作返回码 491 | virtual ReturnCode AdjustDynamicWeight(Service *service, const InstanceGauge &instance_gauge) = 0; 492 | }; 493 | 494 | /// @brief 扩展点接口:上报统计结果 495 | class StatReporter : public Plugin 496 | { 497 | public: 498 | /// @brief 析构函数 499 | virtual ~StatReporter() {} 500 | 501 | /// @brief 通过配置进行初始化 502 | virtual ReturnCode Init(Config *config, Context *context) = 0; 503 | 504 | /// @brief 执行统计数据上报 505 | /// 506 | /// @param stat 统计数据 507 | /// @return ReturnCode 执行结果 508 | virtual ReturnCode ReportStat(const InstanceGauge &instance_gauge) = 0; 509 | }; 510 | 511 | /// @brief 告警级别 512 | enum AlertLevel 513 | { 514 | kNormalAlert = 0, ///< 普通告警 515 | kCriticalAlert, ///< 严重告警 516 | kFatalAlert ///< 致命告警 517 | }; 518 | 519 | /// @brief 扩展点接口:上报告警信息 520 | class AlertReporter : public Plugin 521 | { 522 | public: 523 | /// @brief 析构函数 524 | virtual ~AlertReporter() {} 525 | 526 | /// @brief 通过配置进行初始化 527 | virtual ReturnCode Init(Config *config, Context *context) = 0; 528 | 529 | /// @brief 执行告警上报 530 | /// 531 | /// @param alert_level 告警级别 532 | /// @param msg 告警消息内容 533 | /// @return ReturnCode 执行结果 534 | virtual ReturnCode ReportAlert(AlertLevel alert_level, std::string msg) = 0; 535 | }; 536 | 537 | ///@brief 扩展点接口:收集北极星SDK调用服务器结果 538 | class ServerMetric : public Plugin 539 | { 540 | public: 541 | virtual ~ServerMetric() {} 542 | 543 | /// @brief 通过配置进行初始化 544 | virtual ReturnCode Init(Config *config, Context *context) = 0; 545 | 546 | /// @brief 内部服务调用结果上报 547 | /// 548 | /// @param service_key 服务 549 | /// @param instance 实例 550 | /// @param ret_code 返回码 551 | /// @param ret_status 是否成功 552 | /// @param daley 延迟 553 | virtual void MetricReport(const ServiceKey &service_key, const Instance &instance, 554 | ReturnCode ret_code, CallRetStatus ret_status, uint64_t daley) = 0; 555 | }; 556 | 557 | } // namespace polaris 558 | 559 | #endif // POLARIS_CPP_INCLUDE_POLARIS_PLUGIN_H_ 560 | -------------------------------------------------------------------------------- /include/polaris/polaris.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | /// \mainpage Polaris C++ API 15 | /// The Polaris C++ API mainly consists of the following classes: 16 | /// - Provider API: api for register/deregister/heartbeat service. 17 | /// - Consumer API: api for discover services. 18 | /// - Plugin Interfaces: interface for user define custom plugin. 19 | /// - Context: context contain plugins init from config. 20 | 21 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_POLARIS_H_ 22 | #define POLARIS_CPP_INCLUDE_POLARIS_POLARIS_H_ 23 | 24 | #include 25 | 26 | #include "polaris/accessors.h" 27 | #include "polaris/config.h" 28 | #include "polaris/consumer.h" 29 | #include "polaris/context.h" 30 | #include "polaris/defs.h" 31 | #include "polaris/log.h" 32 | #include "polaris/model.h" 33 | #include "polaris/plugin.h" 34 | #include "polaris/provider.h" 35 | 36 | namespace polaris { 37 | 38 | /// @brief 获取字符串形式的版本号 39 | std::string GetVersion(); 40 | 41 | /// @brief 获取字符串形式的版本信息 42 | std::string GetVersionInfo(); 43 | 44 | } // namespace polaris 45 | 46 | #endif // POLARIS_CPP_INCLUDE_POLARIS_POLARIS_H_ 47 | -------------------------------------------------------------------------------- /include/polaris/provider.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 2 | // 3 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file 4 | // except in compliance with the License. You may obtain a copy of the License at 5 | // 6 | // https://opensource.org/licenses/BSD-3-Clause 7 | // 8 | // Unless required by applicable law or agreed to in writing, software distributed 9 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 11 | // language governing permissions and limitations under the License. 12 | // 13 | 14 | #ifndef POLARIS_CPP_INCLUDE_POLARIS_PROVIDER_H_ 15 | #define POLARIS_CPP_INCLUDE_POLARIS_PROVIDER_H_ 16 | 17 | #include 18 | #include 19 | 20 | #include "defs.h" 21 | #include "noncopyable.h" 22 | 23 | namespace polaris { 24 | 25 | /// @brief 服务实例注册请求 26 | /// 27 | /// 用于向指定命令空间的服务注册服务实例。必须拥有服务token才能进行服务实例注册。 28 | /// 服务实例注册成功后,其他服务调用服务发现接口能发现该服务实例,可能会立即向该服务实例发送请求。 29 | /// @note 所以必须在服务实例启动完成后才去进行服务注册。 30 | class InstanceRegisterRequest : Noncopyable { 31 | public: 32 | /// @brief 构造服务实例注册请求对象 33 | /// 34 | /// @param service_namespace 服务名所属命名空间 35 | /// @param service_name 服务名 36 | /// @param service_token 服务名对应的token 37 | /// @param host 服务实例监听地址 38 | /// @param port 服务实例监听端口 39 | InstanceRegisterRequest(const std::string& service_namespace, const std::string& service_name, 40 | const std::string& service_token, const std::string& host, int port); 41 | 42 | /// @brief 析构服务实例注册请求对象 43 | ~InstanceRegisterRequest(); 44 | 45 | /// @brief 设置请求超时时间。可选,默认为SDK配置的API超时时间 46 | /// 47 | /// @param timeout 设置请求超时时间,可选,单位ms 48 | void SetTimeout(uint64_t timeout); 49 | 50 | /// @brief 设置服务实例的VPC ID。可选,默认为空 51 | /// 52 | /// @param vpc_id 服务实例的host:port所在vpc id 53 | void SetVpcId(const std::string& vpc_id); 54 | 55 | /// @brief 设置服务实例协议。可选,默认为空 56 | /// 57 | /// @param protocol 服务实例协议 58 | void SetProtocol(const std::string& protocol); 59 | 60 | /// @brief 设置服务实例权重。可选,默认为100 61 | /// 62 | /// @param weight 服务实例权重 63 | void SetWeight(int weight); 64 | 65 | /// @brief 设置服务实例优先级。可选,置默认为0 66 | /// 67 | /// @param priority 服务实例优先级 68 | void SetPriority(int priority); 69 | 70 | /// @brief 设置服务实例版本信息。可选,默认为空 71 | /// 72 | /// @param version 服务实例版本 73 | void SetVersion(const std::string& version); 74 | 75 | /// @brief 设置服务实例的metada数据。可选,默认为空 76 | /// 77 | /// @param metadata 服务实例metadata 78 | void SetMetadata(const std::map& metadata); 79 | 80 | /// @brief 设置服务实例是否开启健康检查。可选,默认不开启 81 | /// 82 | /// @param health_check_flag 83 | void SetHealthCheckFlag(bool health_check_flag); 84 | 85 | /// @brief 设置健康检查类型。可选,默认为心跳健康检查 86 | /// 87 | /// @param health_check_type 健康检查类型 88 | void SetHealthCheckType(HealthCheckType health_check_type); 89 | 90 | /// @brief 设置心跳健康检查ttl,单位为s,不填默认为5s, 91 | /// 92 | /// 开启了心跳健康检查,客户端必须以TTL间隔上报心跳 93 | /// 健康检查服务器3个TTL未受到心跳则将实例置为不健康 94 | /// @param ttl 心跳检查ttl 95 | void SetTtl(int ttl); 96 | 97 | /// @brief 设置请求流水号。可选,默认随机流水号 98 | /// 99 | /// @param flow_id 用于跟踪请求的流水号 100 | void SetFlowId(uint64_t flow_id); 101 | 102 | class Impl; 103 | Impl& GetImpl() const; 104 | 105 | private: 106 | Impl* impl_; 107 | }; 108 | 109 | /// @brief 服务实例反注册请求 110 | class InstanceDeregisterRequest : Noncopyable { 111 | public: 112 | /// @brief 构造服务实例反注册请求对象,使用服务实例ID表示服务实例 113 | /// 114 | /// @param service_token 服务token 115 | /// @param instance_id 服务实例ID 116 | InstanceDeregisterRequest(const std::string& service_token, const std::string& instance_id); 117 | 118 | /// @brief 119 | /// 构造服务实例反注册请求对象,使用服务实例四元组(命名空间,服务名,host,port)表示服务实例 120 | /// 121 | /// @param service_namespace 命名空间 122 | /// @param service_name 服务名 123 | /// @param service_token 服务token 124 | /// @param host 服务实例host 125 | /// @param port 服务实例port 126 | InstanceDeregisterRequest(const std::string& service_namespace, const std::string& service_name, 127 | const std::string& service_token, const std::string& host, int port); 128 | 129 | /// @brief 析构服务实例反注册请求对象 130 | ~InstanceDeregisterRequest(); 131 | 132 | /// @brief 设置请求超时时间。可选,默认为全局配置的API超时时间 133 | /// 134 | /// @param timeout 设置请求超时时间,可选,单位ms 135 | void SetTimeout(uint64_t timeout); 136 | 137 | /// @brief 设置服务实例的VPC ID 138 | /// 139 | /// @param vpc_id 服务实例的host:port所在vpc id 140 | void SetVpcId(const std::string& vpc_id); 141 | 142 | /// @brief 设置请求流水号。可选,默认随机流水号 143 | /// 144 | /// @param flow_id 用于跟踪请求的流水号 145 | void SetFlowId(uint64_t flow_id); 146 | 147 | class Impl; 148 | Impl& GetImpl() const; 149 | 150 | private: 151 | Impl* impl_; 152 | }; 153 | 154 | /// @brief 服务实例心跳上报请求 155 | class InstanceHeartbeatRequest : Noncopyable { 156 | public: 157 | /// @brief 构造服务实例心跳上报请求对象,使用服务实例ID表示服务实例 158 | /// 159 | /// @param service_token 服务token 160 | /// @param instance_id 服务实例ID 161 | InstanceHeartbeatRequest(const std::string& service_token, const std::string& instance_id); 162 | 163 | /// @brief 164 | /// 构造服务实例心跳上报请求对象,使用服务实例四元组(命名空间,服务名,host,port)表示服务实例 165 | /// 166 | /// @param service_namespace 命名空间 167 | /// @param service_name 服务名 168 | /// @param service_token 服务token 169 | /// @param host 服务实例host 170 | /// @param port 服务实例port 171 | InstanceHeartbeatRequest(const std::string& service_namespace, const std::string& service_name, 172 | const std::string& service_token, const std::string& host, int port); 173 | 174 | /// @brief 析构服务实例心跳上报请求对象 175 | ~InstanceHeartbeatRequest(); 176 | 177 | /// @brief 设置服务实例的VPC ID 178 | /// 179 | /// @param vpc_id 服务实例的host:port所在vpc id 180 | void SetVpcId(const std::string& vpc_id); 181 | 182 | /// @brief 设置请求流水号。可选,默认随机流水号 183 | /// 184 | /// @param flow_id 用于跟踪请求的流水号 185 | void SetFlowId(uint64_t flow_id); 186 | 187 | /// @brief 设置请求超时时间。可选,默认为全局配置的API超时时间 188 | /// 189 | /// @param timeout 设置请求超时时间,可选,单位ms 190 | void SetTimeout(uint64_t timeout); 191 | 192 | class Impl; 193 | Impl& GetImpl() const; 194 | 195 | private: 196 | Impl* impl_; 197 | }; 198 | 199 | /// @brief Provider异步接口回调函数 200 | class ProviderCallback { 201 | public: 202 | virtual ~ProviderCallback() {} 203 | 204 | /// @brief 应答回调 205 | /// 206 | /// @param code 返回码 207 | /// @param message 返回消息 208 | virtual void Response(ReturnCode code, const std::string& message) = 0; 209 | }; 210 | 211 | // forward declaration 212 | class Context; 213 | class Config; 214 | 215 | /// @brief Provider API 被调服务实例用于注册、反注册、心跳上报 216 | /// 217 | /// 服务启动后先进行注册,注册成功会返回服务实例ID。然后可使用该服务实例ID进行反注册和心跳上报 218 | /// @note 服务端接口必须在请求中传入服务token。服务token可在polaris 控制台上查看 219 | /// @note 该接口线程安全,整个进程创建一个即可 220 | class ProviderApi : Noncopyable { 221 | public: 222 | ~ProviderApi(); 223 | 224 | /// @brief 同步注册服务实例 225 | /// 226 | /// 服务注册成功后会填充instance中的instance_id字段,用户可保持该instance对象用于反注册和心跳上报 227 | /// 228 | /// @param req 实例注册请求 229 | /// @param instance_id 注册成功返回的服务实例ID 230 | /// @return ReturnCode 调用返回码 231 | /// kReturnOk 服务注册成功,instance_id有返回值 232 | /// kReturnExistedResource 服务实例已存在,instance_id有返回值 233 | /// 其他返回码表示服务注册失败 234 | ReturnCode Register(const InstanceRegisterRequest& req, std::string& instance_id); 235 | 236 | /// @brief 同步反注册服务实例 237 | /// 238 | /// @param req 服务实例反注册请求 239 | /// @return ReturnCode 调用返回码 240 | /// kReturnOk 表示服务反注册成功 241 | /// 其他返回码表示服务反注册失败 242 | ReturnCode Deregister(const InstanceDeregisterRequest& req); 243 | 244 | /// @brief 服务实例心跳上报 245 | /// 246 | /// @param req 服务实例心跳上报请求 247 | /// @return ReturnCode 调用返回码 248 | /// kReturnOk 表示心跳上报成功 249 | /// kRetrunRateLimit 表示服务心跳上报频率过快,程序应降低心跳上报频率 250 | /// kReturnServiceNotFound 如果刚刚注册即发起心跳上报可能返回服务不存在,重试即可 251 | /// 其他返回码表示心跳上报失败,可重试 252 | ReturnCode Heartbeat(const InstanceHeartbeatRequest& req); 253 | 254 | /// @brief 异步服务实例心跳上报 255 | /// 256 | /// @param req 服务实例心跳上报请求 257 | /// @param callback 请求回调 258 | /// @return ReturnCode 调用返回码 259 | /// kReturnOk 表示心跳上报成功 260 | ReturnCode AsyncHeartbeat(const InstanceHeartbeatRequest& req, ProviderCallback* callback); 261 | 262 | /// @brief 通过Context创建Provider API对象 263 | /// 264 | /// @param Context SDK上下文对象 265 | /// @return ProviderApi* 创建失败返回NULL 266 | static ProviderApi* Create(Context* Context); 267 | 268 | /// @brief 通过配置创建Provider API对象 269 | /// 270 | /// @param config 配置对象 271 | /// @return ProviderApi* 创建失败则返回NULL 272 | static ProviderApi* CreateFromConfig(Config* config); 273 | 274 | /// @brief 通过配置文件创建Provider API对象 275 | /// 276 | /// @param file 配置文件 277 | /// @return ProviderApi* 创建失败返回NULL 278 | static ProviderApi* CreateFromFile(const std::string& file); 279 | 280 | /// @brief 通过配置字符串创建Provider API对象 281 | /// 282 | /// @param content 配置字符串 283 | /// @return ProviderApi* 创建失败返回NULL 284 | static ProviderApi* CreateFromString(const std::string& content); 285 | 286 | /// @brief 从默认文件创建配置对象,默认文件为./polaris.yaml,文件不存在则使用默认配置 287 | /// 288 | /// @return ProviderApi* 创建失败返回NULL 289 | static ProviderApi* CreateWithDefaultFile(); 290 | 291 | class Impl; 292 | Impl& GetImpl() const; 293 | 294 | private: 295 | explicit ProviderApi(Impl* impl); 296 | 297 | Impl* impl_; 298 | }; 299 | 300 | } // namespace polaris 301 | 302 | #endif // POLARIS_CPP_INCLUDE_POLARIS_PROVIDER_H_ 303 | -------------------------------------------------------------------------------- /include/utils.hpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making polaris-go available. 2 | // 3 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 4 | // 5 | // Licensed under the BSD 3-Clause License (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // https://opensource.org/licenses/BSD-3-Clause 10 | // 11 | // Unless required by applicable law or agreed to in writing, software distributed 12 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | // specific language governing permissionsr and limitations under the License. 15 | // 16 | 17 | #ifndef _UTILS_H_ 18 | #define _UTILS_H_ 19 | 20 | extern "C" 21 | { 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include "php.h" 27 | #include "php_ini.h" 28 | #include "ext/standard/info.h" 29 | #include "php_polaris.h" 30 | } 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "common.hpp" 38 | 39 | static void PolarisOutputDebugString(zend_bool trigger_break, const char *format, ...) /* {{{ */ 40 | { 41 | va_list args; 42 | 43 | va_start(args, format); 44 | #ifdef ZEND_WIN32 45 | { 46 | char output_buf[1024]; 47 | 48 | vsnprintf(output_buf, 1024, format, args); 49 | OutputDebugString(output_buf); 50 | OutputDebugString("\n"); 51 | if (trigger_break && IsDebuggerPresent()) 52 | { 53 | DebugBreak(); 54 | } 55 | } 56 | #else 57 | vfprintf(stderr, format, args); 58 | fprintf(stderr, "\n"); 59 | #endif 60 | va_end(args); 61 | } 62 | 63 | static void PolarisHashDisplay(const HashTable *ht) 64 | { 65 | Bucket *p; 66 | uint i; 67 | 68 | if (UNEXPECTED(ht->nNumOfElements == 0)) 69 | { 70 | PolarisOutputDebugString(0, "The hash is empty"); 71 | return; 72 | } 73 | for (i = 0; i < ht->nNumUsed; ++i) 74 | { 75 | Bucket *b = &ht->arData[i]; 76 | if (Z_ISUNDEF(b->val)) 77 | { 78 | continue; 79 | } 80 | PolarisOutputDebugString(0, "%s <==> 0x%lX\n", b->key, b->val); 81 | } 82 | } 83 | 84 | /** 85 | * @brief 86 | * 87 | * @param metadata 88 | * @return map 89 | */ 90 | static zval TransferMapToArray(map metadata) 91 | { 92 | zval metadataArr; 93 | array_init(&metadataArr); 94 | 95 | if (metadata.size() == 0) 96 | { 97 | return metadataArr; 98 | } 99 | 100 | for (map::iterator iter = metadata.begin(); iter != metadata.end(); iter++) 101 | { 102 | // 这里直接忽略 key 为空的数据 103 | if (iter->first == "") 104 | { 105 | continue; 106 | } 107 | 108 | // char *valN = const_cast(iter->second.c_str()); 109 | add_assoc_string(&metadataArr, iter->first.c_str(), iter->second.c_str()); 110 | } 111 | 112 | return metadataArr; 113 | } 114 | 115 | static map TransferToStdMap(HashTable *ht) 116 | { 117 | if (UNEXPECTED(ht->nNumOfElements == 0) || ht == nullptr) 118 | { 119 | return map(); 120 | } 121 | map metadata = map(); 122 | 123 | uint32_t i; 124 | for (i = 0; i < ht->nNumUsed; ++i) 125 | { 126 | Bucket *b = &ht->arData[i]; 127 | if (Z_ISUNDEF(b->val)) 128 | { 129 | continue; 130 | } 131 | 132 | metadata.insert({string(ZSTR_VAL(b->key)), string(Z_STRVAL(b->val))}); 133 | } 134 | return metadata; 135 | } 136 | 137 | static uint getKeyLength(string val) 138 | { 139 | return val.length() + 1; 140 | } 141 | 142 | #endif -------------------------------------------------------------------------------- /polaris.class.php: -------------------------------------------------------------------------------- 1 | "./polaris.yaml", "log_dir" => "./"); 55 | protected $_polarisClient; 56 | 57 | /** 58 | * 构造方法 59 | * @param string $configPath yaml配置文件地址 60 | * @param string $logDir 日志地址 61 | * @return void 62 | */ 63 | public function __construct($configPath, $logDir) 64 | { 65 | if (empty($configPath)) { 66 | $configPath = $this->default_config["config_path"]; 67 | } 68 | if (empty($logDir)) { 69 | $logDir = $this->default_config["log_dir"]; 70 | } 71 | $this->_polarisClient = new PolarisClient(array("config_path" => $configPath, "log_dir" => $logDir)); 72 | $this->_polarisClient->InitProvider(); 73 | $this->_polarisClient->InitConsumer(); 74 | $this->_polarisClient->InitLimit(); 75 | } 76 | 77 | /** 78 | * 用于开启 PolarisClient的 ProviderAPI的相关能力 79 | * 注册服务实例 80 | * 反注册实例子 81 | * 上报服务实例心跳 82 | * @return void 83 | */ 84 | protected function InitProvider() 85 | { 86 | $this->_polarisClient->InitProvider(); 87 | } 88 | 89 | /** 90 | * 用于开启 PolarisClient的 ConsumerAPI的相关能力 91 | * 获取单个服务的一个实例 92 | * 获取单个服务的实例 93 | * 上报服务调用信息 94 | * @return void 95 | */ 96 | protected function InitConsumer() 97 | { 98 | $this->_polarisClient->InitConsumer(); 99 | } 100 | 101 | /** 102 | * 用于开启 PolarisClient的 LimitAPI的相关能力 103 | * 获取限流规则的配额信息 104 | * 查看当前限流结果 105 | * 更新请求配额调用结果 106 | * @return void 107 | */ 108 | protected function InitLimit() 109 | { 110 | $this->_polarisClient->InitLimit(); 111 | } 112 | 113 | /* ProviderAPI */ 114 | /** 115 | * 注册服务 116 | * @param int $timeout 超时时间,单位毫秒 117 | * @param int $flowId 本次请求的标识ID 118 | * @param array $instanceInfo = array( 119 | * "namespace" => "", //服务所在的命名空间 120 | * "service" => "", //服务名称 121 | * "host" => "", //实例的IP 122 | * "port" => "", //实例的端口,字符串数字: "100" 123 | * "protocol" => "", //实例端口的协议 124 | * "priority" => "", //实例优先级,字符串数字: "100" 125 | * "weight" => "", //实例的权重,字符串数字: "100" 126 | * "version" => "", //实例版本 127 | * "vpc_id" => "", //实例所在的VPC_ID信息 128 | * "heartbeat" => "", //是否开启心服务端对本实例执行跳健康检查,eg: "true" 129 | * "ttl" => "", //心跳间隔时间,单位为秒,仅在 heartbeat 为 true 下生效,eg: "100" 130 | * "metadata" => array(), //实例的标签信息 131 | * ) 132 | * 133 | * @return array $res = array( 134 | * "code" => 0, //方法执行状态码 135 | * "err_msg" => "", //错误信息 136 | * "instance_id" => "", //注册成功,实例的唯一ID标识 137 | * ) 138 | */ 139 | public function Register($instanceInfo, $timeout, $flowId) 140 | { 141 | return $this->_polarisClient->Register($instanceInfo, $timeout, $flowId); 142 | } 143 | 144 | /** 145 | * 提供实例反注册功能,即主动将该实例从北极星中彻底删除 146 | * @param int $timeout 超时时间,单位毫秒 147 | * @param int $flowId 本次请求的标识ID 148 | * @param array $instanceInfo = array( 149 | * "namespace" => "", //服务所在的命名空间 150 | * "service" => "", //服务名称 151 | * "host" => "", //实例的IP 152 | * "port" => "", //实例的端口,字符串数字: "100" 153 | * "vpc_id" => "", //实例所在的VPC_ID信息 154 | * ) 155 | * 156 | * @return array $res = array( 157 | * "code" => 0, //方法执行状态码 158 | * "err_msg" => "", //错误信息 159 | * ) 160 | */ 161 | public function Deregister($instanceInfo, $timeout, $flowId) 162 | { 163 | return $this->_polarisClient->Deregister($instanceInfo, $timeout, $flowId); 164 | } 165 | 166 | /** 167 | * 提供实例反注册功能,即主动将该实例从北极星中彻底删除 168 | * @param string $namespace 服务所在的命名空间 169 | * @param string $service 服务名称 170 | * @param string $host 实例的IP 171 | * @param string $port 实例的端口,字符串数字: "100" 172 | * @param string $vpcId 实例所在的VPC_ID信息 173 | * @return array 174 | */ 175 | public function Heartbeat($namespace, $service, $host, $port, $vpcId) 176 | { 177 | return $this->_polarisClient->Heartbeat(array( 178 | "namespace" => $namespace, 179 | "service" => $service, 180 | "host" => $host, 181 | "port" => $port, 182 | "vpc_id" => $vpcId, 183 | )); 184 | } 185 | 186 | /* ConsmerAPI */ 187 | /** 188 | * 用于提前初始化服务数据 189 | * @param int $timeout 超时时间,单位毫秒 190 | * @param int $flowId 本次请求的标识ID 191 | * @param array $instanceInfo = array( 192 | * "namespace" => "", //服务所在的命名空间 193 | * "service" => "", //服务名称 194 | * "version" => "", //实例版本 195 | * "vpc_id" => "", //实例所在的VPC_ID信息 196 | * "metadata" => array(), //设置元数据,用于元数据路由 197 | * "canary" => "", //设置调用哪个金丝雀服务实例 198 | * "source_set_name" => "", //设置调用哪个set下的服务 199 | * "ignore_half_open" => "true", //设置是否略过跳过半开探测节点,eg:"true" 200 | * "hash_string" => "", //设置 hash 字符串,用于一致性哈希负载均衡算法 201 | * "hash_key" => "", //设置hash key,用于一致性哈希负载均衡算法,eg:"123" 202 | * "replicate_index" => "", //用于一致性hash算法时获取副本实例,eg:"123" 203 | * "backup_instance_num" => "", //设置用于重试的实例数。可选,默认不返回用于重试的实例,eg:"123" 204 | * "load_balance_type" => Polaris::Balance_WeightedRandom, //设置负载均衡类型。可选,默认使用配置文件中设置的类型 205 | * "metadata_failover_type" => Polaris::Failover_None, //设置元数据路由匹配失败时的降级策略,默认不降级 206 | * "labels" = array(), //设置请求标签,用于接口级别熔断 207 | * "source" => array( //设置源服务信息,用于服务路由计算。可选 208 | * "namespace" => "", //实例的标签信息 209 | * "service" => "", //实例的标签信息 210 | * "metadata" => "", //实例的标签信息 211 | * ) 212 | * ) 213 | * 214 | * @return array $res = array( 215 | * "code" => 0, //方法执行状态码 216 | * "err_msg" => "", //错误信息 217 | * ) 218 | */ 219 | public function InitService($instanceInfo, $timeout, $flowId) 220 | { 221 | return $this->_polarisClient->InitService($instanceInfo, $timeout, $flowId); 222 | } 223 | 224 | 225 | /** 226 | * 用于提前初始化服务数据 227 | * @param int $timeout 超时时间,单位毫秒 228 | * @param int $flowId 本次请求的标识ID 229 | * @param array $instanceInfo = array( 230 | * "namespace" => "", //服务所在的命名空间 231 | * "service" => "", //服务名称 232 | * "version" => "", //实例版本 233 | * "vpc_id" => "", //实例所在的VPC_ID信息 234 | * "metadata" => array(), //设置元数据,用于元数据路由 235 | * "canary" => "", //设置调用哪个金丝雀服务实例 236 | * "source_set_name" => "", //设置调用哪个set下的服务 237 | * "ignore_half_open" => "true", //设置是否略过跳过半开探测节点,eg:"true" 238 | * "hash_string" => "", //设置 hash 字符串,用于一致性哈希负载均衡算法 239 | * "hash_key" => "", //设置hash key,用于一致性哈希负载均衡算法,eg:"123" 240 | * "replicate_index" => "", //用于一致性hash算法时获取副本实例,eg:"123" 241 | * "backup_instance_num" => "", //设置用于重试的实例数。可选,默认不返回用于重试的实例,eg:"123" 242 | * "load_balance_type" => Polaris::Balance_WeightedRandom, //设置负载均衡类型。可选,默认使用配置文件中设置的类型 243 | * "metadata_failover_type" => Polaris::Failover_None, //设置元数据路由匹配失败时的降级策略,默认不降级 244 | * "labels" = array(), //设置请求标签,用于接口级别熔断 245 | * "source" => array( //设置源服务信息,用于服务路由计算。可选 246 | * "namespace" => "", //实例的标签信息 247 | * "service" => "", //实例的标签信息 248 | * "metadata" => array(), //实例的标签信息 249 | * ) 250 | * ) 251 | * 252 | * @return array $res = array( 253 | * "code" => 0, //方法执行状态码 254 | * "err_msg" => "", //错误信息 255 | * "response" => array( 256 | * "flow_id" => 0, //请求流水号 257 | * "service" => "", //服务名 258 | * "namespace" => "", //命名空间 259 | * "revision" => "", //版本信息 260 | * "metadata" => array(), //服务元数据 261 | * "weight_type" => Polaris::Weight_Static, //权重类型 262 | * "subset" => array(), //实例所属的subset 263 | * "instances" => array( //服务实例列表 264 | * "instance_id" => "", //服务实例ID 265 | * "host" => "", //服务的节点IP或者域名 266 | * "port" => 32886, //节点端口号 267 | * "container_name" => "", //实例元数据信息中的容器名 268 | * "internal_set_name" => "", //实例元数据信息中的set名 269 | * "logic_set" => "", //实例LogicSet信息 270 | * "region" => "", //location region 271 | * "zone" => "", //location zone 272 | * "campus" => "", // location campus 273 | * "vpc_id" => "", //获取服务实例所在VPC ID 274 | * "protocol" => "", //实例协议信息 275 | * "version" => 1, //实例版本号信息 276 | * "weight" => 100, //实例静态权重值, 0-1000 277 | * "priority" => 888, //实例优先级 278 | * "dynamic_weight" => 123, //实例动态权重 279 | * "hash_key" => 0, //GetHash 280 | * "locality_aware_info" => 0, //locality_aware_info 281 | * "healthy" => true, //实例健康状态 282 | * "isola" => false, //实例隔离状态 283 | * "metadata" => array(), //实例元数据信息 284 | * ) 285 | * ) 286 | * ) 287 | */ 288 | public function GetOneInstance($instanceInfo, $timeout, $flowId) 289 | { 290 | return $this->_polarisClient->GetOneInstance($instanceInfo, $timeout, $flowId); 291 | } 292 | 293 | /** 294 | * 用于提前初始化服务数据 295 | * @param int $timeout 超时时间,单位毫秒 296 | * @param int $flowId 本次请求的标识ID 297 | * @param array $instanceInfo = array( 298 | * "namespace" => "", //服务所在的命名空间 299 | * "service" => "", //服务名称 300 | * "include_unhealthy_instances" => "true", //设置服务路由时否包含不健康的服务实例。可选,默认不包含, 字符串bool值:"true" 301 | * "include_circuit_breaker_instances" => "true", //设置服务路由时是否包含熔断的服务实例。可选,默认不包含, 字符串bool值:"true" 302 | * "skip_route_filter" => "true", //设置是否跳过服务路由。可选,默认不跳过服务路由, 字符串bool值:"true" 303 | * "canary" => "", //设置调用哪个金丝雀服务实例 304 | * "source_set_name" => "", //设置调用哪个set下的服务 305 | * "metadata_failover_type" => Polaris::Failover_None, //设置元数据路由匹配失败时的降级策略,默认不降级 306 | * "source" => array( //设置源服务信息,用于服务路由计算。可选 307 | * "namespace" => "", //实例的标签信息 308 | * "service" => "", //实例的标签信息 309 | * "metadata" => array(), //实例的标签信息 310 | * ) 311 | * ) 312 | * 313 | * @return array $res = array( 314 | * "code" => 0, //方法执行状态码 315 | * "err_msg" => "", //错误信息 316 | * "response" => array( 317 | * "flow_id" => 0, //请求流水号 318 | * "service" => "", //服务名 319 | * "namespace" => "", //命名空间 320 | * "revision" => "", //版本信息 321 | * "metadata" => array(), //服务元数据 322 | * "weight_type" => Polaris::Weight_Static, //权重类型 字符串 323 | * "subset" => array(), //实例所属的subset 324 | * "instances" => array( //服务实例列表 325 | * "instance_id" => "", //服务实例ID 326 | * "host" => "", //服务的节点IP或者域名 327 | * "port" => 32886, //节点端口号 328 | * "container_name" => "", //实例元数据信息中的容器名 329 | * "internal_set_name" => "", //实例元数据信息中的set名 330 | * "logic_set" => "", //实例LogicSet信息 331 | * "region" => "", //location region 332 | * "zone" => "", //location zone 333 | * "campus" => "", // location campus 334 | * "vpc_id" => "", //获取服务实例所在VPC ID 335 | * "protocol" => "", //实例协议信息 336 | * "version" => 1, //实例版本号信息 337 | * "weight" => 100, //实例静态权重值, 0-1000 338 | * "priority" => 888, //实例优先级 339 | * "dynamic_weight" => 123, //实例动态权重 340 | * "hash_key" => 0, //GetHash 341 | * "locality_aware_info" => 0, //locality_aware_info 342 | * "healthy" => true, //实例健康状态 343 | * "isola" => false, //实例隔离状态 344 | * "metadata" => array(), //实例元数据信息 345 | * ) 346 | * ) 347 | * ) 348 | */ 349 | public function GetInstances($instanceInfo, $timeout, $flowId) 350 | { 351 | return $this->_polarisClient->GetInstances($instanceInfo, $timeout, $flowId); 352 | } 353 | 354 | /** 355 | * 用于提前初始化服务数据 356 | * @param int $timeout 超时时间,单位毫秒 357 | * @param int $flowId 本次请求的标识ID 358 | * @param array $instanceInfo = array( 359 | * "namespace" => "", //服务所在的命名空间 360 | * "service" => "", //服务名称 361 | * "include_unhealthy_instances" => "true", //设置服务路由时否包含不健康的服务实例。可选,默认不包含, 字符串bool值:"true" 362 | * "include_circuit_breaker_instances" => "true", //设置服务路由时是否包含熔断的服务实例。可选,默认不包含, 字符串bool值:"true" 363 | * "skip_route_filter" => "true", //设置是否跳过服务路由。可选,默认不跳过服务路由, 字符串bool值:"true" 364 | * "canary" => "", //设置调用哪个金丝雀服务实例 365 | * "source_set_name" => "", //设置调用哪个set下的服务 366 | * "metadata_failover_type" => Polaris::Failover_None, //设置元数据路由匹配失败时的降级策略,默认不降级 367 | * "source" => array( //设置源服务信息,用于服务路由计算。可选 368 | * "namespace" => "", //实例的标签信息 369 | * "service" => "", //实例的标签信息 370 | * "metadata" => array(), //实例的标签信息 371 | * ) 372 | * ) 373 | * 374 | * @return array $res = array( 375 | * "code" => 0, //方法执行状态码 376 | * "err_msg" => "", //错误信息 377 | * "response" => array( 378 | * "flow_id" => 0, //请求流水号 379 | * "service" => "", //服务名 380 | * "namespace" => "", //命名空间 381 | * "revision" => "", //版本信息 382 | * "metadata" => array(), //服务元数据 383 | * "weight_type" => Polaris::Weight_Static, //权重类型 字符串 384 | * "subset" => array(), //实例所属的subset 385 | * "instances" => array( //服务实例列表 386 | * "instance_id" => "", //服务实例ID 387 | * "host" => "", //服务的节点IP或者域名 388 | * "port" => 32886, //节点端口号 389 | * "container_name" => "", //实例元数据信息中的容器名 390 | * "internal_set_name" => "", //实例元数据信息中的set名 391 | * "logic_set" => "", //实例LogicSet信息 392 | * "region" => "", //location region 393 | * "zone" => "", //location zone 394 | * "campus" => "", // location campus 395 | * "vpc_id" => "", //获取服务实例所在VPC ID 396 | * "protocol" => "", //实例协议信息 397 | * "version" => 1, //实例版本号信息 398 | * "weight" => 100, //实例静态权重值, 0-1000 399 | * "priority" => 888, //实例优先级 400 | * "dynamic_weight" => 123, //实例动态权重 401 | * "hash_key" => 0, //GetHash 402 | * "locality_aware_info" => 0, //locality_aware_info 403 | * "healthy" => true, //实例健康状态 404 | * "isola" => false, //实例隔离状态 405 | * "metadata" => array(), //实例元数据信息 406 | * ) 407 | * ) 408 | * ) 409 | */ 410 | public function GetAllInstances($instanceInfo, $timeout, $flowId) 411 | { 412 | return $this->_polarisClient->GetAllInstances($instanceInfo, $timeout, $flowId); 413 | } 414 | 415 | 416 | /** 417 | * 用于提前初始化服务数据 418 | * @param int $timeout 超时时间,单位毫秒 419 | * @param int $flowId 本次请求的标识ID 420 | * @param array $instanceInfo = array( 421 | * "namespace" => "", //服务所在的命名空间 422 | * "service" => "", //服务名称 423 | * "instance_id" => "", //服务实例ID 424 | * "host" => "true", //服务实例Host(可选,如果设置了服务实例ID,则这个可不设置,优先使用服务实例ID) 425 | * "port" => "200", //服务实例Port(可选,如果设置了服务实例ID,则这个可不设置,优先使用服务实例ID),字符串数字:"200" 426 | * "delay" => "200", //设置服务实例调用时延,字符串数字:"200" 427 | * "locality_aware_info" => "200", //设置需要传递的LocalityAware的信息,字符串数字:"200" 428 | * "ret_status" => Polaris::Ret_Status_OK, //调用返回状态 枚举字符串 429 | * "ret_code" => "", //设置调用返回码。可选,用于支持根据返回码实现自己的插件 430 | * "subset" => array(), //设置被调服务subset信息 431 | * "labels" => array(), //设置被调服务labels信息 432 | * ) 433 | * 434 | * @return array $res = array( 435 | * "code" => 0, //方法执行状态码 436 | * "err_msg" => "", //错误信息 437 | * ) 438 | */ 439 | public function UpdateServiceCallResult($instanceInfo, $timeout, $flowId) 440 | { 441 | return $this->_polarisClient->UpdateServiceCallResult($instanceInfo, $timeout, $flowId); 442 | } 443 | 444 | /* LimitAPI */ 445 | /** 446 | * 获取配额 447 | * @param string $namespace 被调服务所在的命名空间 448 | * @param string $service 被调服务所在的服务名称 449 | * @param string $amount 设置请求需要分配的配额数量,可选,默认为1, 字符串数字:100 450 | * @param array $labels 设置标签用于选择限流配置 451 | * @param array $subset 设置请求的所属服务子集,可选 452 | * 453 | * @return array $res = array( 454 | * "code" => 0, //方法执行状态码 455 | * "err_msg" => "", //错误信息 456 | * "quota_result" => array( //规则里配置的所有key 457 | * "wait_time" => 12345, //请求需要获取多长时间才能使用配额 458 | * "degrade" => false, //是否降级 459 | * "duration" => 3600, //配置周期 460 | * "quota_left" => 22, //剩余配额 461 | * "quota_all" => 11, //配置的配额 462 | * "quota_result_code" => 0, //配额获取结果(0:配额正常,1:配额被限流,2:需求需要等待重试) 463 | * ) 464 | * ) 465 | */ 466 | public function GetQuota($namespace, $service, $amount, $labels, $subset = array()) 467 | { 468 | return $this->_polarisClient->GetQuota(array( 469 | "namespace" => $namespace, 470 | "service" => $service, 471 | "amount" => (string)$amount, 472 | "labels" => $labels, 473 | "subset" => $subset, 474 | )); 475 | } 476 | 477 | /** 478 | * 更新请求配额调用结果 479 | * @param string $namespace 命名空间 480 | * @param string $service 服务名称 481 | * @param string $response_time 请求响应时间,字符串数字:"1000" 482 | * @param string $respont_type Polaris::Respont_Type_Limit | Polaris::Respont_Type_Failed | Polaris::Respont_Type_OK 483 | * @param int $respont_code 本次请求的标识ID 484 | * @param array $labels 设置标签用于选择限流配置 485 | * @param array $subset 设置请求的所属服务子集,可选 486 | * 487 | * @return array $res = array( 488 | * "code" => 0, //方法执行状态码 489 | * "err_msg" => "", //错误信息 490 | * ) 491 | */ 492 | public function UpdateCallResult($namespace, $service, $response_time, $respont_type, $respont_code, $labels, $subset = array()) 493 | { 494 | return $this->_polarisClient->UpdateCallResult(array( 495 | "namespace" => $namespace, 496 | "service" => $service, 497 | "response_time" => (string)$response_time, 498 | "respont_code" => $respont_code, 499 | "respont_type" => $respont_type, 500 | "labels" => $labels, 501 | "subset" => $subset, 502 | )); 503 | } 504 | 505 | /** 506 | * 初始化配额窗口,可选调用,用于提前初始化配窗口减小首次配额延迟 507 | * @param string $namespace 被调服务所在的命名空间 508 | * @param string $service 被调服务所在的服务名称 509 | * @param string $amount 设置请求需要分配的配额数量,可选,默认为1, 字符串数字:100 510 | * @param array $labels 设置标签用于选择限流配置 511 | * @param array $subset 设置请求的所属服务子集,可选 512 | * 513 | * @return array $res = array( 514 | * "code" => 0, //方法执行状态码 515 | * "err_msg" => "", //错误信息 516 | * ) 517 | */ 518 | public function InitQuotaWindow($namespace, $service, $amount, $labels, $subset = array()) 519 | { 520 | return $this->_polarisClient->InitQuotaWindow(array( 521 | "namespace" => $namespace, 522 | "service" => $service, 523 | "amount" => (string)$amount, 524 | "labels" => $labels, 525 | "subset" => $subset, 526 | )); 527 | } 528 | } -------------------------------------------------------------------------------- /polaris.yaml.template: -------------------------------------------------------------------------------- 1 | #配置模板,不要直接使用 2 | #不传配置文件或传空的配置文件,SDK会使用默认配置初始化,根据需要传入配置覆盖默认配置项 3 | #描述:全局配置 4 | global: 5 | #描述系统相关配置 6 | system: 7 | #服务发现集群 8 | discoverCluster: 9 | namespace: Polaris 10 | service: polaris.discover 11 | #可选:服务刷新间隔 12 | refreshInterval: 10m 13 | #健康检查集群 14 | healthCheckCluster: 15 | namespace: Polaris 16 | service: polaris.healthcheck 17 | #可选:服务刷新间隔 18 | refreshInterval: 10m 19 | #监控上报集群 20 | monitorCluster: 21 | namespace: Polaris 22 | service: polaris.monitor 23 | #可选:服务刷新间隔 24 | refreshInterval: 10m 25 | # 限流统计集群 26 | metricCluster: 27 | namespace: Polaris 28 | service: polaris.metric 29 | refreshInterval: 10m 30 | #描述:对外API相关配置 31 | api: 32 | #描述:SDK绑定的网卡地址, 33 | #类型:string 34 | bindIf: eth1 35 | #描述:SDK绑定的IP地址, 36 | #类型:string 37 | #特殊说明:假如不传,则SDK通过bindIf的网卡名取地址,假如bindIf为空,则通过tcp连接的localAddress来获取地址 38 | bindIP: 192.168.1.2 39 | #描述:api超时时间 40 | #类型:string 41 | #格式:^\d+(ms|s|m|h)$ 42 | #范围:[1ms:...] 43 | #默认值:1s 44 | timeout: 1s 45 | #描述:API因为网络原因调用失败后的重试次数 46 | #类型:int 47 | #范围:[0:...] 48 | #默认值: 3 49 | maxRetryTimes: 3 50 | #描述:重试间隔 51 | #类型:string 52 | #格式:^\d+(ms|s|m|h)$ 53 | #范围:[1s:...] 54 | #默认值:1s 55 | retryInterval: 1s 56 | #描述:SDK的离线地域信息,假如server没有返回正确的地域信息,则使用离线地域信息 57 | #location: 58 | #描述:大区 59 | #类型:string 60 | #region: south-china 61 | #描述:区域 62 | #类型:string 63 | #zone: shenzhen 64 | #描述:园区 65 | #类型:string 66 | #campus: longgang 67 | #描述:对接polaris server的相关配置 68 | serverConnector: 69 | #描述:server列表,由于SDK在运行过程中可以通过接口定时拉取最新server列表,因此这里填的是初始的地址 70 | #类型:list 71 | #默认值:代理模式,默认为127.0.0.1:8888(本地agent地址);直连模式,无默认值 72 | addresses: 73 | - 127.0.0.1:8081 # 埋点地址 74 | #描述:访问server的连接协议,SDK会根据协议名称会加载对应的插件 75 | #类型:string 76 | #范围:已注册的连接器插件名 77 | #默认值:grpc 78 | protocol: grpc 79 | #描述:发起连接后的连接超时时间 80 | #类型:string 81 | #格式:^\d+(ms|s|m|h)$ 82 | #范围:[1ms:...] 83 | #默认值:200ms 84 | connectTimeout: 200ms 85 | #描述:连接空闲时间,长连接模式下,当连接空闲超过一定时间后,SDK会主动释放连接 86 | #类型:string 87 | #格式:^\d+(ms|s|m|h)$ 88 | #范围:[1ms:...] 89 | #默认值:500ms 90 | connectionIdleTimeout: 500ms 91 | #描述:远程请求超时时间 92 | #类型:string 93 | #格式:^\d+(ms|s|m|h)$ 94 | #范围:[1ms:...] 95 | #默认值:1s 96 | messageTimeout: 1s 97 | #描述:首次请求的任务队列长度,当用户发起首次服务访问请求时,SDK会对任务进行队列调度并连接server,当积压的任务数超过队列长度后,SDK会直接拒绝首次请求的发起。 98 | #类型:int 99 | #范围:[0:...] 100 | #默认值:1000 101 | requestQueueSize: 1000 102 | #描述:server节点的切换周期,为了使得server的压力能够均衡,SDK会定期针对最新的节点列表进行重新计算自己当前应该连接的节点,假如和当前不一致,则进行切换 103 | #类型:string 104 | #格式:^\d+(ms|s|m|h)$ 105 | #范围:[1m:...] 106 | #默认值:10m 107 | serverSwitchInterval: 10m 108 | #统计上报设置 109 | statReporter: 110 | #描述:是否将统计信息上报至monitor 111 | #类型:bool 112 | #默认值:true 113 | enable: true 114 | #描述:启用的统计上报插件类型 115 | #类型:list 116 | #范围:已经注册的统计上报插件的名字 117 | #默认值:stat2Monitor(将信息上报至monitor服务) 118 | chain: 119 | - stat2Monitor 120 | #描述:统计上报插件配置 121 | plugin: 122 | stat2Monitor: 123 | #描述:每次上报多长一段时间的统计信息 124 | #类型:string 125 | #格式:^\d+(ms|s|m|h)$ 126 | #范围:[1m:...] 127 | metricsReportWindow: 1m 128 | #描述:将一段时间内的统计信息分为多少个基本单元收集 129 | #类型:int 130 | #范围:[1:...] 131 | #默认值:12 132 | metricsNumBuckets: 12 133 | #描述:主调端配置 134 | consumer: 135 | #描述:本地缓存相关配置 136 | localCache: 137 | #描述:缓存类型 138 | #类型:string 139 | #范围:已注册的本地缓存插件名 140 | #默认值:inmemory(基于本机内存的缓存策略) 141 | type: inmemory 142 | #描述:服务定期刷新周期 143 | #类型:string 144 | #格式:^\d+(ms|s|m|h)$ 145 | #范围:[1s:...] 146 | #默认值:2s 147 | serviceRefreshInterval: 2s 148 | #描述:服务过期淘汰时间 149 | #类型:string 150 | #格式:^\d+(ms|s|m|h)$ 151 | #范围:[1m:...] 152 | #默认值:24h 153 | serviceExpireTime: 24h 154 | #描述:服务缓存持久化目录,SDK在实例数据更新后,按照服务维度将数据持久化到磁盘 155 | #类型:string 156 | #格式:本机磁盘目录路径,支持$HOME变量 157 | #默认值:$HOME/polaris/backup 158 | persistDir: $HOME/polaris/backup 159 | #描述:缓存写盘失败的最大重试次数 160 | #类型:int 161 | #范围:[1:...] 162 | #默认值:5 163 | persistMaxWriteRetry: 5 164 | #描述:缓存从磁盘读取失败的最大重试次数 165 | #类型:int 166 | #范围:[1:...] 167 | #默认值:1 168 | persistMaxReadRetry: 1 169 | #描述:缓存读写磁盘的重试间隔 170 | #类型:string 171 | #格式:^\d+(ms|s|m|h)$ 172 | #范围:[1ms:...] 173 | #默认值:1s 174 | persistRetryInterval: 1s 175 | #描述:节点熔断相关配置 176 | circuitBreaker: 177 | #描述:是否启用节点熔断功能 178 | #类型:bool 179 | #默认值:true 180 | enable: true 181 | #描述:实例定时熔断检测周期 182 | #类型:string 183 | #格式:^\d+(ms|s|m|h)$ 184 | #范围:[100ms:...] 185 | #默认值:500ms 186 | checkPeriod: 500ms 187 | #描述:熔断策略,SDK会根据策略名称加载对应的熔断器插件 188 | #类型:list 189 | #范围:已注册的熔断器插件名 190 | #默认值:基于周期连续错误数熔断(errorCount)、以及基于周期错误率的熔断策略(errorRate) 191 | chain: 192 | - errorCount 193 | - errorRate 194 | #描述:熔断插件配置 195 | plugin: 196 | #描述:基于周期连续错误数熔断策略配置 197 | errCount: 198 | #描述:触发连续错误熔断的阈值 199 | #类型:int 200 | #范围:[1:...] 201 | #默认值:10 202 | continuousErrorThreshold: 10 203 | #描述:连续失败的统计周期 204 | #类型:string 205 | #格式:^\d+(ms|s|m|h)$ 206 | #范围:[10ms:...] 207 | #默认值:1m 208 | metricStatTimeWindow: 1m 209 | #描述:熔断器半开后最大允许的请求数 210 | #类型:int 211 | #范围:[3:...] 212 | #默认值:3 213 | requestCountAfterHalfOpen: 3 214 | #描述:熔断器打开后,多久后转换为半开状态 215 | #类型:string 216 | #格式:^\d+(ms|s|m|h)$ 217 | #范围:[1s:...] 218 | #默认值:3s 219 | sleepWindow: 5s 220 | #描述:熔断器半开到关闭所必须的最少成功请求数 221 | #类型:int 222 | #范围:[1:requestCountAfterHalfOpen] 223 | #默认值:2 224 | successCountAfterHalfOpen: 2 225 | #描述:基于周期错误率的熔断策略配置 226 | errRate: 227 | #描述:触发错误率熔断的最低请求阈值 228 | #类型:int 229 | #范围:(0:...] 230 | #默认值:10 231 | requestVolumeThreshold: 10 232 | #描述:触发错误率熔断的阈值 233 | #类型:double 234 | #范围:(0:1] 235 | #默认值:0.5 236 | errorRateThreshold: 0.5 237 | #描述:错误率熔断的统计周期 238 | #类型:string 239 | #格式:^\d+(ms|s|m|h)$ 240 | #范围:[1s:...] 241 | #默认值:1m 242 | metricStatTimeWindow: 1m 243 | #描述:错误率熔断的最小统计单元数量 244 | #类型:int 245 | #范围:[1:...] 246 | #默认值:12 247 | metricNumBuckets: 12 248 | #描述:熔断器半开后最大允许的请求数 249 | #类型:int 250 | #范围:[3:...] 251 | #默认值:3 252 | requestCountAfterHalfOpen: 3 253 | #描述:熔断器打开后,多久后转换为半开状态 254 | #类型:string 255 | #格式:^\d+(ms|s|m|h)$ 256 | #范围:[1s:...] 257 | #默认值:3s 258 | sleepWindow: 5s 259 | #描述:熔断器半开到关闭所必须的最少成功请求数 260 | #类型:int 261 | #范围:[1:requestCountAfterHalfOpen] 262 | #默认值:2 263 | successCountAfterHalfOpen: 2 264 | #描述: set(集群)熔断相关配置 265 | setCircuitBreaker: 266 | enable: false 267 | #描述:故障探测相关配置 268 | healthCheck: 269 | #描述:是否启用故障探测功能 270 | #类型:bool 271 | #默认值:true 272 | enable: true 273 | #描述:定时故障探测周期 274 | #类型:string 275 | #格式:^\d+(ms|s|m|h)$ 276 | #范围:[1s:...] 277 | #默认值:10s 278 | checkPeriod: 10s 279 | #描述:故障探测策略,SDK会根据策略名称加载对应的探测器插件 280 | #类型:list 281 | #范围:已注册的探测器插件名 282 | #默认值:基于tcp协议的探测器 283 | chain: 284 | - tcp 285 | #描述:故障探测插件配置 286 | plugin: 287 | #描述:基于TCP的故障探测策略 288 | tcp: 289 | #描述:探测超时时间 290 | #类型:string 291 | #格式:^\d+(ms|s|m|h)$ 292 | #范围:[10ms:100ms] 293 | #默认值:100ms 294 | timeout: 100ms 295 | #描述:探测失败重试次数 296 | #类型:int 297 | #范围:[0:...] 298 | #默认值:0 299 | retry: 0 300 | #描述:tcp发送的探测包,可选字段,假如不配置,则默认只做连接探测 301 | #类型:string 302 | #格式:^0x[1-9A-Fa-f]+$ 303 | send: 0xEEEEEEEE 304 | #描述:期望接收的TCP回复包,可选字段,假如不配置,则默认只做连接或发包探测 305 | #类型:string 306 | #格式:^0x[1-9A-Fa-f]+$ 307 | receive: 0xFFFFFFF 308 | #描述:基于TCP的故障探测策略 309 | udp: 310 | #描述:探测超时时间 311 | #类型:string 312 | #格式:^\d+(ms|s|m|h)$ 313 | #范围:[10ms:100ms] 314 | #默认值:100ms 315 | timeout: 100ms 316 | #描述:探测失败重试次数 317 | #类型:int 318 | #范围:[0:...] 319 | #默认值:0 320 | retry: 0 321 | #描述:udp发送的探测包,必选字段,假如不配置,则不启动UDP探测 322 | #类型:string 323 | #格式:^0x[1-9A-Fa-f]+$ 324 | send: 0xEEEEEEEE 325 | #描述:期望接收的UDP回复包,必选字段,假如不配置,则不启动UDP探测 326 | #类型:string 327 | #格式:^0x[1-9A-Fa-f]+$ 328 | receive: 0xFFFFFFF 329 | http: 330 | #描述:探测超时时间 331 | #类型:string 332 | #格式:^\d+(ms|s|m|h)$ 333 | #范围:[10ms:100ms] 334 | #默认值:100ms 335 | timeout: 100ms 336 | #描述:http探测路径,必选字段,假如不配置,则不启用http探测 337 | #类型:string 338 | #范围:^/.+$ 339 | path: /ping 340 | #描述:负载均衡相关配置 341 | loadBalancer: 342 | #描述:负载均衡类型 343 | #范围:已注册的负载均衡插件名 344 | #默认值:权重随机负载均衡 345 | type: weightedRandom 346 | #描述:服务路由相关配置 347 | serviceRouter: 348 | # 服务路由链 349 | chain: 350 | # 基于主调和被调服务规则的路由策略(默认的路由策略) 351 | - ruleBasedRouter 352 | # 就近路由策略 353 | - nearbyBasedRouter 354 | #描述:服务路由插件的配置 355 | plugin: 356 | nearbyBasedRouter: 357 | #描述:就近路由的最小匹配级别 358 | #类型:string 359 | #范围:region(大区)、zone(区域)、campus(园区) 360 | #默认值:zone 361 | matchLevel: zone 362 | # 就近路由最大的匹配级别 363 | maxMatchLevel: none 364 | # 是否启用按服务不健康实例比例进行降级 365 | enableDegradeByUnhealthyPercent: true 366 | # 需要进行降级的实例比例,不健康实例达到百分之多少才进行降级。值(0, 100]。 367 | # 默认100,即全部不健康才进行切换。 368 | unhealthyPercentToDegrade: 100 369 | # 允许全死全活 370 | enableRecoverAll: true 371 | rateLimiter: 372 | # global:默认值,该模式表示会使用分布式限流,必须填写rateLimitCluster。 373 | # local:表示只会使用本地限流,不会使用分布式限流,可不填rateLimitCluster 374 | mode: local 375 | # global模式必填,分布式限流时用于发现限流服务器 376 | rateLimitCluster: 377 | # 限流服务器集群所在命名空间 378 | namespace: Polaris 379 | # 限流服务器集群名字 380 | service: poalris.metirc.xxx.yyy 381 | -------------------------------------------------------------------------------- /polaris/.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | *.lo 3 | *.la 4 | .libs 5 | acinclude.m4 6 | aclocal.m4 7 | autom4te.cache 8 | build 9 | config.guess 10 | config.h 11 | config.h.in 12 | config.log 13 | config.nice 14 | config.status 15 | config.sub 16 | configure 17 | configure.in 18 | include 19 | install-sh 20 | libtool 21 | ltmain.sh 22 | Makefile 23 | Makefile.fragments 24 | Makefile.global 25 | Makefile.objects 26 | missing 27 | mkinstalldirs 28 | modules 29 | run-tests.php 30 | tests/*/*.diff 31 | tests/*/*.out 32 | tests/*/*.php 33 | tests/*/*.exp 34 | tests/*/*.log 35 | tests/*/*.sh 36 | -------------------------------------------------------------------------------- /polaris/CREDITS: -------------------------------------------------------------------------------- 1 | polaris_provider -------------------------------------------------------------------------------- /polaris/EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polaris-contrib/polaris-php/79ef1cc1e6800b0eed280288de39f82a2260a2be/polaris/EXPERIMENTAL -------------------------------------------------------------------------------- /polaris/build_php74.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf /root/corefile/core-* 4 | 5 | test_module=$1 6 | 7 | /usr/local/php74/bin/phpize --clean 8 | 9 | /usr/local/php74/bin/phpize 10 | 11 | ./configure --with-php-config=/usr/local/php74/bin/php-config --with-polaris 12 | 13 | make && make install 14 | -------------------------------------------------------------------------------- /polaris/common.hpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making polaris-go available. 2 | // 3 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 4 | // 5 | // Licensed under the BSD 3-Clause License (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // https://opensource.org/licenses/BSD-3-Clause 10 | // 11 | // Unless required by applicable law or agreed to in writing, software distributed 12 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | // specific language governing permissionsr and limitations under the License. 15 | // 16 | 17 | #ifndef _COMMON_POLARIS_PHP_H_ 18 | #define _COMMON_POLARIS_PHP_H_ 19 | 20 | extern "C" 21 | { 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include "php.h" 27 | #include "php_ini.h" 28 | #include "ext/standard/info.h" 29 | #include "php_polaris.h" 30 | } 31 | 32 | #include 33 | 34 | // Polaris 创建时的参数key名称 35 | string ConfigPath = "config_path"; 36 | string LogDir = "log_dir"; 37 | 38 | // Polaris 一些元数据信息 39 | string Namespace = "namespace"; 40 | string Service = "service"; 41 | string Protocol = "protocol"; 42 | string Version = "version"; 43 | string Token = "token"; 44 | string Ttl = "ttl"; 45 | string Host = "host"; 46 | string Port = "port"; 47 | string Weight = "weight"; 48 | string Priority = "priority"; 49 | string Metadata = "metadata"; 50 | string SourceMetadata = "source_metadata"; 51 | string VpcID = "vpc_id"; 52 | string HeartbeatFlag = "heartbeat"; 53 | string Canary = "canary"; 54 | string IgnoreHalfOpen = "ignore_half_open"; 55 | string IncludeUnhealthyInstances = "include_unhealthy_instances"; 56 | string IncludeCircuitBreakInstances = "include_circuit_breaker_instances"; 57 | string SkipRouteFilter = "skip_route_filter"; 58 | string SourceService = "source_service"; 59 | string SourceSetName = "source_set_name"; 60 | string HashKey = "hash_key"; 61 | string HashString = "hash_string"; 62 | string Labels = "labels"; 63 | string ReplicateIndex = "replicate_index"; 64 | string BackupInstanceNum = "backup_instance_num"; 65 | string MetadataFailoverTypeStr = "metadata_failover_type"; 66 | string FlowId = "flow_id"; 67 | string Revision = "revision"; 68 | string WeightTypeStr = "weigth_type"; 69 | string ContainerName = "container_name"; 70 | string InternalSetName = "internal_set_name"; 71 | string LogicSet = "logic_set"; 72 | string Region = "region"; 73 | string Zone = "zone"; 74 | string Campus = "campus"; 75 | string LocalityAwareInfo = "locality_aware_info"; 76 | string DynamicWeight = "dynamic_weight"; 77 | string Healthy = "healthy"; 78 | string Isolate = "isolate"; 79 | string Delay = "delay"; 80 | string CallRetStatus = "ret_status"; 81 | string CallRetCode = "ret_code"; 82 | string Amount = "amount"; 83 | string Instances = "instances"; 84 | string GetResponse = "response"; 85 | string ServiceSubSet = "subset"; 86 | string RuleKeys = "rule_keys"; 87 | string LimitLabelKeys = "limit_label_keys"; 88 | string CallResponseType = "response_type"; 89 | string CallResponseTime = "response_time"; 90 | string CallResponseCode = "response_code"; 91 | string LoadBalanceTypeStr = "load_balance_type"; 92 | string kLoadBalanceTypeWeightedRandomStr = "weightedRandom"; 93 | string kLoadBalanceTypeRingHashStr = "ringHash"; 94 | string kLoadBalanceTypeMaglevHashStr = "maglev"; 95 | string kLoadBalanceTypeL5CstHashStr = "l5cst"; 96 | string kLoadBalanceTypeSimpleHashStr = "simpleHash"; 97 | string kLoadBalanceTypeCMurmurHashStr = "cMurmurHash"; 98 | string kLoadBalanceTypeLocalityAwareStr = "localityAware"; 99 | string kLoadBalanceTypeDefaultConfigStr = "default"; 100 | // Polaris 返回信息的一些key 101 | string Code = "code"; 102 | string ErrMsg = "err_msg"; 103 | string InstanceID = "instance_id"; 104 | 105 | // 与限流相关的 key 106 | string LimitRuleJsonStr = "limit_rule_json_str"; 107 | string ResultForQuota = "quota_result"; 108 | string ResultCodeForQuota = "quota_result_code"; 109 | string ResultInfoForQuota = "quota_result_info"; 110 | string LeftQuota = "quota_left"; 111 | string AllQuota = "quota_all"; 112 | string DurationForQuota = "quota_duration"; 113 | string IsDegrade = "degrade"; 114 | string WaitTimeForQuota = "wait_time"; 115 | 116 | #endif -------------------------------------------------------------------------------- /polaris/config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_WITH(polaris, for polaris support, 2 | dnl Make sure that the comment is aligned: 3 | [ --with-polaris Include polaris support]) 4 | 5 | if test "$PHP_polaris" != "no"; then 6 | PHP_REQUIRE_CXX() 7 | PHP_ADD_LIBRARY(stdc++, 1, EXTRA_LDFLAGS) 8 | 9 | PHP_ADD_INCLUDE(../include) 10 | 11 | PHP_ADD_LIBRARY(stdc++, 1, POLARIS_SHARED_LIBADD) 12 | PHP_ADD_LIBRARY_WITH_PATH(polaris_api, "../lib", POLARIS_SHARED_LIBADD) 13 | PHP_ADD_LIBRARY(protobuf, "../lib", POLARIS_SHARED_LIBADD) 14 | 15 | dnl PHP_ADD_LIBRARY_WITH_PATH(polaris_api, "../lib", EXTRA_LDFLAGS) 16 | dnl PHP_ADD_LIBRARY_WITH_PATH(protobuf, "../lib", EXTRA_LDFLAGS) 17 | 18 | PHP_SUBST(POLARIS_SHARED_LIBADD) 19 | 20 | PHP_NEW_EXTENSION(polaris, polaris.cpp, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) 21 | fi 22 | -------------------------------------------------------------------------------- /polaris/config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | // If your extension references something external, use ARG_WITH 5 | // ARG_WITH("polaris", "for polaris support", "no"); 6 | 7 | // Otherwise, use ARG_ENABLE 8 | // ARG_ENABLE("polaris", "enable polaris support", "no"); 9 | 10 | if (PHP_POLARIS != "no") { 11 | EXTENSION("polaris", "polaris.cpp"); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /polaris/configure.ac: -------------------------------------------------------------------------------- 1 | dnl This file becomes configure.ac for self-contained extensions. 2 | 3 | dnl Include external macro definitions before the AC_INIT to also remove 4 | dnl comments starting with # and empty newlines from the included files. 5 | m4_include([build/ax_check_compile_flag.m4]) 6 | m4_include([build/ax_gcc_func_attribute.m4]) 7 | m4_include([build/libtool.m4]) 8 | m4_include([build/php_cxx_compile_stdcxx.m4]) 9 | m4_include([build/php.m4]) 10 | m4_include([build/pkg.m4]) 11 | 12 | AC_PREREQ([2.68]) 13 | AC_INIT 14 | AC_CONFIG_SRCDIR([config.m4]) 15 | AC_CONFIG_AUX_DIR([build]) 16 | AC_PRESERVE_HELP_ORDER 17 | 18 | PHP_CONFIG_NICE(config.nice) 19 | 20 | AC_DEFUN([PHP_EXT_BUILDDIR],[.])dnl 21 | AC_DEFUN([PHP_EXT_DIR],[""])dnl 22 | AC_DEFUN([PHP_EXT_SRCDIR],[$abs_srcdir])dnl 23 | AC_DEFUN([PHP_ALWAYS_SHARED],[ 24 | ext_output="yes, shared" 25 | ext_shared=yes 26 | test "[$]$1" = "no" && $1=yes 27 | ])dnl 28 | 29 | test -z "$CFLAGS" && auto_cflags=1 30 | 31 | abs_srcdir=`(cd $srcdir && pwd)` 32 | abs_builddir=`pwd` 33 | 34 | PKG_PROG_PKG_CONFIG 35 | AC_PROG_CC([cc gcc]) 36 | PHP_DETECT_ICC 37 | PHP_DETECT_SUNCC 38 | 39 | dnl Support systems with system libraries in e.g. /usr/lib64. 40 | PHP_ARG_WITH([libdir], 41 | [for system library directory], 42 | [AS_HELP_STRING([--with-libdir=NAME], 43 | [Look for libraries in .../NAME rather than .../lib])], 44 | [lib], 45 | [no]) 46 | 47 | PHP_RUNPATH_SWITCH 48 | PHP_SHLIB_SUFFIX_NAMES 49 | 50 | dnl Find php-config script. 51 | PHP_ARG_WITH([php-config],, 52 | [AS_HELP_STRING([--with-php-config=PATH], 53 | [Path to php-config [php-config]])], 54 | [php-config], 55 | [no]) 56 | 57 | dnl For BC. 58 | PHP_CONFIG=$PHP_PHP_CONFIG 59 | prefix=`$PHP_CONFIG --prefix 2>/dev/null` 60 | phpincludedir=`$PHP_CONFIG --include-dir 2>/dev/null` 61 | INCLUDES=`$PHP_CONFIG --includes 2>/dev/null` 62 | EXTENSION_DIR=`$PHP_CONFIG --extension-dir 2>/dev/null` 63 | PHP_EXECUTABLE=`$PHP_CONFIG --php-binary 2>/dev/null` 64 | 65 | if test -z "$prefix"; then 66 | AC_MSG_ERROR([Cannot find php-config. Please use --with-php-config=PATH]) 67 | fi 68 | 69 | php_shtool=$srcdir/build/shtool 70 | PHP_INIT_BUILD_SYSTEM 71 | 72 | AC_MSG_CHECKING([for PHP prefix]) 73 | AC_MSG_RESULT([$prefix]) 74 | AC_MSG_CHECKING([for PHP includes]) 75 | AC_MSG_RESULT([$INCLUDES]) 76 | AC_MSG_CHECKING([for PHP extension directory]) 77 | AC_MSG_RESULT([$EXTENSION_DIR]) 78 | AC_MSG_CHECKING([for PHP installed headers prefix]) 79 | AC_MSG_RESULT([$phpincludedir]) 80 | 81 | dnl Checks for PHP_DEBUG / ZEND_DEBUG / ZTS. 82 | AC_MSG_CHECKING([if debug is enabled]) 83 | old_CPPFLAGS=$CPPFLAGS 84 | CPPFLAGS="-I$phpincludedir" 85 | AC_EGREP_CPP(php_debug_is_enabled,[ 86 | #include
87 | #if ZEND_DEBUG 88 | php_debug_is_enabled 89 | #endif 90 | ],[ 91 | PHP_DEBUG=yes 92 | ],[ 93 | PHP_DEBUG=no 94 | ]) 95 | CPPFLAGS=$old_CPPFLAGS 96 | AC_MSG_RESULT([$PHP_DEBUG]) 97 | 98 | AC_MSG_CHECKING([if zts is enabled]) 99 | old_CPPFLAGS=$CPPFLAGS 100 | CPPFLAGS="-I$phpincludedir" 101 | AC_EGREP_CPP(php_zts_is_enabled,[ 102 | #include
103 | #if ZTS 104 | php_zts_is_enabled 105 | #endif 106 | ],[ 107 | PHP_THREAD_SAFETY=yes 108 | ],[ 109 | PHP_THREAD_SAFETY=no 110 | ]) 111 | CPPFLAGS=$old_CPPFLAGS 112 | AC_MSG_RESULT([$PHP_THREAD_SAFETY]) 113 | 114 | dnl Discard optimization flags when debugging is enabled. 115 | if test "$PHP_DEBUG" = "yes"; then 116 | PHP_DEBUG=1 117 | ZEND_DEBUG=yes 118 | changequote({,}) 119 | CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'` 120 | CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'` 121 | changequote([,]) 122 | dnl Add -O0 only if GCC or ICC is used. 123 | if test "$GCC" = "yes" || test "$ICC" = "yes"; then 124 | CFLAGS="$CFLAGS -O0" 125 | CXXFLAGS="$CXXFLAGS -g -O0" 126 | fi 127 | if test "$SUNCC" = "yes"; then 128 | if test -n "$auto_cflags"; then 129 | CFLAGS="-g" 130 | CXXFLAGS="-g" 131 | else 132 | CFLAGS="$CFLAGS -g" 133 | CXXFLAGS="$CFLAGS -g" 134 | fi 135 | fi 136 | else 137 | PHP_DEBUG=0 138 | ZEND_DEBUG=no 139 | fi 140 | 141 | dnl Always shared. 142 | PHP_BUILD_SHARED 143 | 144 | dnl Required programs. 145 | PHP_PROG_AWK 146 | 147 | sinclude(config.m4) 148 | 149 | enable_static=no 150 | enable_shared=yes 151 | 152 | dnl Only allow AC_PROG_CXX and AC_PROG_CXXCPP if they are explicitly called (by 153 | dnl PHP_REQUIRE_CXX). Otherwise AC_PROG_LIBTOOL fails if there is no working C++ 154 | dnl compiler. 155 | AC_PROVIDE_IFELSE([PHP_REQUIRE_CXX], [], [ 156 | undefine([AC_PROG_CXX]) 157 | AC_DEFUN([AC_PROG_CXX], []) 158 | undefine([AC_PROG_CXXCPP]) 159 | AC_DEFUN([AC_PROG_CXXCPP], [php_prog_cxxcpp=disabled]) 160 | ]) 161 | AC_PROG_LIBTOOL 162 | 163 | all_targets='$(PHP_MODULES) $(PHP_ZEND_EX)' 164 | install_targets="install-modules install-headers" 165 | phplibdir="`pwd`/modules" 166 | CPPFLAGS="$CPPFLAGS -DHAVE_CONFIG_H" 167 | CFLAGS_CLEAN='$(CFLAGS)' 168 | CXXFLAGS_CLEAN='$(CXXFLAGS)' 169 | 170 | test "$prefix" = "NONE" && prefix="/usr/local" 171 | test "$exec_prefix" = "NONE" && exec_prefix='$(prefix)' 172 | 173 | PHP_SUBST(PHP_MODULES) 174 | PHP_SUBST(PHP_ZEND_EX) 175 | 176 | PHP_SUBST(all_targets) 177 | PHP_SUBST(install_targets) 178 | 179 | PHP_SUBST(prefix) 180 | PHP_SUBST(exec_prefix) 181 | PHP_SUBST(libdir) 182 | PHP_SUBST(prefix) 183 | PHP_SUBST(phplibdir) 184 | PHP_SUBST(phpincludedir) 185 | 186 | PHP_SUBST(CC) 187 | PHP_SUBST(CFLAGS) 188 | PHP_SUBST(CFLAGS_CLEAN) 189 | PHP_SUBST(CPP) 190 | PHP_SUBST(CPPFLAGS) 191 | PHP_SUBST(CXX) 192 | PHP_SUBST(CXXFLAGS) 193 | PHP_SUBST(CXXFLAGS_CLEAN) 194 | PHP_SUBST(EXTENSION_DIR) 195 | PHP_SUBST(PHP_EXECUTABLE) 196 | PHP_SUBST(EXTRA_LDFLAGS) 197 | PHP_SUBST(EXTRA_LIBS) 198 | PHP_SUBST(INCLUDES) 199 | PHP_SUBST(LFLAGS) 200 | PHP_SUBST(LDFLAGS) 201 | PHP_SUBST(SHARED_LIBTOOL) 202 | PHP_SUBST(LIBTOOL) 203 | PHP_SUBST(SHELL) 204 | PHP_SUBST(INSTALL_HEADERS) 205 | 206 | PHP_GEN_BUILD_DIRS 207 | PHP_GEN_GLOBAL_MAKEFILE 208 | 209 | test -d modules || $php_shtool mkdir modules 210 | 211 | AC_CONFIG_HEADERS([config.h]) 212 | 213 | AC_CONFIG_COMMANDS_PRE([PHP_PATCH_CONFIG_HEADERS([config.h.in])]) 214 | 215 | AC_OUTPUT 216 | -------------------------------------------------------------------------------- /polaris/limit_core.hpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making polaris-go available. 2 | // 3 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 4 | // 5 | // Licensed under the BSD 3-Clause License (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // https://opensource.org/licenses/BSD-3-Clause 10 | // 11 | // Unless required by applicable law or agreed to in writing, software distributed 12 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | // specific language governing permissionsr and limitations under the License. 15 | // 16 | 17 | using namespace std; 18 | 19 | extern "C" 20 | { 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include "php.h" 26 | #include "php_ini.h" 27 | #include "ext/standard/info.h" 28 | #include "php_polaris.h" 29 | } 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | // 引入 Polaris ProviderApi 函数定义 37 | #include "polaris/limit.h" 38 | #include "polaris/log.h" 39 | 40 | #include "utils.hpp" 41 | #include "common.hpp" 42 | 43 | // Polaris-PHP 中的依赖 44 | 45 | /** 46 | * @brief 47 | * 48 | * @param val 49 | * @return polaris::LimitCallResultType 50 | */ 51 | static polaris::LimitCallResultType convertToLimitCallResultType(string val) 52 | { 53 | if (val.compare("Limit") == 0) 54 | { 55 | return polaris::kLimitCallResultLimited; 56 | } 57 | if (val.compare("Failed") == 0) 58 | { 59 | return polaris::kLimitCallResultFailed; 60 | } 61 | return polaris::kLimitCallResultOk; 62 | } 63 | 64 | /** 65 | * @brief 66 | * 67 | * @param reqVal 68 | * @return polaris::QuotaRequest& 69 | */ 70 | static polaris::QuotaRequest ConvertToQuotaRequest(zval *reqVal) 71 | { 72 | map params = TransferToStdMap(Z_ARRVAL_P(reqVal)); 73 | map labels = map(); 74 | 75 | polaris::QuotaRequest req; 76 | 77 | zval *labelsVal, *subsetVal; 78 | labelsVal = zend_hash_find(HASH_OF(reqVal), zend_string_init(Labels.c_str(), getKeyLength(Labels), 0)); 79 | if (labelsVal != NULL) 80 | { 81 | labels = TransferToStdMap(Z_ARRVAL_P(labelsVal)); 82 | } 83 | subsetVal = zend_hash_find(HASH_OF(reqVal), zend_string_init(ServiceSubSet.c_str(), getKeyLength(ServiceSubSet), 0)); 84 | if (subsetVal != NULL) 85 | { 86 | req.SetSubset(TransferToStdMap(Z_ARRVAL_P(subsetVal))); 87 | } 88 | 89 | string tmp = params[Amount]; 90 | if (string("").compare(tmp) == 0) 91 | { 92 | tmp = "1"; 93 | } 94 | 95 | req.SetServiceNamespace(params[Namespace]); 96 | req.SetServiceName(params[Service]); 97 | req.SetAcquireAmount(atoi(tmp.c_str())); 98 | req.SetLabels(labels); 99 | 100 | return req; 101 | } 102 | 103 | // /** 104 | // * @brief 105 | // * 106 | // * @param limit 107 | // * @param reqVal 108 | // * @return polaris::ReturnCode 109 | // */ 110 | // static polaris::ReturnCode DoFetchRule(polaris::LimitApi *limit, zval *reqVal, uint64_t timeout, zval *returnVal) 111 | // { 112 | // map params = TransferToStdMap(Z_ARRVAL_P(reqVal)); 113 | 114 | // polaris::ServiceKey key = {params[Namespace], params[Service]}; 115 | // string jsonRule; 116 | 117 | // polaris::ReturnCode code = limit->FetchRule(key, timeout, jsonRule); 118 | 119 | // string errMsg = polaris::ReturnCodeToMsg(code); 120 | 121 | // add_assoc_long(returnVal, Code.c_str(), code); 122 | // add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length(), 1); 123 | // add_assoc_stringl(returnVal, LimitRuleJsonStr.c_str(), (char *)jsonRule.c_str(), jsonRule.length(), 1); 124 | // return code; 125 | // } 126 | 127 | // /** 128 | // * @brief 129 | // * 130 | // * @param limit 131 | // * @param reqVal 132 | // * @param timeout 133 | // * @return polaris::ReturnCode 134 | // */ 135 | // static polaris::ReturnCode DoFetchRuleLabelKeys(polaris::LimitApi *limit, zval *reqVal, uint64_t timeout, zval *returnVal) 136 | // { 137 | // map params = TransferToStdMap(Z_ARRVAL_P(reqVal)); 138 | 139 | // polaris::ServiceKey key = {params[Namespace], params[Service]}; 140 | 141 | // const set *labelKeys = nullptr; 142 | // polaris::ReturnCode code = limit->FetchRuleLabelKeys(key, timeout, labelKeys); 143 | 144 | // string errMsg = polaris::ReturnCodeToMsg(code); 145 | // add_assoc_long(returnVal, Code.c_str(), code); 146 | // add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length(), 1); 147 | 148 | // if (code == polaris::kReturnOk && labelKeys != nullptr) 149 | // { 150 | // zval *arr; 151 | // ALLOC_INIT_ZVAL(arr); 152 | // array_init_size(arr, labelKeys->size()); 153 | // for (set::iterator iter = labelKeys->begin(); iter != labelKeys->end(); iter++) 154 | // { 155 | // std::cout << *iter << " , " << endl; 156 | // add_next_index_string(arr, ((string)(*iter)).c_str(), 1); 157 | // } 158 | // add_assoc_zval(returnVal, LimitLabelKeys.c_str(), arr); 159 | // } 160 | 161 | // return code; 162 | // } 163 | 164 | /** 165 | * @brief 获取配额 166 | * 167 | * @param limit 168 | * @param reqVal 获取配额请求 169 | * @return polaris::ReturnCode 170 | * { 171 | * ["quota_result"]=> 172 | * array(5) { 173 | * ["quota_result_code"]=> 174 | * int(0) 175 | * ["quota_duration"]=> 176 | * int(0) 177 | * ["quota_left"]=> 178 | * int(0) 179 | * ["quota_all"]=> 180 | * int(0) 181 | * ["degrade"]=> 182 | * bool(false) 183 | * } 184 | * } 185 | */ 186 | static polaris::ReturnCode DoGetQuota(polaris::LimitApi *limit, zval *reqVal, zval *returnVal) 187 | { 188 | polaris::QuotaRequest req = ConvertToQuotaRequest(reqVal); 189 | 190 | polaris::QuotaResponse *resp; 191 | 192 | polaris::ReturnCode code = limit->GetQuota(req, resp); 193 | string errMsg = polaris::ReturnCodeToMsg(code); 194 | add_assoc_long(returnVal, Code.c_str(), code); 195 | add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length()); 196 | 197 | if (code == polaris::kReturnOk && resp != nullptr) 198 | { 199 | zval *arr; 200 | array_init(arr); 201 | add_assoc_long(arr, ResultCodeForQuota.c_str(), resp->GetResultCode()); 202 | add_assoc_long(arr, DurationForQuota.c_str(), resp->GetQuotaResultInfo().duration_); 203 | add_assoc_long(arr, LeftQuota.c_str(), resp->GetQuotaResultInfo().left_quota_); 204 | add_assoc_long(arr, AllQuota.c_str(), resp->GetQuotaResultInfo().all_quota_); 205 | add_assoc_bool(arr, IsDegrade.c_str(), resp->GetQuotaResultInfo().is_degrade_); 206 | add_assoc_long(arr, WaitTimeForQuota.c_str(), resp->GetWaitTime()); 207 | add_assoc_zval(returnVal, ResultForQuota.c_str(), arr); 208 | } 209 | 210 | return code; 211 | } 212 | 213 | /** 214 | * @brief 更新请求配额调用结果 215 | * 216 | * @param limit 217 | * @param reqVal 218 | * @param waitTime 219 | * @return polaris::ReturnCode 220 | */ 221 | static polaris::ReturnCode DoUpdateCallResult(polaris::LimitApi *limit, zval *reqVal, zval *returnVal) 222 | { 223 | map params = TransferToStdMap(Z_ARRVAL_P(reqVal)); 224 | map labels, subset; 225 | 226 | zval *labelsVal = zend_hash_find(HASH_OF(reqVal), zend_string_init(Labels.c_str(), getKeyLength(Labels), 0)); 227 | if (labelsVal != NULL && Z_TYPE_P(labelsVal) == IS_ARRAY) 228 | { 229 | labels = TransferToStdMap(Z_ARRVAL_P(labelsVal)); 230 | } 231 | else 232 | { 233 | labels = map(); 234 | } 235 | 236 | zval *subsetVal = zend_hash_find(HASH_OF(reqVal), zend_string_init(ServiceSubSet.c_str(), getKeyLength(ServiceSubSet), 0)); 237 | if (subsetVal != NULL) 238 | { 239 | subset = TransferToStdMap(Z_ARRVAL_P(subsetVal)); 240 | } 241 | else 242 | { 243 | subset = map(); 244 | } 245 | 246 | polaris::LimitCallResult callResult; 247 | callResult.SetServiceNamespace(params[Namespace]); 248 | callResult.SetServiceName(params[Service]); 249 | callResult.SetSubset(subset); 250 | callResult.SetLabels(labels); 251 | callResult.SetResponseResult(convertToLimitCallResultType(params[CallResponseType])); 252 | callResult.SetResponseTime(atol(params[CallResponseTime].c_str())); 253 | callResult.SetResponseCode(atoi(params[CallResponseCode].c_str())); 254 | 255 | polaris::ReturnCode code = limit->UpdateCallResult(callResult); 256 | string errMsg = polaris::ReturnCodeToMsg(code); 257 | add_assoc_long(returnVal, Code.c_str(), code); 258 | add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length()); 259 | return code; 260 | } 261 | 262 | /** 263 | * @brief 初始化配额窗口,可选调用,用于提前初始化配窗口减小首次配额延迟 264 | * 265 | * @param limit 266 | * @param reqVal 267 | * @param waitTime 268 | * @return polaris::ReturnCode 269 | */ 270 | static polaris::ReturnCode DoInitQuotaWindow(polaris::LimitApi *limit, zval *reqVal, zval *returnVal) 271 | { 272 | polaris::QuotaRequest req = ConvertToQuotaRequest(reqVal); 273 | 274 | polaris::ReturnCode code = limit->InitQuotaWindow(req); 275 | string errMsg = polaris::ReturnCodeToMsg(code); 276 | add_assoc_long(returnVal, Code.c_str(), code); 277 | add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length()); 278 | return code; 279 | } -------------------------------------------------------------------------------- /polaris/php_polaris.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making polaris-go available. 2 | // 3 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 4 | // 5 | // Licensed under the BSD 3-Clause License (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // https://opensource.org/licenses/BSD-3-Clause 10 | // 11 | // Unless required by applicable law or agreed to in writing, software distributed 12 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | // specific language governing permissionsr and limitations under the License. 15 | // 16 | 17 | /* 18 | +----------------------------------------------------------------------+ 19 | | PHP Version 5 | 20 | +----------------------------------------------------------------------+ 21 | | Copyright (c) 1997-2016 The PHP Group | 22 | +----------------------------------------------------------------------+ 23 | | This source file is subject to version 3.01 of the PHP license, | 24 | | that is bundled with this package in the file LICENSE, and is | 25 | | available through the world-wide-web at the following url: | 26 | | http://www.php.net/license/3_01.txt | 27 | | If you did not receive a copy of the PHP license and are unable to | 28 | | obtain it through the world-wide-web, please send a note to | 29 | | license@php.net so we can mail you a copy immediately. | 30 | +----------------------------------------------------------------------+ 31 | | Author: | 32 | +----------------------------------------------------------------------+ 33 | */ 34 | 35 | /* $Id$ */ 36 | 37 | #ifndef PHP_POLARIS_H 38 | #define PHP_POLARIS_H 39 | 40 | extern zend_module_entry polaris_module_entry; 41 | #define phpext_polaris_ptr &polaris_module_entry 42 | 43 | #define PHP_POLARIS_VERSION "0.1.0" /* Replace with version number for your extension */ 44 | 45 | #ifdef PHP_WIN32 46 | #define PHP_POLARIS_API __declspec(dllexport) 47 | #elif defined(__GNUC__) && __GNUC__ >= 4 48 | #define PHP_POLARIS_API __attribute__((visibility("default"))) 49 | #else 50 | #define PHP_POLARIS_API 51 | #endif 52 | 53 | #ifdef ZTS 54 | #include "TSRM.h" 55 | #endif 56 | 57 | /* 58 | Declare any global variables you may need between the BEGIN 59 | and END macros here: 60 | ZEND_BEGIN_MODULE_GLOBALS(polaris) 61 | long global_value; 62 | char *global_string; 63 | ZEND_END_MODULE_GLOBALS(polaris) 64 | */ 65 | 66 | /* In every utility function you add that needs to use variables 67 | in php_polaris_globals, call TSRMLS_FETCH(); after declaring other 68 | variables used by that function, or better yet, pass in TSRMLS_CC 69 | after the last function argument and declare your utility function 70 | with TSRMLS_DC after the last declared argument. Always refer to 71 | the globals in your function as POLARIS_G(variable). You are 72 | encouraged to rename these macros something shorter, see 73 | examples in any other php module directory. 74 | */ 75 | 76 | #ifdef ZTS 77 | #define POLARIS_G(v) TSRMG(polaris_globals_id, zend_polaris_globals *, v) 78 | #else 79 | #define POLARIS_G(v) (polaris_globals.v) 80 | #endif 81 | 82 | // __construct PolarisClient 的构造函数定义 83 | PHP_METHOD(PolarisClient, __construct); 84 | // InitProvider 初始化 Polaris 的 Provider 功能 85 | PHP_METHOD(PolarisClient, InitProvider); 86 | // InitConsumer 初始化 Polaris 的 Consumer 功能 87 | PHP_METHOD(PolarisClient, InitConsumer); 88 | // InitLimit 初始化 Polaris 的 Limit 功能 89 | PHP_METHOD(PolarisClient, InitLimit); 90 | 91 | // Provider 92 | // 必须要先执行 InitProvider 才可以执行 93 | PHP_METHOD(PolarisClient, Register); 94 | PHP_METHOD(PolarisClient, Deregister); 95 | PHP_METHOD(PolarisClient, Heartbeat); 96 | 97 | // Consumer 98 | // 必须要先执行 InitConsumer 才可以执行 99 | PHP_METHOD(PolarisClient, InitService); 100 | PHP_METHOD(PolarisClient, GetOneInstance); 101 | PHP_METHOD(PolarisClient, GetInstances); 102 | PHP_METHOD(PolarisClient, GetAllInstances); 103 | PHP_METHOD(PolarisClient, UpdateServiceCallResult); 104 | // PHP_METHOD(PolarisClient, GetRouteRuleKeys); 105 | 106 | // Limit 107 | // 必须要先执行 InitLimit 才可以执行 108 | // PHP_METHOD(PolarisClient, FetchRule); 109 | // PHP_METHOD(PolarisClient, FetchRuleLabelKeys); 110 | PHP_METHOD(PolarisClient, GetQuota); 111 | PHP_METHOD(PolarisClient, UpdateCallResult); 112 | PHP_METHOD(PolarisClient, InitQuotaWindow); 113 | 114 | #endif /* PHP_POLARIS_H */ 115 | 116 | /* 117 | * Local variables: 118 | * tab-width: 4 119 | * c-basic-offset: 4 120 | * End: 121 | * vim600: noet sw=4 ts=4 fdm=marker 122 | * vim<600: noet sw=4 ts=4 123 | */ -------------------------------------------------------------------------------- /polaris/polaris.cpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making polaris-go available. 2 | // 3 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 4 | // 5 | // Licensed under the BSD 3-Clause License (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // https://opensource.org/licenses/BSD-3-Clause 10 | // 11 | // Unless required by applicable law or agreed to in writing, software distributed 12 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | // specific language governing permissionsr and limitations under the License. 15 | // 16 | 17 | /* 18 | +----------------------------------------------------------------------+ 19 | | PHP Version 5 | 20 | +----------------------------------------------------------------------+ 21 | | Copyright (c) 1997-2016 The PHP Group | 22 | +----------------------------------------------------------------------+ 23 | | This source file is subject to version 3.01 of the PHP license, | 24 | | that is bundled with this package in the file LICENSE, and is | 25 | | available through the world-wide-web at the following url: | 26 | | http://www.php.net/license/3_01.txt | 27 | | If you did not receive a copy of the PHP license and are unable to | 28 | | obtain it through the world-wide-web, please send a note to | 29 | | license@php.net so we can mail you a copy immediately. | 30 | +----------------------------------------------------------------------+ 31 | | Author: | 32 | +----------------------------------------------------------------------+ 33 | */ 34 | 35 | /* $Id$ */ 36 | 37 | #ifdef HAVE_CONFIG_H 38 | #include "config.h" 39 | #endif 40 | 41 | #include "php.h" 42 | #include "php_ini.h" 43 | #include "ext/standard/info.h" 44 | #include "php_polaris.h" 45 | 46 | #include "polaris_core.hpp" 47 | 48 | /* If you declare any globals in php_polaris.h uncomment this: 49 | ZEND_DECLARE_MODULE_GLOBALS(polaris) 50 | */ 51 | 52 | /* True global resources - no need for thread safety here */ 53 | static int le_polaris; 54 | 55 | /* {{{ PHP_INI 56 | */ 57 | /* Remove comments and fill if you need to have entries in php.ini 58 | PHP_INI_BEGIN() 59 | STD_PHP_INI_ENTRY("polaris.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_polaris_globals, polaris_globals) 60 | STD_PHP_INI_ENTRY("polaris.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_polaris_globals, polaris_globals) 61 | PHP_INI_END() 62 | */ 63 | /* }}} */ 64 | 65 | /* Remove the following function when you have successfully modified config.m4 66 | so that your module can be compiled into PHP, it exists only for testing 67 | purposes. */ 68 | 69 | /* Every user-visible function in PHP should document itself in the source */ 70 | /* {{{ proto string confirm_polaris_compiled(string arg) 71 | Return a string to confirm that the module is compiled in */ 72 | PHP_FUNCTION(confirm_polaris_compiled) 73 | { 74 | char *arg = NULL; 75 | int arg_len, len; 76 | char *strg; 77 | 78 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) 79 | { 80 | return; 81 | } 82 | 83 | len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "polaris", arg); 84 | RETURN_STRINGL(strg, len); 85 | } 86 | /* }}} */ 87 | /* The previous line is meant for vim and emacs, so it can correctly fold and 88 | unfold functions in source code. See the corresponding marks just before 89 | function definition, where the functions purpose is also documented. Please 90 | follow this convention for the convenience of others editing your code. 91 | */ 92 | 93 | /* {{{ php_polaris_init_globals 94 | */ 95 | /* Uncomment this function if you have INI entries 96 | static void php_polaris_init_globals(zend_polaris_globals *polaris_globals) 97 | { 98 | polaris_globals->global_value = 0; 99 | polaris_globals->global_string = NULL; 100 | } 101 | */ 102 | /* }}} */ 103 | 104 | zend_class_entry *polaris_core_client; 105 | 106 | /* {{{ PHP_MINIT_FUNCTION 107 | */ 108 | PHP_MINIT_FUNCTION(polaris) 109 | { 110 | // If you have INI entries, uncomment these lines 111 | // REGISTER_INI_ENTRIES(); 112 | 113 | // 初始化 ProviderApi 相关 114 | zend_class_entry polaris_core_ins; 115 | INIT_CLASS_ENTRY(polaris_core_ins, "PolarisClient", polaris_core_functions); 116 | 117 | polaris_core_client = zend_register_internal_class(&polaris_core_ins TSRMLS_CC); 118 | polaris_core_client->create_object = polaris_core_create_handler; 119 | memcpy(&polaris_core_object_handlers, 120 | zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 121 | polaris_core_object_handlers.clone_obj = NULL; 122 | return SUCCESS; 123 | } 124 | /* }}} */ 125 | 126 | /* {{{ PHP_MSHUTDOWN_FUNCTION 127 | */ 128 | PHP_MSHUTDOWN_FUNCTION(polaris) 129 | { 130 | /* uncomment this line if you have INI entries 131 | UNREGISTER_INI_ENTRIES(); 132 | */ 133 | return SUCCESS; 134 | } 135 | /* }}} */ 136 | 137 | /* Remove if there's nothing to do at request start */ 138 | /* {{{ PHP_RINIT_FUNCTION 139 | */ 140 | PHP_RINIT_FUNCTION(polaris) 141 | { 142 | return SUCCESS; 143 | } 144 | /* }}} */ 145 | 146 | /* Remove if there's nothing to do at request end */ 147 | /* {{{ PHP_RSHUTDOWN_FUNCTION 148 | */ 149 | PHP_RSHUTDOWN_FUNCTION(polaris) 150 | { 151 | return SUCCESS; 152 | } 153 | /* }}} */ 154 | 155 | /* {{{ PHP_MINFO_FUNCTION 156 | */ 157 | PHP_MINFO_FUNCTION(polaris) 158 | { 159 | php_info_print_table_start(); 160 | php_info_print_table_header(2, "polaris support", "enabled"); 161 | php_info_print_table_end(); 162 | 163 | /* Remove comments if you have entries in php.ini 164 | DISPLAY_INI_ENTRIES(); 165 | */ 166 | } 167 | /* }}} */ 168 | 169 | // 定义 PolarisCPP 中在 PHP 对应的类 170 | 171 | /* {{{ polaris_functions[] 172 | * 173 | * Every user visible function must have an entry in polaris_functions[]. 174 | */ 175 | const zend_function_entry polaris_functions[] = { 176 | PHP_FE(confirm_polaris_compiled, NULL) /* For testing, remove later. */ 177 | PHP_FE_END /* Must be the last line in polaris_functions[] */ 178 | }; 179 | /* }}} */ 180 | 181 | /* {{{ polaris_module_entry 182 | */ 183 | zend_module_entry polaris_module_entry = { 184 | STANDARD_MODULE_HEADER, 185 | "polaris", 186 | NULL, 187 | PHP_MINIT(polaris), 188 | NULL, 189 | NULL, /* Replace with NULL if there's nothing to do at request start */ 190 | NULL, /* Replace with NULL if there's nothing to do at request end */ 191 | NULL, 192 | PHP_POLARIS_VERSION, 193 | STANDARD_MODULE_PROPERTIES}; 194 | /* }}} */ 195 | 196 | #ifdef COMPILE_DL_POLARIS 197 | ZEND_GET_MODULE(polaris) 198 | #endif 199 | 200 | /* 201 | * Local variables: 202 | * tab-width: 4 203 | * c-basic-offset: 4 204 | * End: 205 | * vim600: noet sw=4 ts=4 fdm=marker 206 | * vim<600: noet sw=4 ts=4 207 | */ -------------------------------------------------------------------------------- /polaris/polaris_provider.loT: -------------------------------------------------------------------------------- 1 | # polaris_provider.lo - a libtool object file 2 | # Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56) 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # Name of the PIC object. 8 | -------------------------------------------------------------------------------- /polaris/polaris_test.php: -------------------------------------------------------------------------------- 1 | "; 3 | 4 | if(!extension_loaded('polaris')) { 5 | dl('polaris.' . PHP_SHLIB_SUFFIX); 6 | } 7 | 8 | // 创建一个 polaris-provider 实例 9 | $polaris = new PolarisClient(array( 10 | "config_path" => "/root/Github/polaris-php/polaris.yaml", 11 | "log_dir" => "./" 12 | )); 13 | 14 | $polaris -> InitProvider(); 15 | 16 | // 实例注册信息 17 | $register_instance_info = array( 18 | "namespace" => "default", 19 | "service" => "php_ext_test", 20 | "host" => "127.0.0.3", 21 | "port" => "8080", 22 | ); 23 | 24 | // 实例元信息 25 | $metadata = array( 26 | "client" => "php" 27 | ); 28 | 29 | // 执行实例注册动作 30 | $res = $polaris->Register($register_instance_info, $metadata, 5000, 1); 31 | print $res; 32 | var_dump($register_instance_info); 33 | 34 | 35 | // 实例心跳 36 | 37 | 38 | // 实例反注册信息 39 | $deregister_instance_info = array( 40 | "namespace" => "default", 41 | "service" => "php_ext_test", 42 | "host" => "127.0.0.3", 43 | "port" => "8080", 44 | ); 45 | 46 | // 执行实例反注册动作 47 | $res = $polaris->Deregister($deregister_instance_info, 5000, 1); 48 | print $res; 49 | var_dump($deregister_instance_info); 50 | ?> 51 | -------------------------------------------------------------------------------- /polaris/provider_core.hpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making polaris-go available. 2 | // 3 | // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 4 | // 5 | // Licensed under the BSD 3-Clause License (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // https://opensource.org/licenses/BSD-3-Clause 10 | // 11 | // Unless required by applicable law or agreed to in writing, software distributed 12 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | // specific language governing permissionsr and limitations under the License. 15 | // 16 | 17 | using namespace std; 18 | 19 | extern "C" 20 | { 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include "php.h" 26 | #include "php_ini.h" 27 | #include "ext/standard/info.h" 28 | #include "php_polaris.h" 29 | } 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | // 引入 Polaris ProviderApi 函数定义 37 | #include "polaris/provider.h" 38 | #include "polaris/log.h" 39 | 40 | #include "utils.hpp" 41 | #include "common.hpp" 42 | 43 | /** 44 | * @brief 45 | * 46 | * @param provider 47 | * @param reqVal 48 | * @param metadataVal 49 | * @param timeout 50 | * @param flowId 51 | * @return polaris::ReturnCode 52 | */ 53 | static polaris::ReturnCode RegisterInstance(polaris::ProviderApi *provider, zval *reqVal, uint64_t timeout, uint64_t flowId, zval *returnVal) 54 | { 55 | map params = TransferToStdMap(Z_ARRVAL_P(reqVal)); 56 | map metadata = map(); 57 | 58 | zval *metadataVal; 59 | metadataVal = zend_hash_find(HASH_OF(reqVal), zend_string_init(Metadata.c_str(), getKeyLength(Metadata), 0)); 60 | if (metadataVal != NULL) 61 | { 62 | metadata = TransferToStdMap(Z_ARRVAL_P(metadataVal)); 63 | } 64 | 65 | int port = atoi(params[Port].c_str()); 66 | int weight = atoi(params[Weight].c_str()); 67 | int priority = atoi(params[Priority].c_str()); 68 | bool healthcheck = string("true").compare(params[HeartbeatFlag]) == 0; 69 | int ttl = 0; 70 | if (healthcheck) 71 | { 72 | ttl = atoi(params[Ttl].c_str()); 73 | } 74 | 75 | string tmp = params[Token]; 76 | string token = tmp.empty() ? "polaris_php_sdk__" + params[Service] : tmp; 77 | 78 | // 获取 metadata 数据 79 | // 进行 InstanceRegisterRequest 请求参数的初始化动作 80 | polaris::InstanceRegisterRequest req(params[Namespace], params[Service], token, params[Host], port); 81 | 82 | req.SetTimeout(timeout); 83 | req.SetProtocol(params[Protocol]); 84 | req.SetVpcId(params[VpcID]); 85 | req.SetVersion(params[Version]); 86 | req.SetMetadata(metadata); 87 | req.SetHealthCheckFlag(healthcheck); 88 | req.SetTtl(ttl); 89 | req.SetWeight(weight); 90 | req.SetFlowId(flowId); 91 | req.SetPriority(priority); 92 | 93 | string instanceId; 94 | polaris::ReturnCode code = provider->Register(req, instanceId); 95 | string errMsg = polaris::ReturnCodeToMsg(code); 96 | add_assoc_long(returnVal, Code.c_str(), code); 97 | add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length()); 98 | add_assoc_stringl(returnVal, InstanceID.c_str(), (char *)instanceId.c_str(), instanceId.length()); 99 | return code; 100 | } 101 | 102 | /** 103 | * @brief 104 | * 105 | * @param provider 106 | * @param reqVal 107 | * @param timeout 108 | * @param flowId 109 | * @return polaris::ReturnCode 110 | */ 111 | static polaris::ReturnCode DeregisterInstance(polaris::ProviderApi *provider, zval *reqVal, uint64_t timeout, uint64_t flowId, zval *returnVal) 112 | { 113 | // 将参数转换为 map 对象 114 | map params = TransferToStdMap(Z_ARRVAL_P(reqVal)); 115 | 116 | int port = atoi(params[Port].c_str()); 117 | string tmp = params[Token]; 118 | string token = tmp.empty() ? "polaris_php_sdk__" + params[Service] : tmp; 119 | 120 | // 进行 InstanceDeregisterRequest 请求参数的初始化动作 121 | polaris::InstanceDeregisterRequest req(params[Namespace], params[Service], token, params[Host], port); 122 | req.SetTimeout(timeout); 123 | req.SetFlowId(flowId); 124 | req.SetVpcId(params[VpcID]); 125 | 126 | polaris::ReturnCode code = provider->Deregister(req); 127 | // 返回值回插入到 register_req 中? 128 | string errMsg = polaris::ReturnCodeToMsg(code); 129 | add_assoc_long(returnVal, Code.c_str(), code); 130 | add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length()); 131 | return code; 132 | } 133 | 134 | /** 135 | * @brief 136 | * 137 | * @param provider 138 | * @param reqVal 139 | * @return polaris::ReturnCode 140 | */ 141 | static polaris::ReturnCode DoHeartbeat(polaris::ProviderApi *provider, zval *reqVal, zval *returnVal) 142 | { 143 | // 将参数转换为 map 对象 144 | map params = TransferToStdMap(Z_ARRVAL_P(reqVal)); 145 | 146 | int port = atoi(params[Port].c_str()); 147 | string tmp = params[Token]; 148 | string token = tmp.empty() ? "polaris_php_sdk__" + params[Service] : tmp; 149 | 150 | polaris::InstanceHeartbeatRequest req(params[Namespace], params[Service], token, params[Host], port); 151 | req.SetVpcId(params[VpcID]); 152 | 153 | polaris::ReturnCode code = provider->Heartbeat(req); 154 | // 返回值回插入到 register_req 中? 155 | string errMsg = polaris::ReturnCodeToMsg(code); 156 | add_assoc_long(returnVal, Code.c_str(), code); 157 | add_assoc_stringl(returnVal, ErrMsg.c_str(), (char *)errMsg.c_str(), errMsg.length()); 158 | return code; 159 | } -------------------------------------------------------------------------------- /polaris/tests/001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for polaris_provider presence 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 20 | --EXPECT-- 21 | polaris_provider extension is available 22 | -------------------------------------------------------------------------------- /sdk_class_example.php: -------------------------------------------------------------------------------- 1 | "default", 8 | "service" => "php_ext_test", 9 | "host" => "127.0.0.3", 10 | "port" => "8080", 11 | "metadata" => array( 12 | "env" => "pre" 13 | ), 14 | "vpc_id" => "test_vpc", 15 | ); 16 | 17 | $timeout = 500; 18 | $flow_id = 123456; 19 | 20 | $res = $polaris_client->Register($instance_info, $timeout, $flow_id); 21 | var_dump("====================Register=================="); 22 | var_dump($res); 23 | 24 | $res = $polaris_client->Heartbeat("default", "php_ext_test", "127.0.0.3", "8080", "test_vpc"); 25 | var_dump("====================Heartbeat=================="); 26 | var_dump($res); 27 | 28 | 29 | $init_service_info = array( 30 | "namespace" => "default", 31 | "service" => "php_ext_test", 32 | "vpc_id" => "test_vpc", 33 | "metadata" => array( 34 | "env" => "pre" 35 | ), 36 | "labels" => array( 37 | "user_id" => "uin_001" 38 | ), 39 | "source" => array( 40 | "namespace" => "", 41 | "service" => "", 42 | "metadata" => array( 43 | "env" => "pre" 44 | ) 45 | ), 46 | ); 47 | 48 | $res = $polaris_client->InitService($init_service_info, $timeout, $flow_id); 49 | var_dump("====================InitService=================="); 50 | var_dump($res); 51 | 52 | $init_service_info = array( 53 | "namespace" => "default", 54 | "service" => "php_ext_test", 55 | "vpc_id" => "test_vpc", 56 | "metadata" => array( 57 | "env" => "pre" 58 | ), 59 | "labels" => array( 60 | "user_id" => "uin_001" 61 | ), 62 | "source" => array( 63 | "namespace" => "", 64 | "service" => "", 65 | "metadata" => array( 66 | "env" => "pre" 67 | ) 68 | ) 69 | ); 70 | 71 | $res = $polaris_client->GetOneInstance($init_service_info, $timeout, $flow_id); 72 | var_dump("====================GetOneInstance=================="); 73 | var_dump($res); 74 | 75 | $init_service_info = array( 76 | "namespace" => "default", 77 | "service" => "php_ext_test", 78 | "canary" => "test_vpc", 79 | "source" => array( 80 | "namespace" => "", 81 | "service" => "", 82 | "metadata" => array( 83 | "env" => "pre" 84 | ) 85 | ) 86 | ); 87 | 88 | $res = $polaris_client->GetInstances($init_service_info, $timeout, $flow_id); 89 | var_dump("====================GetInstances=================="); 90 | var_dump($res); 91 | 92 | 93 | $init_service_info = array( 94 | "namespace" => "default", 95 | "service" => "php_ext_test", 96 | "canary" => "test_vpc", 97 | "source" => array( 98 | "namespace" => "", 99 | "service" => "", 100 | "metadata" => array( 101 | "env" => "pre" 102 | ) 103 | ) 104 | ); 105 | 106 | $res = $polaris_client->GetAllInstances($init_service_info, $timeout, $flow_id); 107 | var_dump("====================GetAllInstances=================="); 108 | var_dump($res); 109 | 110 | 111 | 112 | $init_service_info = array( 113 | "namespace" => "default", 114 | "service" => "php_ext_test", 115 | "locality_aware_info" => "", 116 | "ret_status" => "ok", 117 | "host" => "127.0.0.1", 118 | "port" => "8080", 119 | ); 120 | 121 | $res = $polaris_client->UpdateServiceCallResult($init_service_info, $timeout, $flow_id); 122 | var_dump("====================UpdateServiceCallResult=================="); 123 | var_dump($res); 124 | 125 | $res = $polaris_client->GetQuota("default", "php_ext_test", 0, array(), array()); 126 | var_dump("====================GetQuota=================="); 127 | var_dump($res); 128 | 129 | $res = $polaris_client->UpdateCallResult("default", "php_ext_test", "100", "100", "100", array(), array()); 130 | var_dump("====================UpdateCallResult=================="); 131 | var_dump($res); 132 | 133 | $res = $polaris_client->InitQuotaWindow("default", "php_ext_test", 0, array(), array()); 134 | var_dump("====================InitQuotaWindow=================="); 135 | var_dump($res); 136 | 137 | 138 | $instance_info = array( 139 | "namespace" => "default", 140 | "service" => "php_ext_test", 141 | "host" => "127.0.0.3", 142 | "port" => "8080", 143 | "vpc_id" => "test_vpc", 144 | ); 145 | 146 | $res = $polaris_client->Deregister($instance_info, $timeout, $flow_id); 147 | var_dump("====================Deregister=================="); 148 | var_dump($res); --------------------------------------------------------------------------------