本篇概要:
1. 服務註冊與發現、consul;
1.1 consul 簡學、服務註冊與發現,手動註冊服務;
服務的發現與註冊
- 配置共享:調用端裏面有數據庫或者 Redis 的鏈接,單機開發的時候寫在配置文件裏,但是多臺服務器或者通過 docker 部署,配置一旦發生改變(服務器沒了,地址改了),這些改變無法讓調用端獲取到。這時候需要一個統一的配置中心,配置發生改變的時候要有一些即時的機制讓調用端不需要大量的修改配置
下載安裝 Consul
- 下載地址:https://www.consul.io/downloads.html,解壓出來直接是一個可執行文件
- 拷貝到
/usr/local/consul
,執行./consul -v
出現版本號,即可正常使用
啓動 Consul
# 參數配置
# -data-dir 數據目錄
# -bind 指定機器
# -server 以服務器模式進行啓動
# -bootstrap 指定自己爲 leader,而不需要選舉
# -ui 啓動一個內置管理 web 界面(瀏覽器訪問:http://192.168.60.221:8500)
# -client 指定客戶端可以訪問的 IP。設置爲 0.0.0.0 則任意訪問,否則默認本機可以訪問
./consul agent -data-dir=/home/hua/consul -bind=192.168.60.221 -server -bootstrap -client 0.0.0.0 -ui -client=0.0.0.0
基本操作
# 1. 服務端模式:負責保存信息、集羣控制、與客戶端通信、與其它數據中心通信
## 新開一個終端,查看當前多少個節點
./consul members
# 返回
Node Address Status Type Build Protocol DC Segment
hua-PC 192.168.60.221:8301 alive server 1.7.0 2 dc1 <all>
## 1.1 通過 API 的方式來調用並查看:https://www.consul.io/api/index.html
# 查看節點:
curl http://192.168.60.221:8500/v1/agent/members
## 1.2 註冊服務
# 服務註冊好之後,是會通過一定的方式保存到服務端
# 有服務註冊,就會檢查(比如服務掛了,就會發出警告)
# 列出當前所有註冊好的服務(目前爲空):https://www.consul.io/api/agent/service.html
curl http://192.168.60.221:8500/v1/agent/services
# 1.2.1 註冊一個服務
# 參考 1:https://www.consul.io/api/agent/service.html#register-service
# 參考 2 格式:https://www.consul.io/api/agent/service.html#sample-payload
curl http://192.168.60.221:8500/v1/agent/service/register \
--request PUT \
--data '{"ID":"testservice","Name":"testservice","Tags":["test"],"Address":"192.168.60.221","Port":18306,"Check":{"HTTP":"http://192.168.60.221:18306/test/health","Interval":"5s"}}'
# 1.2.2 反註冊
curl http://192.168.60.221:8500/v1/agent/service/deregister/testservice \
--request PUT
## 1.3 檢查服務狀態是否健康:https://www.consul.io/api/health.html
curl http://192.168.60.221:8500/v1/health/checks/testservice
# 2. 客戶端模式:無狀態,將請求轉發服務器或者集羣,此時服務器或集羣並不保存任何內容
# 3. 基於 Agent 守護進程
2. RPC 服務;
2.1 RPC 服務的基本配置;
2.1.1 基本概念;
概念:
- 中文名稱是“遠程過程調用”。現在做的網站裏面提交表單就是一個遠程調用,它的過程是在服務端執行的。PRC 是一個更廣泛的概念。如果只侷限在 HTTP 這個範疇,現在做的網站和 RESTful API 都是 RPC
基本原理:
- 建立在客戶端和服務端,網絡是相通的,兩者之間能夠建立 TCP、UDP 連接等基礎之上,能夠傳輸一些內容,這就是 RPC
- 這裏面的內容需要雙方進行約定。客戶端連上 TCP 之後,傳一個 abc,服務端立馬就知道客戶端要它執行 abc 這個方法。所以 abc 就是協議,協議都是約定好的(比如 JSONRPC),系統做好之後,第三方纔可以根據協議接入
關於 JSONRPC
- 文檔:http://wiki.geekdream.com/Specification/json-rpc_2.0.html
- 好比創建一個 JSON 對象,裏面包含一些固定的格式
- 用戶建立好 TCP 的過程當中,發送如下數據(請求),客戶端只要拼湊如下數據發送給服務端就可以了
{"jsonrpc": "2.0", "method": "add", "params": [1,2], "id": 1}
- 服務端直接獲取數據進行 JSON decode,分別解析參數,在進行執行,執行的過程自己決定
- 響應結果:
{"jsonrpc": "2.0", "result": 3, "id": 1}
- 現在只要寫代碼完成以上數據的“接收”和“響應”,然後再把過程封裝,使其更加的人性化(本地化)
- 實際開發有各種框架支持
2.1.2 基本配置;
- 配置參數:https://www.swoft.org/documents/v2/core-components/rpc-server/#heading7
- 修改文件:
Swoft_rpc\App\bean.php
# 添加如下代碼
'rpcServer' => [
'class' => ServiceServer::class,
],
- 實例操作
# 啓動
# 默認監聽端口 18307
php ./bin/swoft rpc:start
# 返回
SERVER INFORMATION(v2.0.8)
**************************************************************
* RPC | Listen: 0.0.0.0:18307, Mode: Process, Worker: 2
**************************************************************
RPC Server Start Success!
2.2 創建 RPC 服務,客戶端直連調用;
- 參考:https://www.swoft.org/documents/v2/core-components/rpc-server/#-rpc-client
- RPC 端新建:
Swoft_rpc/App/Rpc/Lib/ProdInterface.php
- HTTP 端新建:
Swoft/App/Rpc/Lib/ProdInterface.php
<?php
namespace App\Rpc\Lib;
interface ProdInterface{
function getProdList();
}
- RPC 端新建:
Swoft_rpc/App/Rpc/Service/ProdService.php
<?php
namespace App\Rpc\Service;
use App\Rpc\Lib\ProdInterface;
use Swoft\Rpc\Server\Annotation\Mapping\Service;
/**
* Class ProdService
* @package App\Rpc\Service
* @Service()
*/
class ProdService implements ProdInterface{
function getProdList()
{
return [
["prod_id" => 101, "prod_name" => "testprod1"],
["prod_id" => 102, "prod_name" => "testprod2"]
];
}
}
- HTTP 端新建
Swoft/App/Http/Controller/ProdController.php
- HTTP 調用:http://192.168.60.221:18306/prod/list 會返回 RPC 端
ProdService.php
返回的內容
<?php
namespace App\Http\Controller;
use App\Rpc\Lib\ProdInterface;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Rpc\Client\Annotation\Mapping\Reference;
/**
* Class ProdController
* @Controller(prefix="/prod")
*/
class ProdController{
/**
* @Reference(pool="prod.pool")
*
* @var ProdInterface
*/
private $prodService;
/**
* @RequestMapping(route="list",method={RequestMethod::GET})
*/
public function prod(){
// return ["prod_list"];
// 接口實現部分在 RPC 端,並不在 HTTP 端
return $this->prodService->getProdList();
}
}
- HTTP 端新建文件:
Swoft\App\rpcbean.php
<?php
use Swoft\Rpc\Client\Client as ServiceClient;
use Swoft\Rpc\Client\Pool as ServicePool;
$settings = [
'timeout' => 0.5,
'connect_timeout' => 1.0,
'write_timeout' => 10.0,
'read_timeout' => 0.5,
];
return [
'prod' => [
'class' => ServiceClient::class,
'host' => '192.168.60.221',
'port' => 18307,
'setting' => $settings,
'packet' => bean('rpcClientPacket')
],
'prod.pool' => [
'class' => ServicePool::class,
'client' => bean('prod'),
]
];
- HTTP 端修改文件:
Swoft\App\bean.php
# 修改一下內容(配置合併)
$rpcbeans = require("rpcbean.php");
$beans = [];
return array_merge($beans, $rpcbeans );