文章目錄
- 前言
- 一、微服務的場景演化
- 1、一開始
- 2、隨著業務發展...
- 3、改造...
- 二、微服務與單體架構風格之間的區別
- 三、關于微服務存在的一些問題
- 四、RPC的那些事
- 1.概念
- 2、RPC或者RESTful API
- 3、使用hyperf框架搭建RPC服務
- 總結
前言
首先,微服務是一種思想,是一種將單個應用程式開發成為一組小服務得方法,每個小服務都在自己的行程中運行并與輕量化機制(通常是HTTP資源API)進行通訊,這些服務圍繞著業務功能構建,并且可以由全自動部署機制獨立部署,
一、微服務的場景演化
1、一開始
最初的需求:一開始的需求是相當的簡單,只需做一個簡單的網上商城并掛在公網上就可以賺錢了,這個時候如下圖的架構即可滿足要求,

2、隨著業務發展…
這個時候需要加入資料分析以及移動端相關開發模塊,

可以看出,這個階段存在許多不合理的地方:
移動端和網站有許多同樣冗余的代碼,
單個應用為了為其他應用提供介面,包含了很多不屬于它的邏輯,
所有的應用都在一個資料庫上操作,資料庫出現性能瓶頸,特別是資料分析跑起來的時候,資料庫性能急劇下降,
3、改造…
隨著問題的逐漸增多,需要進行微服務改造,需要對專案冗余的代碼進行抽象整理出來,微服務改造實際上也是一個抽象的功能,

但是這樣子會有一個問題,資料庫是共用的,隨著時間的推移,總會有一個服務直接從資料庫取另一個服務資料的現象,
如果一直保持共用資料庫的模式,則整個架構會越來越僵化,失去了架構的意義,所以在這里我們一并把資料庫進行拆分,如下圖

二、微服務與單體架構風格之間的區別
這種單體應用程式是最自然的構建系統的方式,所有請求的處理都到單體應用程式的行程內,采用應用程式開發語言的基本特性把它拆分成不同的包、類和函式中從而實作模塊化,可以在開發者的便攜機上開發和測驗單體應用,可以采用部署流水線把測驗后的應用程式部署到生產環境中,可以增加更多負載均衡器后面的實體數量來水平的擴展服務能力,
單體應用程式可以做的很好,但人們也越來越發現問題,尤其是把應用程式部署到云上以后,變更被捆綁在一起,單體應用程式中一個小的改變都需要整個程式重新部署,時間長了保持模塊化的架構也會比較困難,本應影響一個模塊的變更也很難做到僅影響單個模塊,單個模塊的伸縮需要整個程式來伸縮,這也導致需要更多的資源,這些問題就導致了人們自然而然地想到了微服務架構,把程式構建成一系列服務,每個服務可以獨立部署和伸縮,每個服務也定義了清晰的邊界,不同的服務可以采用不同的語言撰寫,不同的團隊來維護,
正是單體架構的這些問題,才使得微服務風格的架構得以發展,微服務除了服務是可獨立部署、可獨立擴展的之外,每個服務都提供一個固定的模塊邊界,甚至允許不同的服務用不同的的語言開發,由不同的團隊管理,下面文章探討一下微服務所具有的共同特征,
三、關于微服務存在的一些問題
1、穩定性下降,服務數量變多導致其中一個服務的概率變大,并且一個服務故障可能導致整個系統崩潰,事實上,在大訪問前提下,故障總會出現的,
2、微服務架構整個應用分散服務,定位故障點非常困難,
3、測驗方面:服務拆分后,幾乎所有功能都會涉及多個服務,原本單個程式的測驗變為服務間呼叫的測驗,測驗變得更加復雜,
解決方案:
①盡量減少故障發生的概率
②降低故障造成的影響,
四、RPC的那些事
1.概念
顧名思義,PPC是Remote Procedure Call Protocol的縮寫,既遠程程序呼叫,
RPC框架,要向呼叫方屏蔽各種復雜性,要向服務提供方也屏蔽各類復雜性:
1、服務呼叫方client感覺就像呼叫本地函式一樣,來呼叫服務,
2、服務提供方server感覺就像實作一個本地函式一樣,來實作服務,
2、RPC或者RESTful API
RPC就用于呼叫者與服務之間的通訊,RPC協議可基于TCP、UDP或者HTTP實作,但是更推薦選擇TCP,
1、TCP的支持保持連接,當呼叫服務的時候不需要每次都進行三次握手才實作,從性能和網路消耗來說RPC都具備了很好的優勢,
2、RESTful API 基于HTTP的,也就是說每次呼叫服務都需要進行三次握手建立起通信才可以實作呼叫,當我們的并發量高的時候這就會浪費很多帶寬資源
服務對外的話采用RESTful API會比RPC更具備優勢,因此看自己團隊的服務是對內還是對外

