モノリシックサービス開発のベストプラクティスに進む

モノリシックベストプラクティスの起源

  • 多くの新興企業にとって、ビジネスの初期段階では、ビジネス価値の提供に重点を置く必要があります。またQPS、現時点ではユーザー数も非常に少なく、非常に少ないです。よりシンプルな技術アーキテクチャを使用して、ビジネスの提供を加速する必要があります。ビジネス価値。これは、単一ユニットの利点が反映されています。
  • 生放送を共有する際によく言ったように、モノマーを使ってビジネス価値を迅速に提供する一方で、ビジネスの発展の可能性も確保する必要があります。ビジネスモジュールをモノマーに明確に分割できます。
  • go-zeroコミュニティには、モノリシック開発のベストプラクティスを尋ねる小さなパートナーもたくさんいます。

go-zero広く使われているプログレッシブマイクロサービスフレームワークとして、私は複数の大規模プロジェクトの完全な開発プロセスでそれを生み出しました。当然、単一サービス開発のシナリオも十分に検討しました。

go-zeroに示すように使用されるモノリシックアーキテクチャは、Service複数のモノリシックサービスを含む大規模なビジネスもサポートできますPod

この記事では、複数のモジュールを使用して単一のサービスをgo-zero迅速にます。

モノリスの例

単一サービスのアップロードとダウンロードを使用して、go-zero単一が、なぜそのような例を使用するのでしょうか。

  • go-zeroコミュニティには、アップロードするファイルを定義し、それを使用して自動的に生成するAPI方法を尋ねる学生がよくいます。goctlこのような問題を最初に目にするのは不思議ですが、このようなサービスをOSS利用か?多くのシナリオでは、ユーザーがExcelをアップロードする必要があり、サーバーは解析後にファイルを破棄することがわかっています。1つはファイルが小さいこと、もう1つはユーザー数が少ないことですので、このような複雑なプロセスOSSをかなり合理的だと思います。

  • go-zeroコミュニティの一部の学生は、APIファイルgoctlて自動的に生成することにより、ファイルをダウンロードする方法も尋ねました。このような問題がGoを介して行われる理由は、2つあります。1つは、ビジネスの開始時にサービスをデプロイするだけで1つを取得できること、もう1つはgo-zero、組み込みのJWT自動認証を使用できることを期待することです。

これは単なる例であり、を介してアップロードとダウンロードを実装する必要Goがある。次に、このような単一のサービスをどのように解決go-zeroできる。これをファイルサービスと呼びます。アーキテクチャは次のとおりです。

モノリシック実装

API意味

go-zeroこれを使用した学生APIは、説明する形式のファイルを提供していることを知っています。RESTful APIその後、goctlワンlogicます。ファイルに対応するビジネスロジックを入力するだけで済みます。とサービスがどのように定義されdownloadいるかを見てみましょうuploadAPI

Downloadサービス定義

要件の例は次のとおりです。

  • /static/<filename>パスで指定され<filename>たファイルをダウンロードします
  • ファイルの内容を返すだけです

次の内容のディレクトリに名前の付いたファイルapi作成します。download.api

syntax = "v1"

type DownloadRequest {
  File string `path:"file"`
}

service file-api {
  @handler DownloadHandler
  get /static/:file(DownloadRequest)
}

zero-api構文は比較的自明であり、次の意味があります。

  1. syntax = “v1”zero-apiこれを示すv1構文は次のとおりです。
  2. type DownloadRequestを定義Downloadする
  3. service file-apiDownload定義されたリクエストルーティング

Uploadサービス定義

要件の例は次のとおりです。

  • /uploadパス経由でファイルをアップロード
  • jsonアップロードステータスを返すことにより、より豊富なcodeシナリオを表現するために使用できますHTTP code

次の内容のディレクトリに名前の付いたファイルapi作成します。upload.api

syntax = "v1"

type UploadResponse {
  Code int `json:"code"`
}

