前言
现在微服务很流行,很多的语言都有自己的rpc框架,在同一框架内的微服务之间通信很方便,笔者工作时用到的框架是hyperf,自带jsonrpc、grpc组件,grpc用起来略感繁琐,调试起来也不方便,因此选用jsonrpc-http,损失些许通信成本在可接受范围之内,能用postman调试实在是太方便了。
随着业务和团队的不断发展,开始有多语言开发需求,我们的另一个项目是用go搭建的,hyperf与go之间也打算用jsonrpc,go自带jsonrpc包,但是是jsonrpc1.0的,与hyperf不兼容,经过努力,找到一个jsonrpc2.0的包(go-jsonrpc),与hyperf完美兼容。
hyperf为服务端,go为客户端
hyperf服务端
- comfig/autoload/server.php
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact [email protected]
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
use Hyperf\Server\Server;
use Hyperf\Server\SwooleEvent;
return [
'mode' => SWOOLE_PROCESS,
'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' => (int)env('SERVICE_HTTP_PORT', 3232),
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
],
],
],
'settings' => [
'enable_coroutine' => true,
'worker_num' => swoole_cpu_num(),
'pid_file' => BASE_PATH . '/runtime/hyperf.pid',
'open_tcp_nodelay' => true,
'max_coroutine' => 100000,
'open_http2_protocol' => true,
'max_request' => 100000,
'socket_buffer_size' => 2 * 1024 * 1024,
'buffer_output_size' => 2 * 1024 * 1024,
],
'callbacks' => [
SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
SwooleEvent::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
],
];
- app/JsonRpc/PhpService.php
<?php
namespace App\JsonRpc;
use Hyperf\RpcServer\Annotation\RpcService;
/**
* 注意,如希望通过服务中心来管理服务,需在注解内增加 publishTo 属性
* @RpcService(name="PhpService", protocol="jsonrpc-http", server="jsonrpc-http")
*/
class PhpService
{
public function add(int $a, int $b)
{
return $a + $b;
}
}
go客户端
package main
import (
"fmt"
go_jsonrpc "github.com/iloveswift/go-jsonrpc"
"go-jsonrpc-skeleton/jsonrpc"
)
func main() {
result := new(jsonrpc.Result)
c, _ := go_jsonrpc.NewClient("http", "127.0.0.1", "3232")
err := c.Call("php/add", jsonrpc.Params{
1, 6}, result, false)
// data sent: {"id":"1604283212","jsonrpc":"2.0","method":"php/add","params":{"a":1,"b":6}}
// data received: {"id":"1604283212","jsonrpc":"2.0","result":7}
fmt.Println(err) // nil
fmt.Println(*result) // 7
}
go为服务端,hyperf为客户端
go服务端
- jsonrpc/go_service.go
package jsonrpc
type Go struct {
}
type Params struct {
A int `json:"a"`
B int `json:"b"`
}
type Result = int
func (*Go) Sub(params *Params, result *Result) error {
a := params.A - params.B
*result = interface{
}(a).(Result)
return nil
}
- main.go
package main
import (
go_jsonrpc "github.com/iloveswift/go-jsonrpc"
"go-jsonrpc-skeleton/jsonrpc"
)
func main() {
s, _ := go_jsonrpc.NewServer("http", "127.0.0.1", "3233")
s.Register(new(jsonrpc.Go))
s.Start()
}
hyperf客户端
- comfig/autoload/services.php
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact [email protected]
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'consumers' => [
[
'name' => 'GoService',
'nodes' => [
['host' => '127.0.0.1', 'port' => 3233]
],
],
],
];
- app/JsonRpc/GoServiceConsumer.php
<?php
namespace App\JsonRpc;
use Hyperf\RpcClient\AbstractServiceClient;
class GoServiceConsumer extends AbstractServiceClient
{
/**
* 定义对应服务提供者的服务名称
* @var string
*/
protected $serviceName = 'GoService';
/**
* 定义对应服务提供者的服务协议
* @var string
*/
protected $protocol = 'jsonrpc-http';
public function Sub(int $a, int $b): int
{
return $this->__request(__FUNCTION__, compact('a', 'b'));
}
}
Demo
-
hyperf项目:hyperf-skeleton
-
go项目:go-jsonrpc-skeleton