PHP微服务 hyperf+nacos使用
PHP微服务使用 hyper+nacos使用
PHP微服务 hyperf+nacos使用
这里简单说下微服务,及架构方面东西
1:微服务对php +fpm 模式意义不是很大,原因就是php+fpm 天生支持模块拆分,热更新,如果只是性能上的考虑,那php+fpm 还是比较耗cpu的,这样用微服务就不如单体+多库的方案,即一个项目拆分多个数据库,不同业务调用对应的库即可
2:微服务可不可以直接调用http 接口?
答案是可以的,都是自己公司内部的项目,并且项目不是说特别大,完全可以直接通过接口,这里注意几个点:
a:保证这些接口通过内网调用,毕竟走外网时间是比较长的
b:Http接口默认为同步调用,当需要同时调用多个服务时,考虑接口时间问题
c:定义好规范,写好文档
3:微服务的服务治理方式
a:现在流行的都是统一服务治理中心(nacos/zookeeper)及 统一配置管理服务;
优点就是: 统一管理,动态增减,及时上下线
缺点是: 多个服务集中到了一起,容易形成瓶颈压力,多一层服务增加了系统的复杂性,在性能测试时需要考虑服务中心的压力
b:服务自治模式,即每个服务提供统一的对外域名,由服务内部自己负载均衡实现减压,这样可以省去服务治理这一层,也不需要服务一直ping 治理中心;
缺点就是新增服务得手动添加到负载均衡器里
这里主要记录使用统一治理中心(nacos) 跟hyerf 搭建微服务的过程及注意点
nacos 安装
官网链接:https://nacos.io/zh-cn/docs/quick-start.html
建议 直接下载nacos编译包解压后,开箱即用,这里注意配置,官方建议最低 2c 4g 太低可能导致启动失败
unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
cd nacos/bin
启动建议先用单机模式
启动命令(standalone代表着单机模式运行,非集群模式):
sh startup.sh -m standalone
管理后台连接,默认账号 nacos 密码nacos
http://host:8848/nacos/
注意端口是否有放开,生产环境建议端口白名单方式,因为更新删除服务是不需要账号密码的,外网很容易被人攻击
PS:nacos 服务默认会健康检测,30s内没有心跳会默认删除,所以自己后台创建的 可能过一会就不见了,不要大惊小怪,还有通过api服务,创建要注意对应的命名空间,命名空间一定要在服务端先创建好,不然直接添加是不会在后端显示的,不熟悉的以为是bug
Hyperf 使用(下面流程都是参照官方文档,这里说明下注意点)
官网:https://hyperf.wiki/2.2
一:根据文档安装好 swoole,跟Hyperf框架
二:配置rpc 个服务 主要下面2个文档里
1:https://hyperf.wiki/2.2/#/zh-cn/json-rpc
2:https://hyperf.wiki/2.2/#/zh-cn/service-register
这里主要说下注意的
1:rpc 服务注解需要加上publishTo=“nacos” 才会同步到到nacos
<?php
/**
* 测试微服务提供者
* Created by PhpStorm.
* User: 05
* Date: 2022/8/10
* Time: 10:06
*/
namespace App\JsonRpc;
use Hyperf\RpcServer\Annotation\RpcService;
/**
* 注意,如希望通过服务中心来管理服务,需在注解内增加 publishTo 属性
* @RpcService(name="CaculatorService", protocol="jsonrpc-http", server="jsonrpc-http",publishTo="nacos")
*/
class CaculatorService extends DefaultService
{
/**
* @param int $a
* @param int $b
* @return int
*/
public function add(array $pms)
{
return $pms['a']+$pms['b']+10;
}
public function get(array $pms)
{
return parent::get($pms); // TODO: Change the autogenerated stub
}
}
2:配置config/autoload/services.php 的 namespace_id 需要提前在nacos 后台新增命名空间,获取对应的id,随便填写一个链接上nacos 也不会在nacos后台显示的
3:作为消费者端使用nacos的话 在config/autoload/services.php 也是要配置服务驱动相关配置drivers (服务提供端可以不配置consumers),不然获取不到服务
配置如下
return [
'enable' => [
// 开启服务发现
'discovery' => true,
// 开启服务注册
'register' => true,
],
// 服务消费者相关配置
//服务消费者
'consumers' => [
[
// 对应消费者类的 $serviceName
'name' => 'CaculatorService',
// 这个消费者要从哪个服务中心获取节点信息,如不配置则不会从服务中心获取节点信息
'registry' => [
'protocol' => 'nacos',
'address' => 'http://127.0.0.1:8848',
],
// 如果没有指定上面的 registry 配置,即为直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
// 'nodes' => [
// ['host' => '127.0.0.1', 'port' => 9513],
// ],
],
[
// 对应消费者类的 $serviceName
'name' => 'DefaultService',
// 这个消费者要从哪个服务中心获取节点信息,如不配置则不会从服务中心获取节点信息
'registry' => [
'protocol' => 'nacos',
'address' => 'http://127.0.0.1:8848',
],
// 如果没有指定上面的 registry 配置,即为直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
// 'nodes' => [
// ['host' => '127.0.0.1', 'port' => 9513],
// ],
]
],
// 服务提供者相关配置
'providers' => [],
// 服务驱动相关配置
'drivers' => [
// 'consul' => [
//
// ],
'nacos' => [
// nacos server url like https://nacos.hyperf.io, Priority is higher than host:port
// 'url' => '',
// The nacos host info
'host' => '127.0.0.1',
'port' => 8848,
// The nacos account info
'username' => 'nacos',//可以不用配置
'password' => '',//似乎可以不用密码
'guzzle' => [
'config' => null,
],
'group_name' => 'api',
'namespace_id' => '950fdb39-edeb-4978-8ab6-3cf742732449',//这个要从nacos 后台获取
'heartbeat' => 5,
'ephemeral' => false, // 是否注册临时实例
],
],
];
链接成功后
使用&优化:
按照官方的使用方式是
服务提供者Service写好对应类 通过注解 RpcService 对外提供服务
服务消费者Consumer 需要写对应的类跟方法,之后才能调用
这里就会有个问题,如果一个服务被很多项目调用,那提供者每添加一个服务 其他的消费者都要对应添加一个服务类或者修改对应的方法,这个对消费者非常不友好,服务多了需要浪费大量的时间互相同步
简单优化
消费端提供默认消费者 DefaultConsumer ,生成唯一get 方法 通过传入方法名跟参数调用对应的服务,这样服务端新增一个服务时 消费者端就不在需要写对应的消费类,但这里要求服务接收的参数就只有一个数组,通过数组约定里面的参数(这里还是要生成对应的消费端类继承DefaultConsumer,将$serviceName 默认好,Hyperf 通过容器绑定了对象,初始化就会获取此属性,没法更改,如果自己new DefaultConsumer 会造成内存泄露,随着访问量上升cpu 跟内存很快就爆满…)
代码如下
DefaultConsumer
<?php
/**
* Created by PhpStorm.
* User: 05
* Date: 2021/11/25
* Time: 15:00
*/
namespace App\JsonRpc;
use Hyperf\Rpc\Protocol;
use Hyperf\Rpc\ProtocolManager;
use Hyperf\RpcClient\AbstractServiceClient;
use Hyperf\RpcClient\Client;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerInterface;
use function Swoole\Coroutine\Http\get;
class DefaultConsumer extends AbstractServiceClient
{
/**
* 定义对应服务提供者的服务名称
* @var string
*/
protected $serviceName = 'DefaultService';
/**
* 定义对应服务提供者的服务协议
* @var string
*/
protected $protocol = 'jsonrpc-http';
public function get(string $method, array $parms)
{
return $this->__request($method, ['pms'=>$parms]);
}
}
CalculatorServiceConsumer
<?php
/**
* Created by PhpStorm.
* User: 05
* Date: 2021/11/25
* Time: 15:00
*/
namespace App\JsonRpc;
class CalculatorServiceConsumer extends DefaultConsumer
{
/**
* 只需要改这个属性,方法实现可以不要,直接通过参数传递
* @var string
*/
protected $serviceName = 'CaculatorService';
}
测试
消费者代码
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Controller;
use App\JsonRpc\DefaultConsumer;
use function EasyWeChat\Kernel\Support\get_server_ip;
use Hyperf\HttpServer\Annotation\AutoController;
/**
* @AutoController();需要引入对应的文件
* */
class IndexController extends BaseController
{
public function rpc_test(){
//这里不要自己new 实例,不然内存泄露...
$cus= ApplicationContext::getContainer()->get(CalculatorServiceConsumer::class);
$d= $cus->get("add",['a'=>1,'b'=>2]);
return [
'本机ip' => get_server_ip(),
'message' => "微服务调用结果=$d",
];
}
}
服务提供者代码
<?php
/**
* 测试微服务提供者
* Created by PhpStorm.
* User: 05
* Date: 2022/8/10
* Time: 10:06
*/
namespace App\JsonRpc;
use Hyperf\RpcServer\Annotation\RpcService;
/**
* @RpcService(name="CaculatorService", protocol="jsonrpc-http", server="jsonrpc-http",publishTo="nacos")
*/
class CaculatorService extends DefaultService
{
/**
* @param int $a
* @param int $b
* @return int
*/
public function add(array $pms)
{
return "远端调用结果:".(($pms['a']+$pms['b'])*10);//这里是远端特意乘以10
}
}
结果
注册中心下线服务后,再调用就不可用了
更多推荐
所有评论(0)