こんにちは。開発グループ・エンジニアの阿部です。
社内では abemotion って呼ばれたりもします。
前回の記事で紹介したのですが、
提案していたマイクロサービスの構成を初めて利用した
「新プロフィールページ機能」をついにリリースしました!!
設計期間も含めると約5ヶ月、、
長い戦いでした...
今回はそんな「新プロフィールページ機能」のシステム部分について、お話をさせて頂けたらと思います。
- システム構成
- 設計方針
- レイヤ設計
- gRPC
システム構成
言語・フレームワーク | |
---|---|
フロントエンド | Nuxt.js |
apigateway | golang |
サーバーサイド | Rails |
通信 | gRPC |
私は apigateway(golang)の構築と profile Service の Rails 実装を担当しました。
マイクロサービス構成としてもそうですが、apigateway に至っては、本当に一から構築でした。
今回は golang での apigateway に焦点をあてたいと思います。
設計方針
まずは設計方針からなのですが、
男は黙って標準パッケージ
フレームワーク(以下、WAF)を用いず、Goの標準パッケージを使って開発しました。
まだデファクトスタンダードのWAFがなく、
その段階でWAFを使うのは、今後負債化する恐れがあるためです。
※ もちろん使っている会社もある
ただ仕方なしの選定ではないです。
Goには機能豊富なパッケージが多く、
WAFの中には、標準パッケージをラッパーしているだけ的なのもあります。
標準パッケージ選定理由
- そもそも apigateway の機能仕様が限られてる(O/Rマッパーもいらないぐらい)
- パフォーマンス良
- 細かいチューニングができる(WAF仕様に縛られない)
- 外部ライブラリは使ってますよ!
パッケージ構成
次はパッケージ構成について、 Webアプリ内のレイヤ(ディレクトリ)構造をどうするかという話です。
そもそもGoでは、相互参照するとエラーになるので、
フレームワークを使わない以上、設計が重要になってきます。
他社さんの記事なども参考にさせて頂き、Lightweight DDDを採用しました。
(DDDライクなライトなパッケージ構成。レイヤアーキテクチャ)
レイヤ設計
- interfaces:リクエストハンドラ
- application:domain層を扱うビジネスロジック
- domain:モデル。構造体定義(値と振る舞い)他構造体に付随する共通処理
- repository:infrastructure のインターフェース定義
- service:application のインターフェース定義
- infrastructure:技術的機能
- persistence:domainで定義したデータアクセスの実装
「依存関係逆転の法則」を意識し、依存の方向や詳細ではなく抽象へ依存するよう考慮しました。
参考記事
Webアプリケーションにおける Go 言語のパッケージ構成〜メルカリ カウル編〜
Goのパッケージ構成の失敗遍歴と現状確認
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
gRPC
フロントエンド(Express)→ apigateway → Profile Service 間は、gRPCで通信しています。
前回の記事で、gRPCの概要・メリットは説明したので、ここでは使い方や運用方法について記します。
使い方
- .proto ファイルの定義
- ソースコードの自動生成
- サーバ、クライアントの実装
- 実行
まずインターフェースの仕様となる .proto ファイルを Protocol Buffers 形式で記述し、
ファイル自体は専用のリポジトリを1つ用意し一元管理しています。
リポジトリからソースを取得し、 protoc コマンドを使うことで言語毎のモデルファイルが生成できます。
実装はサーバ/クライアント共に生成されたファイルを使って開発を行います。
gRPC では、エラーコードが独自に用意されており、 HTTP ステータスコードとのマッピングもコメント内に書かれています。
gRPCエラーコード
エラー名 | code | HTTP Status Code |
---|---|---|
OK | 0 | 200 |
UNKNOWN | 2 | 500 |
INVALID_ARGUMENT | 3 | 400 |
DEADLINE_EXCEEDED | 4 | 504 |
NOT_FOUND | 5 | 404 |
ALREADY_EXISTS | 6 | 409 |
PERMISSION_DENIED | 7 | 403 |
RESOURCE_EXHAUSTED | 8 | 429 |
FAILED_PRECONDITION | 9 | 429 |
ABORTED | 10 | 409 |
OUT_OF_RANGE | 11 | 400 |
UNIMPLEMENTED | 12 | 501 |
INTERNAL | 13 | 500 |
UNAVAILABLE | 14 | 503 |
DATA_LOSS | 15 | 500 |
UNAUTHENTICATED | 16 | 401 |
通信エラーなどは上記コードが返ってきますし、
gRPC上でのリトライ処理等も、このエラーコードで判定されて行われるので慣れる必要があります。
詳細はこちら
最後に
今回 apigateway をフレームワークを用いずに一から構築することで、
以下、システムの構成要素全てを設計・検討する良い機会となりました。
システム構成要素
- 基本設計
- レイヤ設計
- 抽象(inteface)への依存
- パッケージ管理
- エラーハンドリング
- ログ出力
- アラート設定
挑戦させてくれた会社と開発チームにはホント感謝です!
ココナラでは新技術にチャレンジングな仲間もお待ちしています!
お知らせメール登録
よもやまブログの更新時にメールでお知らせします。