3、使用hyperf框架搭建RPC服務
1、hyperf給我們提供了RPC的底層服務,我們并不需要去關心底層通訊細節和呼叫的程序,
2、hyperf通過定義介面,實作介面,啟動RPC Server 提供介面服務,我們只需要簡單的寫好幾個類就可以實作一個簡單RPC模塊,
搭建環境:
一、分別在兩臺虛擬機上搭建兩套hyperf環境,
搭建程序:
centor7下安裝docker
yum -y install docker-ce --nobest
啟動docker
systemctl start docker
systemctl enable docker
下載hyperf環境鏡像
docker pull hyperf/hyperf
檢查鏡像是否下載成功
docker images
回到根目錄,運行容器
docker run -itd --network host -v $PWD/first_hyperf:/first_hyperf --name first_hyperf hyperf/hyperf
這個時候我們已經進入到容器里面了,

我們進入到我們新建的first_hyperf檔案里面去,
將composer源置為國內源,加快下載速度,
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer
新建hyperf專案
composer create-project hyperf/hyperf-skeleton client
安裝配置如下:
What time zone do you want to setup ?
[n] Default time zone for php.ini
Make your selection or type a time zone name, like Asia/Shanghai (n): n
Which RPC protocol do you want to use ?
[1] JSON-RPC with Service Governance
[2] JSON-RPC
[3] gRPC
[n] None of the above
Make your selection or type a composer package name and version (n): 2
Which config center do you want to use ?
[1] Apollo
[2] Aliyun ACM
[n] None of the above
Make your selection or type a composer package name and version (n): 1
Do you want to use hyperf/constants component ?
[1] yes
[n] None of the above
Make your selection (n): 1
Do you want to use hyperf/async-queue component ? (A simple redis queue component)
[1] yes
[n] None of the above
Make your selection or type a composer package name and version (n): 1
Do you want to use hyperf/amqp component ?
[1] yes
[n] None of the above
Make your selection or type a composer package name and version (n): 1
Do you want to use hyperf/model-cache component ?
[1] yes
[n] None of the above
Make your selection or type a composer package name and version (n): 1
Do you want to use hyperf/elasticsearch component ?
[1] yes
[n] None of the above
Make your selection or type a composer package name and version (n): n
Do you want to use hyperf/tracer component ? (A open tracing protocol component, adapte with Zipkin etc.)
[1] yes
[n] None of the above
Make your selection or type a composer package name and version (n): 1
安裝 JSON RPC 服務端:
composer require hyperf/rpc-server
安裝 JSON RPC 客戶端:
composer require hyperf/rpc-client
運行hyperf框架
# 進入安裝好的 Hyperf 專案目錄
cd hyperf-skeleton
# 啟動 Hyperf
php bin/hyperf.php start


