閱讀目錄

上一篇文章我們瞭解了如何使用hyperf對專案進行垂直拆分,這是我們整個微服務模組的基礎。

hyperf支援JSON-RPC和gRPC,我們在分散式服務架構一文中介紹過什麼是JSON-RPC以及JSON-RPC請求響應的案例(後來做的補充),後面我們會著重以JSON-RPC為例來解決整個微服務系統出現的各種問題。

首先我們加以明確什麼是服務。

服務有兩種角色,一種是 服務提供者(ServiceProvider),即為其它服務提供服務的服務,另一種是 服務消費者(ServiceConsumer),即依賴其它服務的服務,一個服務既可能是 服務提供者(ServiceProvider),同時又是 服務消費者(ServiceConsumer)。而兩者直接可以通過 服務契約 來定義和約束介面的呼叫,在 Hyperf 裡,可直接理解為就是一個 介面類(Interface),通常來說這個介面類會同時出現在提供者和消費者下。——摘自官網。

簡單的說,我們的專案模組將會被分為服務提供者模組和服務消費者模組。 服務提供者模組指的是提供各種服務的模組,它需要與資料庫進行互動。 服務消費者模組指的是消費服務的模組。它需要遠端訪問服務提供者。

本節課的原始碼已上傳至github,https://github.com/bailangzhan/hyperf-rpc

下面我們按照步驟,看看如何構建服務提供者。