service file-api {
  @handler UploadHandler
  post /upload returns (UploadResponse)
}

説明は次のとおりです。

  1. syntax = “v1”zero-apiこれを示すv1構文は次のとおりです。
  2. type UploadResponseUpload戻り形式を定義します
  3. service file-apiUpload定義されたリクエストルーティング

ここに問題があります

DownloadUploadサービスを定義しましたが、ユーザーにサービスを提供するためにどのようにサービスに組み込むことができますか?

あなたがいくつかの詳細に気づいたかどうかはわかりません:

  1. Downloadまたは、データ定義の前に接頭辞をUpload付け、またはなどrequestresponseRequestResponse
  2. とを定義するときにこれdownload.api使用し、upload.apiservicefile-apiservice namedownload-apiupload-api

これの目的は、実際には、これら2つのサービスを同じモノマーに配置したときに、対応するGoコードです。組み合わせる方法DownloadUpload

モノリシックサービスインターフェイスの定義

簡単にするために、パラメータとしてgoctlサポートされるのは1つのAPIファイルAPIであり、同時に複数のファイルを受け入れる問題についてはここでは説明しません。単純で効率的な解決策があれば、将来的にサポートされる可能性があります。

次の内容の新しいファイルをディレクトリにapi作成します。file.api

syntax = "v1"

import "download.api"
import "upload.api"

このようC/C++にして、とのようなサービスをインポート#includeます。ただし、注意すべき点がいくつかあります。DownloadUpload

  1. 定義された構造に同じ名前を付けることはできません
  2. すべてのファイルに同じものが含まれているservice name必要

>最も外側のAPIファイルにもservice同じの部分的な定義を含めることができますが、これらAPIが実際に親レベルに属している場合(およびと同じ論理レベルに属してDownloadいる場合など)を除き、対称に保つことをお勧めします。Uploadfile.api

これまでのところ、ファイル構造は次のとおりです。

.
└── api
    ├── download.api
    ├── file.api
    └── upload.api

モノリシックサービスを生成する

APIインターフェイスの定義ができたので、go-zero次のことAPIgoctl

$ goctl api go -api api/file.api -dir .

生成されたファイル構造を見てみましょう。

.
├── api
│   ├── download.api
│   ├── file.api
│   └── upload.api
├── etc
│   └── file-api.yaml
├── file.go
├── go.mod
├── go.sum
└── internal
    ├── config
    │   └── config.go
    ├── handler
    │   ├── downloadhandler.go
    │   ├── routes.go
    │   └── uploadhandler.go
    ├── logic
    │   ├── downloadlogic.go
    │   └── uploadlogic.go
    ├── svc
    │   └── servicecontext.go
    └── types
        └── types.go

ディレクトリごとのプロジェクトコードの構成を説明しましょう。

  • apiディレクトリ:前に定義したAPIインターフェース、多くを言う必要はありません
  • etcディレクトリ:これはyaml構成、すべての構成アイテムをfile-api.yamlファイルに書き込むことができます
  • file.gomain関数が配置されているファイル、ファイル名はserviceと同じ、サフィックスは削除されます-api
  • internal/configディレクトリ:サービスの構成定義
  • internal/handlerディレクトリ:APIファイルで定義されたルートに対応するhandler実装
  • internal/logicディレクトリ:各ルートに対応するビジネス処理ロジックを配置するために使用されます。handlerlogicは、ビジネス処理部分の依存関係を可能な限り減らしHTTP requests、簡単に分割できるようにするためです。の中へRPC service
  • internal/svcディレクトリ:ビジネスロジック処理の依存関係を定義するために使用されます。依存関係のあるリソースをその中に作成mainし、ServiceContextそれらをhandlerとができます。logic
  • internal/typesディレクトリ:APIリクエストます

何も変えずに走って効果を見てみましょう。

$ go run file.go -f etc/file-api.yaml
Starting server at 0.0.0.0:8888...

