基于swoole(rpc),consul实现服务的注册与发现
1 . 用户服务
1 . 1 . 用户服务目录结构
├─userProject
├─service ------ 用户服务的业务逻辑
│ ├─RegisterUser.php ------ consul操作类
│ ├─UserService.php ------ 用户操作类
├─UserClient.php ------ 用户客户端,服务rpc的服务发起与调用
├─UserServer.php ------- 用户服务端,负责注册consul服务,接受rpc请求并返回请求数据
1 . 2 . 请求原理
注:consul的api请求性能很高,因此不用担心每次请求都需要去consul获取服务配置而带来的损耗,图下是测试机器性能比较差,也能达到很高的并发请求,当然这里也可以定时缓存consul返回的配置信息到redis中
1 . 3 . RegisterUser.php
<?php
class RegisterUser {
//注意,此处的IP和端口只能是consul_client服务的IP和端口
public $ip = "192.168.48.134";
public $port = "8500";
/**
* 服务注册
* @param $json
* @return mixed
*/
public function registerService($json)
{
return $this->curlPUT("/v1/agent/service/register",$json);
}
/**
* 销毁服务
* @param $service_id
* @return mixed
*/
public function deregisterService($service_id){
return $this->curlPUT("/v1/agent/service/deregister/$service_id",null);
}
/**
* 获取consul的服务信息
* @param $service_id
* @return bool|string
*/
public function getService($service_id){
return $this->curlGET("/v1/health/service/$service_id".'?passing=true',null);
}
/**
* PUT请求
* @param $request_uri
* @param $data
* @return mixed
*/
public function curlPUT($request_uri,$data){
$ch = curl_init();
$header[] = "Content-type:application/json";
$httpUrl = "http://{$this->ip}:{$this->port}{$request_uri}";
curl_setopt($ch,CURLOPT_URL,$httpUrl);
curl_setopt($ch,CURLOPT_CUSTOMREQUEST,"PUT");
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
/**
* GET请求
* @param $request_uri
* @param $data
* @return bool|string
*/
public function curlGET($request_uri,$data){
$ch = curl_init();
$header[] = "Content-type:application/json";
$httpUrl = "http://{$this->ip}:{$this->port}{$request_uri}";
curl_setopt($ch,CURLOPT_URL,$httpUrl);
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_HTTPHEADER, $header);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
}
1 . 4 . UserService.php
<?php
class UserService
{
/**
* 测试返回
* @param $sex
* @return array
*/
public function getUserList($sex)
{
return [
[
'name' => 'admin',
'sex' => $sex,
],
[
'name' => 'salesman',
'sex' => $sex,
]
];
}
}
1 . 5 . UserClient.php
用户客户端,服务rpc的服务发起与调用
<?php
use Swoole\Client;
require_once './service/RegisterUser.php';
class UserClient
{
protected $service;
/**
* @param $name 调用的方法名称
* @param $arguments 调用的参数
*/
public function __call($name, $arguments)
{
if ($name == 'service') {
$this->service = $arguments[0];
return $this;
}
$json_data = json_encode([
'uid' => mt_rand(1000,9696),
'type' => 'user',
'service' => $this->service, //服务
'action' => $name, //方法
'param' => $arguments[0], //参数
]);
//打包网络数据包
$data = pack('N', strlen($json_data)).$json_data;
//获取User服务地址
$address = $this->getServerAddress($this->service);
$client = new Client(SWOOLE_SOCK_TCP);
if (!$client->connect($address['ip'], $address['port'], -1)) {
exit("user connect failed. Error: {$client->errCode}\n");
}
$client->send($data);
//返回信息到前端页面
$result = $client->recv();
//$client->close();
return $result;
}
/**
* 获取consul服务的信息
* @param $server
* @return array
*/
public function getServerAddress($server)
{
//获取调用service的地址
$service = new RegisterUser();
$result = $service->getService($server);
$result = json_decode($result, true);
$arr = [
'ip' => $result[0]['Service']['Address'],
'port' => $result[0]['Service']['Port'],
];
return $arr;
}
}
$client = new UserClient();
$userList = $client->service('UserService')->getUserList(16);
//调用order服务下面的方法处理,先获取到OrderService地址,然后在发送TCP协议请求到OrderService服务中,在调用逻辑处理方法
$orderList = $client->service('OrderService')->getOrderList(16);
运行结果
1 . 6 . UserServer.php
用户服务端,负责注册consul服务,接受rpc请求并返回请求数据
<?php
use Swoole\Server;
class UserServer
{
protected $server;
public function __construct()
{
$this->server = new Server("0.0.0.0", 9501);
$this->onConnect();
$this->onReceive();
$this->onClose();
$this->onWorkerStart();
$this->onStart();
$this->start();
$this->server->set(array(
'open_length_check' => true, // 开启协议解析
'package_max_length' => 81920, //包的最大长度
'package_length_type' => 'N', // 长度字段的类型
'package_length_offset' => 0, //从第几个字节是包长度的值
'package_body_offset' => 4, //从第几个字节开始计算长度
));
}
public function onStart()
{
$this->server->on('start', function ($serv) {
require_once './service/RegisterUser.php';
$data = array(
"ID" => "userService",
"Name" => "userService",
"Tags" => ['core.user'],
"Address" => "192.168.48.129",
"Port" => 9501,
"Check" => ["TCP"=>"192.168.48.129:9501","Interval"=>"5s"]
);
//往Consul里注册服务
$consul = new RegisterUser();
$consul->registerService(json_encode($data));
echo 'consul注册用户服务成功'.PHP_EOL;
});
}
public function onWorkerStart()
{
$this->server->on('WorkerStart', function ($serv, $fd) {
require_once './service/UserService.php';
echo "userServer: 启动.\n";
});
}
public function onConnect()
{
$this->server->on('Connect', function ($serv, $fd) {
echo "Hello: user.\n";
});
}
public function onReceive()
{
$this->server->on('Receive', function ($serv, $fd, $from_id, $data) {
echo "Receive: Connect : ".date('Y-m-d H:i:s').PHP_EOL;
//解包网络数据包
$info = unpack('N', $data);
$len = $info[1];
$body = substr($data, - $len);
$data = json_decode($body, true);
$result = 'ok';
if($data){
$service = $data['service'];
$action = $data['action'];
$page = $data['param'];
$class = $service;
$instance = new $class;
$result = json_encode($instance->$action($page));
}
//返回信息到swoole的client端
$serv->send($fd, $result);
});
}
public function onClose()
{
$this->server->on('Close', function ($serv, $fd) {
echo "bye: user.\n";
});
}
public function start()
{
$this->server->start();
}
}
$server = new UserServer();
运行结果
consul服务