当前位置: 首页 > 后端技术 > PHP

PhpRpc从0到0.7

时间:2023-03-29 20:48:34 PHP

1。什么是RPCRPC?业务场景:以大多数phper都接触过的一个商城开发为例。一般商城有以下几个模块:商品模块、订单模块、会员模块、XX模块。Provider,架构体现:在这个架构中,业务机的职责是将一个请求拆分成N个小请求,分发给各个服务,然后整合各个服务的结果返回给用户。比如某个订单请求,发送的逻辑大致如下:1.业务机接受请求2.业务机提取用户参数,请求用户服务,获取用户余额等信息,等待结果3、商机提取商品参数,请求商品服务,获取商品剩余库存、价格等信息,等待结果。4、商机整合用户服务和商品服务的返回结果,进行下一步调用(假设满足购买条件)。5、业务机调用用户服务扣款,调用商品服务扣库存,调用订单服务下单(交易逻辑和提现可以通过请求id来保证,或者其他逻辑调度可自行实现)6、上述业务机根据处理响应用户的行为称为远程过程调用。调用进程可以实现多种通信协议,比如常见的HTTP和TCP协议。当一个服务出现故障或异常时,直接对整个服务进行熔断,而不是等到服务超时,服务降级。当一个服务被熔断后,服务器将不再被调用。这时候客户端可以准备一个本地回退。,返回默认值。这样做虽然降低了服务水平,但总比直接挂断要好。服务降级处理在客户端完成,与服务器端无关。比如一台服务器最多只能同时处理100个请求,或者当CPU负载达到80%时,为了保障服务的稳定性,你不再期望接收到新的连接。那么这个时候就要求客户端不再向它发起请求。例如,您可以以任何形式监控您的服务。当触发某种条件时(CPU负载80%),服务会下线,业务机会动态获取服务节点。当可以知道服务已经被限时,再响应用户【网络繁忙,请稍后再试】或者该服务由多台机器提供,其他机器可以继续提供服务,下线后再上线机器恢复2.PhpTcp通信源码https://github.com/ar414-com/...开发环境要求PHP版本大于等于7.2,Swoole扩展版本大于或等于4.3.5。作者使用Linux/FreeBSD/MacOS开发三种操作系统环境PHP7.2Swoole4.3.5CentOS7.2创建一个基本的TCP服务器on('Start',function($serv){echo"服务已经启动,主进程PID:{$serv->master_pid}\n";});//监听连接入口事件$serv->on('Connect',function($serv,$fd){echo"Client:Connect.\n";});//监听数据接收事件$serv->on('Receive',function($serv,$fd,$from_id,$data){echo"接收客户端数据:{$data}\n";$serv->send($fd,"Server:".$data);});//监听连接关闭事件$serv->on('Close',function($serv,$fd){echo"Client:Close.\n";});//启动服务器$serv->start();'Goods',//服务名称'action'=>'getList',//具体方法'arg'=>['page'=>1]//请求参数];//用户信息$data=['service'=>'User',//服务名称'action'=>'getUserInfoForToken',//具体method'arg'=>['token'=>'6aa62603ef82b70597a90d93af04b542']//请求参数];//打包数据$dataStr=serialize($data);$dataStr=pack('N',strlen($str)).$海峡;请求API网关API网关根据Service参数自动查询对应的服务IP和PORT并回调。本示例是为了方便将Rpc服务配置写入.env文件示例://.envRPC_GOODS_HOST=10.0.0.1RPC_GOODS_PORT=8899RPC_USER_HOST=10.0.0.2RPC_USER_PORT=8899服务器处理请求(完整代码)//接受请求数据并unpack$data=substr($request,'4');$data=unserialize($data);//TODO检测必须有参数服务动作//检查服务是否存在//$controllerNameSpace是你的控制器命名空间$service=ucfirst($data['service']);$class="{$controllerNameSpace}\\{$service}";if(!class_exists($class)){//TODO服务不存在//设置响应状态错误码(需要封装)$response->setStatus(Response::STATUS_SERVICE_SERVICE_NOT_FOUND);//响应客户端(需要封装)gotoresponse;}//检查方法是否存在$class=new\ReflectionClass($class);$action=$data['action'];if(!$class->hasMethod($action)){//action不存在//重新组装参数//如果调用了该方法,则调用魔术方法,比如调用一些PDO方法,如果没有,调用$request->proxyActionAssemblyArg()时return方法不存在;$method=$class->getMethod('__call');}else{$method=$class->getMethod($action);}//调用$instance=$class->newInstance($request,$response);$ret=$method->invokeArgs($instance,$request->getArg());$response->setMessage($ret);//对客户端的响应(需要自己封装)gotoresponse;//作者的响应封装(仅供参考):response:{if($server->exist($fd)){$message=$response->getMessage();$responseData=['status'=>$response->getStatus(),'data'=>$message];$responseData=序列化($responseData);$responseData=Request::pack($responses电子数据);$server->send($fd,$responseData);//判断客户端是否需要长连接if(!$request->getIsKeep()){$server->close($fd);}}}