運行成功,
關閉容器
docker stop 容器id
重新進入容器
docker exec -it 容器id bash
安裝完畢,另外一臺服務器也同理安裝,
開始搭建RPC
服務端代碼撰寫
編輯IndexController.php檔案:
<?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 Hyperf\Utils\Context;
use Hyperf\Utils\Coroutine;
use Hyperf\Utils\Parallel;
use Hyperf\Utils\ApplicationContext;
use App\JsonRpc\CalculatorService;
use App\JsonRpc\MathValue;
class IndexController extends AbstractController
{
public function index()
{
$user = $this->request->input('user', 'Hyperf');
$method = $this->request->getMethod();
return [
'method' => $method,
'message' => "Hello {$user}.",
];
}
public function add()
{
$client = ApplicationContext::getContainer()->get(CalculatorService::class);
$value = $client->add(10, 20);
return $value;
}
}
在app下新增JsonRpc目錄并新增CalculatorService.php和CalculatorServiceInterface.php檔案,
CalculatorService.php
<?php
namespace App\JsonRpc;
use Hyperf\RpcServer\Annotation\RpcService;
/**
* 注意,如希望通過服務中心來管理服務,需在注解內增加 publishTo 屬性
* @RpcService(name="CalculatorService", protocol="jsonrpc", server="jsonrpc")
*/
class CalculatorService implements CalculatorServiceInterface
{
public function add(int $v1, int $v2): int
{
return $v1 + $v2;
// TODO: Implement add() method.
}
}
CalculatorServiceInterface.php
<?php
declare(strict_types=1);
namespace App\JsonRpc;
interface CalculatorServiceInterface
{
public function add(int $v1, int $v2): int;
}
route.php
<?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
*/
use Hyperf\HttpServer\Router\Router;
Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
Router::addRoute(['GET', 'POST', 'HEAD'],'/add', 'App\Controller\IndexController@add');
Router::get('/favicon.ico', function () {
return '';
});
server.php
<?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
*/
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' => 9601,
'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' => 9604,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
],
],
[
'name' => 'jsonrpc',
'type' => Server::SERVER_BASE,
'host' => '0.0.0.0',
'port' => 9603,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_RECEIVE => [\Hyperf\JsonRpc\TcpServer::class, 'onReceive'],
],
'settings' => [
'open_eof_split' => true,
'package_eof' => "\r\n",
'package_max_length' => 1024 * 1024 * 2,
],
],
],
'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'],
],
];
消費端代碼撰寫
IndexController.php
<?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 Hyperf\Utils\Context;
use Hyperf\Utils\Coroutine;
use Hyperf\Utils\Parallel;
use Hyperf\Utils\ApplicationContext;
use App\JsonRpc\CalculatorServiceInterface;
use function PHPStan\dumpType;
class IndexController extends AbstractController
{
public function index()
{
$user = $this->request->input('user', 'Hyperf');
$method = $this->request->getMethod();
return [
'method' => $method,
'message' => "Hello {$user}.",
];
}
public function add()
{
$client = ApplicationContext::getContainer()->get(CalculatorServiceInterface::class);
$value = $client->add(10, 20);
return $value;
}
}
CalculatorServiceInterface.php
<?php
declare(strict_types=1);
namespace App\JsonRpc;
interface CalculatorServiceInterface
{
public function add(int $v1, int $v2): int;
}
server.php
<?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
*/
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' => 9504,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
],
],
[
'name' => 'jsonrpc',
'type' => Server::SERVER_BASE,
'host' => '0.0.0.0',
'port' => 9503,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
SwooleEvent::ON_RECEIVE => [\Hyperf\JsonRpc\TcpServer::class, 'onReceive'],
],
'settings' => [
'open_eof_split' => true,
'package_eof' => "\r\n",
],
],
],
'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'],
],
];
service.php
<?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
*/
return [
'consumers' => [
[
// The service name, this name should as same as with the name of service provider.
'name' => 'CalculatorService',
// The service registry, if `nodes` is missing below, then you should provide this configs.
// 服務介面名,可選,默認值等于 name 配置的值,如果 name 直接定義為介面類則可忽略此行配置,如 name 為字串則需要配置 service 對應到介面類
'service' => \App\JsonRpc\CalculatorServiceInterface::class,
// 服務提供者的服務協議,可選,默認值為 jsonrpc-http
'protocol' => 'jsonrpc',
// 負載均衡演算法,可選,默認值為 random
'load_balancer' => 'random',
// 對應容器物件 ID,可選,默認值等于 service 配置的值,用來定義依賴注入的 key
'id' => \App\JsonRpc\CalculatorServiceInterface::class,
// If `registry` is missing, then you should provide the nodes configs.
'nodes' => [
// Provide the host and port of the service provider.
['host' => '192.168.227.129', 'port' => 9603]
],
// 配置項,會影響到 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,
],
// 當使用 JsonRpcPoolTransporter 時會用到以下配置
'pool' => [
'min_connections' => 1,
'max_connections' => 32,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => 60.0,
],
]
],
],
];
分別進入這兩臺主機,分別把服務端和消費者端啟動起來,

服務端運行截圖

消費者端運行截圖

另外一臺主機同理運行,
驗證:
我們訪問消費者端:

我們達到了我們的目的,我們訪問消費者端,然后消費者端通過jsonrpc發送tcp請求到服務器端的計算服務,
總結
以上就是關于rpc技術的 演化以及一些 使用場景,并 簡單介紹什么是rpc以及如何使用hyperf框架搭建rpc服務的程序,希望對大家的學習有些許的幫助,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/224110.html
標籤:其他
