マイクロサービスの定義:
これは、一人のプログラマが設計、実装、デプロイ、保守できるアプリケーションとして理解できます。モノリシックなアプリケーションでは、コンポーネントは言語レベルのメソッドや関数を通してお互いを呼び出します。対照的に、マイクロサービスベースのアプリケーションは、複数のマシン上で動作する分散システムであり、各サービスインスタンスは異なるプロセスです。したがって、これらのサービスはプロセス間通信を使用して相互作用する必要があります。
サービス間通信の最もシンプルなソリューションは、gRPC、pub/subなどに加えて、HTTPプロトコルに基づいたJSON形式のデータを使用して対話することです。
マイクロサービスにも多くの課題があります:
- シリアライズ
- ロギング
- 融合
- リクエストトラッキング
- サービス発見
go-kit
go-kitはgo言語関連のマイクロサービス・ツールキットで、フレームワークではなくツールキットと名乗っています。つまり、go-kit は、開発者が独自のマイクロサービスプロジェクトを自由に構築できるように、インターフェイスを提供するサービスの集合体です。
go-kit
Service
具体的なビジネス処理ロジックはここに置かれ、サービスは一般的にインターフェースとしてモデル化されます:
// StringService provides operations on strings.
type StringService interface {
Uppercase(string) (string, error)
Count(string) int
}
このインターフェイスは
type stringService struct{}
func (stringService) Uppercase(s string) (string, error) {
if s == "" {
return "", ErrEmpty
}
return strings.ToUpper(s), nil
}
func (stringService) Count(s string) int {
return len(s)
}
// ErrEmpty is returned when input string is empty
var ErrEmpty = errors.New("Empty string")
Endpoint
type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(uppercaseRequest)
v, err := svc.Uppercase(req.S)
if err != nil {
return uppercaseResponse{v, err.Error()}, nil
}
return uppercaseResponse{v, ""}, nil
}
}
Transport
トランスポートの主な目的は、何らかのトランスポートを通じてサービスを外部世界に公開し、これらのサービスを呼び出せるようにすることです。go-kitは、一般的にhttpやrpcなど、すぐに使えるさまざまなトランスポートをサポートしています。
import (
httptransport "github.com/http"
)
func main() {
ctx := context.Background()
svc := stringService{}
uppercaseHandler := httptransport.NewServer(
ctx,
makeUppercaseEndpoint(svc),
decodeUppercaseRequest,
encodeResponse,
)
countHandler := httptransport.NewServer(
ctx,
makeCountEndpoint(svc),
decodeCountRequest,
encodeResponse,
)
http.Handle("/uppercase", uppercaseHandler)
http.Handle("/count", countHandler)
}
func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) {
var request uppercaseRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
return nil, err
}
return request, nil
}
func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) {
var request countRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
return nil, err
}
return request, nil
}
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
return json.NewEncoder(w).Encode(response)
}
リクエスト追跡
go-kitには、opentracingとzipkinの2種類のリンクトレースがあります。
ZIPKINについて簡単にご紹介します:
zipkinは時間データの収集を支援し、分散システムの時間データの収集とクエリの機能を提供します:
ZipkinはCollector、Storage、API、UIの合計4つのコンポーネントで構成され、Reporterはアプリケーションシステムによって提供され、データを収集します:
- トラッカーをアプリケーションに組み込み、Spanを使用してアプリケーションのアクションに関するタイミングとメタデータ情報を記録します;
- ReporterはSpanをZipkinのデータコレクターであるCollectorに送信します;
- Collectorは、Storageコンポーネントを通じてデータベースにデータを保存します;
- UIコンポーネントはトラッキングデータを照会し、APIインターフェースを通じて表示します;
ZIPKINはトレース構造を通してリクエストのトレースを表現します。リクエストはいくつかのサービスによって処理され、各サービスはスパンを生成し、同じリクエストのスパン間の関連があり、それはUIコンポーネントでツリーとして表示されます:
API
マイクロサービスでは、APIがサービスと外部とのほぼ唯一のインタラクションチャネルであり、APIの安定性・信頼性は無視できない部分になってきています。APIのリアルタイムの稼働状況を把握し、過去のデータ分析を通じて、どのAPIがパフォーマンスのボトルネックになっているかを把握し、後の最適化につなげることが必要です。したがって、システムが優れたサービスを提供することを保証するために、マイクロサービス・フレームワークの大部分はAPIモニタリング・コンポーネントとも統合されています。プロメテウス(Prometheus)は、オープンソースのシステム監視アラームフレームワークのセットです。新世代の監視フレームワークとして、以下の特徴があります:
- カウンター、ゲージ、ヒストグラム、サマリーなどの強力な多次元データモデルを提供します。
- 強力で柔軟なクエリ文により、時系列データに対するクエリや集計操作を簡単に実行できます;
- 管理が簡単で効率的;
- プルモード、プッシュゲートウェイを提供し、時系列データの収集を実現します;
- Grafana、Web UI、APIクライアントなど、複数のビジュアルグラフィカルインターフェースをサポートします;
- アラームルール管理、アラーム検知、アラームプッシュ機能
main.goを修正して、メトリクス・コレクション・オブジェクトを作成します。
count := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: "51world",
Subsystem: "stringService",
Name: "request_count",
Help: "Number of requests received.",
}, fieldKeys)
latency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
Namespace: "51world",
Subsystem: "stringService",
Name: "request_latency_seconds",
Help: "Total duration of requests in seconds.",
}, fieldKeys)