1、建立資料表

  1. CREATE DATABASE hyperf;
  2. USE hyperf;
  3. CREATE TABLE `user` (
  4. `id` int(11) NOT NULL AUTO_INCREMENT,
  5. `name` varchar(30) NOT NULL DEFAULT '' COMMENT '姓名',
  6. `gender` tinyint(1) NOT NULL DEFAULT '0' COMMENT '性別 1男 2女 0未知',
  7. `created_at` int(11) NOT NULL DEFAULT '0' COMMENT '建立時間',
  8. `updated_at` int(11) NOT NULL DEFAULT '0' COMMENT '更新時間',
  9. PRIMARY KEY (`id`)
  10. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用者基礎表';

2、構建服務提供者

  1. composer create-project hyperf/hyperf-skeleton shop_provider_user

安裝的時候會讓我們選擇預設的元件,除了時區和資料庫外,其他一律選擇“n”,選擇如下

  1. What time zone do you want to setup ?
  2. [n] Default time zone for php.ini
  3. Make your selection or type a time zone name, like Asia/Shanghai (n):
  4. Asia/Shanghai
  5. Do you want to use Database (MySQL Client) ?
  6. [y] yes
  7. [n] None of the above
  8. Make your selection or type a composer package name and version (yes): y
  9. - Adding package hyperf/database (~2.2.0)
  10. - Adding package hyperf/db-connection (~2.2.0)
  11. Do you want to use Redis Client ?
  12. [y] yes
  13. [n] None of the above
  14. Make your selection or type a composer package name and version (yes): n
  15. Which RPC protocol do you want to use ?
  16. [1] JSON RPC with Service Governance
  17. [2] JSON RPC
  18. [3] gRPC
  19. [n] None of the above
  20. Make your selection or type a composer package name and version (n): n
  21. Which config center do you want to use ?
  22. [1] Apollo
  23. [2] Aliyun ACM
  24. [3] ETCD
  25. [4] Nacos
  26. [n] None of the above
  27. Make your selection or type a composer package name and version (n): n
  28. Do you want to use hyperf/constants component ?
  29. [y] yes
  30. [n] None of the above
  31. Make your selection (n): n
  32. Do you want to use hyperf/async-queue component ? (A simple redis queue component)
  33. [y] yes
  34. [n] None of the above
  35. Make your selection or type a composer package name and version (n): n
  36. Do you want to use hyperf/amqp component ?
  37. [y] yes
  38. [n] None of the above
  39. Make your selection or type a composer package name and version (n): n
  40. Do you want to use hyperf/model-cache component ?
  41. [y] yes
  42. [n] None of the above
  43. Make your selection or type a composer package name and version (n): n
  44. Do you want to use hyperf/elasticsearch component ?
  45. [y] yes
  46. [n] None of the above
  47. Make your selection or type a composer package name and version (n): n
  48. Do you want to use hyperf/tracer component ? (An open tracing protocol component, adapte with Zipkin etc.)
  49. [y] yes
  50. [n] None of the above
  51. Make your selection or type a composer package name and version (n): n

需要什麼元件後面可以我們再自行新增。

3、安裝json rpc依賴

  1. cd shop_provider_user
  2. composer require hyperf/json-rpc

4、安裝rpc server元件

我們準備讓 shop_provider_user 應用對外提供服務,所以需要安裝 rpc server元件

  1. composer require hyperf/rpc-server

5、修改server配置

shop_provider_user 提供的是 jsonrpc服務,不需要提供http服務,所以遮蔽 http 服務配置,新加 jsonrpc-http 服務。

hyperf支援 jsonrpc-http 協議、jsonrpc 協議以及jsonrpc-tcp-length-check 協議,我們後續都將以 jsonrpc-http為例。

以下配置在 config/autoload/server.php 檔案內,注意 jsonrpc-http服務配置的埠號是9600

  1. 'servers' => [
  2. // [
  3. // 'name' => 'http',
  4. // 'type' => Server::SERVER_HTTP,
  5. // 'host' => '0.0.0.0',
  6. // 'port' => 9501,
  7. // 'sock_type' => SWOOLE_SOCK_TCP,
  8. // 'callbacks' => [
  9. // Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
  10. // ],
  11. // ],
  12. [
  13. 'name' => 'jsonrpc-http',
  14. 'type' => Server::SERVER_HTTP,
  15. 'host' => '0.0.0.0',
  16. 'port' => 9600,
  17. 'sock_type' => SWOOLE_SOCK_TCP,
  18. 'callbacks' => [
  19. Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
  20. ],
  21. ],
  22. ],

6、配置資料庫

修改.env檔案,修改 APP_NAME以及資料庫配置

  1. APP_NAME=shop_provider_user
  2. DB_DRIVER=mysql
  3. DB_HOST=192.168.33.20
  4. DB_PORT=3306
  5. DB_DATABASE=hyperf
  6. DB_USERNAME=www
  7. DB_PASSWORD=123456
  8. DB_CHARSET=utf8mb4
  9. DB_COLLATION=utf8mb4_unicode_ci
  10. DB_PREFIX=

7、編寫基礎程式碼

7-1、編寫model程式碼

生成model並修改如下:

  1. php bin/hyperf.php gen:model User
  2. app/Model/User.php
  3. <?php
  4. declare (strict_types=1);
  5. namespace App\Model;
  6. use Hyperf\DbConnection\Model\Model;
  7. /**
  8. */
  9. class User extends Model
  10. {
  11. /**
  12. * The table associated with the model.
  13. *
  14. * @var string
  15. */
  16. protected $table = 'user';
  17. /**
  18. * The attributes that are mass assignable.
  19. *
  20. * @var array
  21. */
  22. protected $fillable = ['name', 'gender'];
  23. /**
  24. * The attributes that should be cast to native types.
  25. *
  26. * @var array
  27. */
  28. protected $casts = ['id' => 'integer', 'gender' => 'integer'];
  29. // 自定義時間戳的格式 U表示int
  30. protected $dateFormat = 'U';
  31. }

7-2、編寫service程式碼

app下新建JsonRpc目錄,編寫UserService.php和UserServiceInterface.php檔案。

UserServiceInterface 對外提供兩個介面,一個用於建立使用者,一個用於獲取使用者資訊。

  1. UserServiceInterface
  2. <?php
  3. namespace App\JsonRpc;
  4. interface UserServiceInterface
  5. {
  6. public function createUser(string $name, int $gender);
  7. public function getUserInfo(int $id);
  8. }
  9. UserService
  10. <?php
  11. namespace App\JsonRpc;
  12. use App\Model\User;
  13. use Hyperf\RpcServer\Annotation\RpcService;
  14. /**
  15. * @RpcService(name="UserService", protocol="jsonrpc-http", server="jsonrpc-http")
  16. */
  17. class UserService implements UserServiceInterface
  18. {
  19. /**
  20. * @param string $name
  21. * @param string $gender
  22. * @return string
  23. */
  24. public function createUser(string $name, int $gender)
  25. {
  26. if (empty($name)) {
  27. throw new \RuntimeException("name不能為空");
  28. }
  29. $result = User::query()->create([
  30. 'name' => $name,
  31. 'gender' => $gender,
  32. ]);
  33. return $result ? "success" : "fail";
  34. }
  35. /**
  36. * @param int $id
  37. * @return array
  38. */
  39. public function getUserInfo(int $id)
  40. {
  41. $user = User::query()->find($id);
  42. if (empty($user)) {
  43. throw new \RuntimeException("user not found");
  44. }
  45. return $user->toArray();
  46. }
  47. }

注意,在 UserService 類中,我們使用了 @RpcService 註解,記得 use Hyperf\RpcServer\Annotation\RpcService;

@RpcService 共有 4 個引數,也就是 Hyperf\RpcServer\Annotation\RpcService 的4個屬性:

  1. name 屬性為定義該服務的名稱,注意不同的service不要用相同的名字,該名字唯一,Hyperf 會根據該屬性生成對應的 ID 註冊到服務中心去,後面我們會詳細介紹,這裡有個印象就好;
  2. protocol 屬性為定義該服務暴露的協議,目前僅支援 jsonrpc-http, jsonrpc, jsonrpc-tcp-length-check ,分別對應於 HTTP 協議和 TCP 協議下的兩種協議,預設值為 jsonrpc-http,這裡的值對應在 Hyperf\Rpc\ProtocolManager 裡面註冊的協議的 key,它們本質上都是 JSON RPC 協議,區別在於資料格式化、資料打包、資料傳輸器等不同;
  3. server 屬性為繫結該服務類釋出所要承載的 Server,預設值為 jsonrpc-http,該屬性對應 config/autoload/server.php 檔案內 servers 下所對應的 name;
  4. publishTo 屬性為定義該服務所要釋出的服務中心,目前僅支援 consul、nacos 或為空,我們這裡先不做設定,留空

到這裡我們就構建好一個基本的服務提供者了。

postman測試

下面我們測試下這兩個介面是否正常。執行命令 php bin/hyperf.php start 啟動服務,利用postman傳送請求。

  1. 請求地址:http://127.0.0.1:9600
  2. 請求方法:POST
  3. 請求引數
  4. {
  5. "jsonrpc": "2.0",
  6. "method": "/user/createUser",
  7. "params": {
  8. "name": "zhangsan",
  9. "gender": 3
  10. },
  11. "id": "61025bc35e07d",
  12. "context": []
  13. }
  14. header
  15. Content-Type: application/json
  16. 響應結果
  17. {
  18. "jsonrpc": "2.0",
  19. "id": "61025bc35e07d",
  20. "result": "success",
  21. "context": []
  22. }

看下資料表

created_at 和 update_at 這兩個欄位被自動填充。

再利用 postman訪問 /user/getUserInfo 方獲試試。

  1. 請求地址:http://127.0.0.1:9600
  2. 請求方法:POST
  3. 請求引數
  4. {
  5. "jsonrpc": "2.0",
  6. "method": "/user/getUserInfo",
  7. "params": {
  8. "id": 1
  9. },
  10. "id": "61025bc35e07d",
  11. "context": []
  12. }
  13. header
  14. Content-Type: application/json
  15. 響應結果
  16. {
  17. "jsonrpc": "2.0",
  18. "id": "61025bc35e07d",
  19. "result": {
  20. "id": 1,
  21. "name": "zhangsan",
  22. "gender": 3,
  23. "created_at": "1630101991",
  24. "updated_at": "1630101991"
  25. },
  26. "context": []
  27. }

到這裡,我們的服務提供者基本上就構建好了,有同學可能看其他文章介紹還有consul的內容,我們後續還會介紹更多內容,稍安勿躁。

下一節,我們繼續構建服務消費者。