【GO】31.grpc クライアント負荷分散ソースコード解析

この記事は、クライアント grpc ロード バランシングのソース コードを自分で表示するプロセスを記録するものです. あまり詳細には説明しません. 参考価値はほとんどないので、直接スキップできます. 主に自分用です.

1.メインインターフェース:バランサーリゾルバー

1.バランサーの定義

リゾルバ定義

具体的な場所は

1. grpc ソース コードは、dns、passthrough、および unix の 3 つの構造を持つリゾルバー (リゾルバー) Builder インターフェースを実装します。clientconn.goファイル内のパッケージを参照して該当パッケージの初期化メソッドに登録

2. internal/resolver/passthrough/passthrough.go ファイルに init 初期化関数を入力し、passthroughBuilder が登録されていることを確認します。リゾルバーパッケージの Register 関数が呼び出されます

func init() {
    resolver.Register(&passthroughBuilder{})
}

3. Register は、登録された構造をマップであるグローバル変数 m に保存します。キーは Scheme で、値は Builder インターフェースです。grpc のデフォルト スキームは passthrough であることがわかります。つまり、passthrough は何もしません。

package resolver

import (
    "context"
    "net"
    "net/url"
    "strings"

    "google.golang.org/grpc/attributes"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/internal/pretty"
    "google.golang.org/grpc/serviceconfig"
)

var (
    // m is a map from scheme to resolver builder.
    m = make(map[string]Builder)
    // defaultScheme is the default scheme to use.
    defaultScheme = "passthrough"
)

// TODO(bar) install dns resolver in init(){}.

// Register registers the resolver builder to the resolver map. b.Scheme will be
// used as the scheme registered with this builder.
//
// NOTE: this function must only be called during initialization time (i.e. in
// an init() function), and is not thread-safe. If multiple Resolvers are
// registered with the same name, the one registered last will take effect.
func Register(b Builder) {
    m[b.Scheme()] = b
}

// Get returns the resolver builder registered with the given scheme.
//
// If no builder is register with the scheme, nil will be returned.
func Get(scheme string) Builder {
    if b, ok := m[scheme]; ok {
        return b
    }
    return nil
}

4. passthroughBuilder をもう一度見て、Buider インターフェイスを実装していることを確認します。Build メソッドは、Resolver インターフェイスを実装する構造体 passthroughResolver を返します。その中で、 passthroughBuilder はパーサーを作成するために使用され、 passthroughResolver は作成されたパーサーです

package passthrough

import (
    "errors"

    "google.golang.org/grpc/resolver"
)

const scheme = "passthrough"

type passthroughBuilder struct{}

func (*passthroughBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
    if target.Endpoint() == "" && opts.Dialer == nil {
        return nil, errors.New("passthrough: received empty target in Build()")
    }
    r := &passthroughResolver{
        target: target,
        cc:     cc,
    }
    r.start()
    return r, nil
}

func (*passthroughBuilder) Scheme() string {
    return scheme
}

type passthroughResolver struct {
    target resolver.Target
    cc     resolver.ClientConn
}

func (r *passthroughResolver) start() {
    r.cc.UpdateState(resolver.State{Addresses: []resolver.Address{
    
    {Addr: r.target.Endpoint()}}})
}

func (*passthroughResolver) ResolveNow(o resolver.ResolveNowOptions) {}

func (*passthroughResolver) Close() {}

func init() {
    resolver.Register(&passthroughBuilder{})
}

5. このコードで返される resolverBuilder は、上記で見つかった登録済みビルダーであり、resolver.Get は 1.3 の対応するコードです。

7. パーサーのパッケージ newCCResolverWrapper を生成し、build を呼び出してパーサーを作成する. このプロセスでは、パーサーの start メソッドが呼び出されます. このメソッドでさらに重要なことは、2 つのことを行うことです. 1. バランサー信号を選択するためのトリガー。2. トリガー状態の変更 (ロード バランシング、つまり接続の作成を含む)

上記は、switchToUpdate と ccStateUpdate をそれぞれ ccBalancerWrapper のチャネルに送信しました

バランサーの選択ロジック

baseBalancer会将所有地址都创建一个连接

invoke的时候,会调用picker选择连接

以上路径最终调用这个方法,可以看到是轮询使用连接

おすすめ

転載: blog.csdn.net/chen_peng7/article/details/129213025