ビジネスロジックを実装する

次に、関連するビジネスロジックを実装する必要がありますが、ここでのロジックはデモンストレーション用であり、実装の詳細にあまり注意を払う必要はありません。logicレイヤー。

これが行われたいくつかのことです:

  • 構成項目のPath設定、アップロードされたファイルを配置します。現在のディレクトリを書き込んだデフォルト値は、次の例です。

    type Config struct {
      rest.RestConf
      // 新增
      Path string `json:",default=."`
    }
    
  • リクエスト本文のサイズ制限を次のように調整しました。

    Name: file-api
    Host: localhost
    Port: 8888
    # 新增
    MaxBytes: 1073741824
    
  • Downloadクライアントにファイルを書き込む必要があるため、レイヤーに渡さResponseWriterれたものとして処理するため、変更されたコードは次のようになります。io.Writerlogic

    func (l *DownloadLogic) Download(req *types.DownloadRequest) error {
      logx.Infof("download %s", req.File)
      body, err := ioutil.ReadFile(req.File)
      if err != nil {
        return err
      }
    
      n, err := l.writer.Write(body)
      if err != nil {
        return err
      }
    
      if n &lt; len(body) {
        return io.ErrClosedPipe
      }
    
      return nil
    }
    
  • Uploadユーザーがアップロードしたファイルを読み取る必要があるhttp.Requestため、logicレイヤーます。変更されたコードは次のとおりです。

    func (l *UploadLogic) Upload() (resp *types.UploadResponse, err error) {
      l.r.ParseMultipartForm(maxFileSize)
      file, handler, err := l.r.FormFile("myFile")
      if err != nil {
        return nil, err
      }
      defer file.Close()
    
      logx.Infof("upload file: %+v, file size: %d, MIME header: %+v",
        handler.Filename, handler.Size, handler.Header)
    
      tempFile, err := os.Create(path.Join(l.svcCtx.Config.Path, handler.Filename))
      if err != nil {
        return nil, err
      }
      defer tempFile.Close()
      io.Copy(tempFile, file)
    
      return &amp;types.UploadResponse{
        Code: 0,
      }, nil
    }
    

完全なコード:https ://github.com/zeromicro/zero-examples/tree/main/monolithic

fileモノリシックサービスは次の方法で開始できます。

$ go run file.go -f etc/file-api.yaml

サービスは次の方法で確認できcurlますDownload

$ curl -i "http://localhost:8888/static/file.go"
HTTP/1.1 200 OK
Traceparent: 00-831431c47d162b4decfb6b30fb232556-dd3b383feb1f13a9-00
Date: Mon, 25 Apr 2022 01:50:58 GMT
Content-Length: 584
Content-Type: text/plain; charset=utf-8

...

サンプルリポジトリが含まれてupload.htmlおり、ブラウザはこのファイルを開いてUploadサービス。

モノリシック開発の概要

go-zeroモノリシックサービスを開発する完全なプロセスを次のように要約します。

  1. 次のような個々のサブモジュールを定義するAPIファイル:download.apiおよびupload.api
  2. 一般APIファイル。例: file.apiimport手順1で定義された各サブモジュールのAPIファイル
  3. goctl api goコマンドでモノリシックサービスフレームワークコードを生成する
  4. 対応するサブモジュールのビジネスロジックを実現するために、構成を追加および調整します

さらに、ワンgoctlクリックで生成およびコーディングできるため、単一のサービスをより迅速に開発できます。SQLCRUDcache

プロジェクトアドレス

https://github.com/zeromicro/go-zero

https://gitee.com/kevwan/go-zero

ようこそgo-zeroスターが私たちをサポートします!

WeChat交換グループ

「マイクロサービスプラクティス」の公式アカウントをフォローし、交換、コミュニティグループのQRコードを取得します。

{{o.name}}
{{m.name}}

おすすめ

転載: my.oschina.net/kevwan/blog/5519393