前言
現在微服務很流行,很多的語言都有自己的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