hyperf从零开始构建微服务(一)——构建服务提供者

阅读目录

上一篇文章我们了解了如何使用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、创建数据表

CREATE DATABASE hyperf;
USE hyperf;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL DEFAULT '' COMMENT '姓名',
  `gender` tinyint(1) NOT NULL DEFAULT '0' COMMENT '性别 1男 2女 0未知',
  `created_at` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
  `updated_at` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户基础表';

2、构建服务提供者

composer create-project hyperf/hyperf-skeleton shop_provider_user

安装的时候会让我们选择默认的组件,除了时区和数据库外,其他一律选择“n”,选择如下

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):
Asia/Shanghai
  Do you want to use Database (MySQL Client) ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (yes): y
  - Adding package hyperf/database (~2.2.0)
  - Adding package hyperf/db-connection (~2.2.0)
  Do you want to use Redis Client ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (yes): 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): n
  Which config center do you want to use ?
  [1] Apollo
  [2] Aliyun ACM
  [3] ETCD
  [4] Nacos
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/constants component ?
  [y] yes
  [n] None of the above
  Make your selection (n): n
  Do you want to use hyperf/async-queue component ? (A simple redis queue component)
  [y] 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/amqp component ?
  [y] 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/model-cache component ?
  [y] 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/elasticsearch component ?
  [y] 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 ? (An open tracing protocol component, adapte with Zipkin etc.)
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n

需要什么组件后面可以我们再自行添加。

3、安装json rpc依赖

cd shop_provider_user
composer require hyperf/json-rpc

4、安装rpc server组件

我们准备让 shop_provider_user 应用对外提供服务,所以需要安装 rpc server组件

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

'servers' => [
//        [
//            'name' => 'http',
//            'type' => Server::SERVER_HTTP,
//            'host' => '0.0.0.0',
//            'port' => 9501,
//            'sock_type' => SWOOLE_SOCK_TCP,
//            'callbacks' => [
//                Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
//            ],
//        ],
    [
        'name' => 'jsonrpc-http',
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9600,
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
        ],
    ],
],

6、配置数据库

修改.env文件,修改 APP_NAME以及数据库配置

APP_NAME=shop_provider_user
DB_DRIVER=mysql
DB_HOST=192.168.33.20
DB_PORT=3306
DB_DATABASE=hyperf
DB_USERNAME=www
DB_PASSWORD=123456
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
DB_PREFIX=

7、编写基础代码

7-1、编写model代码

生成model并修改如下:

php bin/hyperf.php gen:model User
【app/Model/User.php】
<?php
declare (strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
 */
class User extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'user';
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name', 'gender'];
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = ['id' => 'integer', 'gender' => 'integer'];
    // 自定义时间戳的格式 U表示int
    protected $dateFormat = 'U';
}

7-2、编写service代码

app下新建JsonRpc目录,编写UserService.php和UserServiceInterface.php文件。

UserServiceInterface 对外提供两个接口,一个用于创建用户,一个用于获取用户信息。

【UserServiceInterface】
<?php
namespace App\JsonRpc;
interface UserServiceInterface
{
    public function createUser(string $name, int $gender);
    public function getUserInfo(int $id);
}
【UserService】
<?php
namespace App\JsonRpc;
use App\Model\User;
use Hyperf\RpcServer\Annotation\RpcService;
/**
 * @RpcService(name="UserService", protocol="jsonrpc-http", server="jsonrpc-http")
 */
class UserService implements UserServiceInterface
{
    /**
     * @param string $name
     * @param string $gender
     * @return string
     */
    public function createUser(string $name, int $gender)
    {
        if (empty($name)) {
            throw new \RuntimeException("name不能为空");
        }
        $result = User::query()->create([
            'name' => $name,
            'gender' => $gender,
        ]);
        return $result ? "success" : "fail";
    }
    /**
     * @param int $id
     * @return array
     */
    public function getUserInfo(int $id)
    {
        $user = User::query()->find($id);
        if (empty($user)) {
            throw new \RuntimeException("user not found");
        }
        return $user->toArray();
    }
}

注意,在 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发送请求。

请求地址:http://127.0.0.1:9600
请求方法:POST
请求参数
{
    "jsonrpc": "2.0",
    "method": "/user/createUser",
    "params": {
        "name": "zhangsan",
        "gender": 3
    },
    "id": "61025bc35e07d",
    "context": []
}
header头
Content-Type: application/json
响应结果
{
    "jsonrpc": "2.0",
    "id": "61025bc35e07d",
    "result": "success",
    "context": []
}
image

看下数据表

image

created_at 和 update_at 这两个字段被自动填充。

再利用 postman访问 /user/getUserInfo 方获试试。

请求地址:http://127.0.0.1:9600
请求方法:POST
请求参数
{
    "jsonrpc": "2.0",
    "method": "/user/getUserInfo",
    "params": {
        "id": 1
    },
    "id": "61025bc35e07d",
    "context": []
}
header头
Content-Type: application/json
响应结果
{
    "jsonrpc": "2.0",
    "id": "61025bc35e07d",
    "result": {
        "id": 1,
        "name": "zhangsan",
        "gender": 3,
        "created_at": "1630101991",
        "updated_at": "1630101991"
    },
    "context": []
}

到这里,我们的服务提供者基本上就构建好了,有同学可能看其他文章介绍还有consul的内容,我们后续还会介绍更多内容,稍安勿躁。

下一节,我们继续构建服务消费者。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容