抽空测试了下hyperf的微服物,基于docker容器,整体来说架构还是很清晰,不需要用户对微服物架构做过多的设置与了解。
顺便一说,hyperf 默认的微服务是基于http协议的,但其实大众认可的还是走tcp传输层协议的比较多,毕竟多了一层封装|解析 和多余的http头文件,对于注重性能的微服物,是没啥意义的。
拉取docker镜像,创建docker容器就不写了。
大致上创建3个容器,1个服务提供者的容器(hyperf),1个服务消费者的容器(hyperf),1个consul容器(非必需,作为服务中心)
1 配置服务提供者(用户服务)
修改server.php,servers中新增 jsonrpc部分,因为用户中心可能需要http对外服务,所以保留了http,新增一个额外的端口给jsonRpc(端口记得在docker容器绑定到服务器)
'servers' => [
[
'name' => 'http',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 9501,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
],
],
[
'name' => 'jsonrpc-http',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 9502,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
],
],
],
新增services.php(配置服务自动发布,非必需)
[
'discovery' => true,
'register' => true,
],
'consumers' => [],
'providers' => [],
'drivers' => [
'consul' => [
'uri' => 'http://172.18.0.7:8500',
'token' => '',
],
],
];
执行命令创建consul组件的配置文件,并配置其中的ip为我们consul容器的ip
php bin/hyperf.php vendor:publish hyperf/consul
创建服务UserService 和对应接口类
namespace App\JsonRpc;
interface UserServiceInterface
{
public function login(string $username, string $password): array;
}
namespace App\JsonRpc;
use Hyperf\RpcServer\Annotation\RpcService;
/**
* 注意,如希望通过服务中心来管理服务,需在注解内增加 publishTo 属性
* @RpcService(name="UserService", protocol="jsonrpc-http", server="jsonrpc-http",publishTo="consul")
*/
class UserService implements UserServiceInterface
{
public function login(string $username, string $password): array
{
// 这里是服务方法的具体实现
if($username == 'test' && $password == 123456){
return [
'status'=>200,
];
}else{
return [
'status'=>500,
'msg'=>'账户密码错误'
];
}
}
}
最后记得启动服务提供者,到此为止服务提供者配置好了
2配置服务消费者并消费服务
新增services.php(配置服务消费者)
return [
// 此处省略了其它同层级的配置
'consumers' => [
[
// name 需与服务提供者的 name 属性相同
'name' => 'UserService',
// 服务接口名,可选,默认值等于 name 配置的值,如果 name 直接定义为接口类则可忽略此行配置,如 name 为字符串则需要配置 service 对应到接口类
'service' => \App\JsonRpc\UserServiceInterface::class,
// 对应容器对象 ID,可选,默认值等于 service 配置的值,用来定义依赖注入的 key
'id' => \App\JsonRpc\UserServiceInterface::class,
// 服务提供者的服务协议,可选,默认值为 jsonrpc-http
// 可选 jsonrpc-http jsonrpc jsonrpc-tcp-length-check
'protocol' => 'jsonrpc-http',
// 负载均衡算法,可选,默认值为 random
'load_balancer' => 'random',
// 这个消费者要从哪个服务中心获取节点信息,如不配置则不会从服务中心获取节点信息
'registry' => [
'protocol' => 'consul',
'address' => 'http://172.18.0.7:8500',
],
// 如果没有指定上面的 registry 配置,即为直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
'nodes' => [
['host' => '127.0.0.1', 'port' => 9504],
],
// 配置项,会影响到 Packer 和 Transporter
'options' => [
'connect_timeout' => 5.0,
'recv_timeout' => 5.0,
'settings' => [
// 根据协议不同,区分配置
'open_eof_split' => true,
'package_eof' => "\r\n",
// 'open_length_check' => true,
// 'package_length_type' => 'N',
// 'package_length_offset' => 0,
// 'package_body_offset' => 4,
],
// 重试次数,默认值为 2,收包超时不进行重试。暂只支持 JsonRpcPoolTransporter
'retry_count' => 2,
// 重试间隔,毫秒
'retry_interval' => 100,
// 当使用 JsonRpcPoolTransporter 时会用到以下配置
'pool' => [
'min_connections' => 1,
'max_connections' => 32,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => 60.0,
],
],
]
],
];
因为我们配置中使用的是自动创建消费类,所以只需要再创建一个消费类的接口类即可
namespace App\JsonRpc;
interface UserServiceInterface
{
public function login(string $username, string $password): array;
}
消费服务
namespace App\Controller;
use Hyperf\Di\Annotation\Inject;
use \App\JsonRpc\UserServiceInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
class IndexController extends AbstractController
{
/**
* @Inject()
* @var UserServiceInterface
*/
private $UserService;
public function login(RequestInterface $request)
{
return $this->UserService->login($request->query('username'),$request->query('password'));
}
}
最后一样启动项目。
理论上到这一部就完成了基本的微服务架构的配置与使用了,当然还有很多如并发配置等细节需要实际使用中去注意。
最后说下初步使用的感受:
由于swoole提供的高性能协程,使得php的并发性能指数增长,我的垃圾单核心2G云服务器,跑个300Rps毫无压力。
这也使得对于并发天生有一定的性能要求的微服务架构能够通过php语言来实现了。
微服物架构(rpc远程过程调用) 和我们常用的基于api的多服务串接最大的区别
1、api通常基于http请求,rpc通常基于tcp请求,所以性能更优异。当然不绝对,google的grpc 和hyperf默认支持的都是基于http请求的rpc.
2、rpc模式,服务提供方和使用方都需要使用rpc框架实现服务的注册和发现,管理等等。 api模式则不需要,需要的是定义好各种api和参数。通用性更强。
3、rpc模式,我们所有的服务提供方和消费方都需要遵循同样的interface接口文件去进行服务使用,更适合团队协作,而且提供方也更容易在功能未实现前提供模拟实现,方便双方功能测试的解耦。
综合而言,他们实现的目标是相似的,广义上基于http请求的api模式实现的也属于rpc.
他们的区别更像是设计模式上的区别而非协议上的。rpc是牺牲了通用性、可读性来换取性能的优势。分场合使用即可。