要約特使プロキシの動的APIを使用します
特使プロキシおよび他のL4 / L7は、逆方向の最大の違いは、一次ツール支持動的構成することである無視します。およそのアーキテクチャ特使初めて目に
これは単に、図から理解することができる。特定のクラスタへの転送、処理後にフィルタ/ルータを介して、外部要求を受信し、そしてためのリスナーが担います。リスナー、ルータ、クラスタとホストアドレスが動的に構成されており、それがXディスカバリーサービスと呼ばれるサービスの構成データは、XDSと呼ばれます。
この記事では、XDSサーバーの更新ロジックを記述する方法について説明します。
GRPCサービスを通じて更新特使Porxy XDSサービスデータは、すべてのプロト・ファイルが参照できhttps://github.com/envoyproxy/envoy/tree/master/api/envoy/api/v2を。ユーザーは、ファイル自体プロトに対応GRPC言語コードファイルを生成することができます。あなたが叶うするgolangを使用している場合は、特使は、ここでGRPCコンパイルされたコード、アドレスを提供していますhttps://github.com/envoyproxy/go-control-plane/tree/master/envoy/api/v2
各XDSサービスは2つのGRPCサービスを提供しています、Stream
とDelta
。Stream
これは、データの全額更新するために使用されるDelta
増分データを更新するために使用します。RDSサービス下記の例として、XDSサービスを実装する方法を確認してください。
RDS Service
これは、すべて提供することがRoute
簡略化され、通常の後、情報をRoute
以下のように設定は次のとおりです。
# 完整的Route API定义参考 https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/rds.proto#envoy-api-msg-routeconfiguration
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
require_tls: NONE
routes:
- match:
prefix: "/MyService"
route: { cluster: my-grpc-svc_cluster }
上記構成セマンティクス:パスプレフィックスを受信する/MyService
要求は、この要求に転送された後my-grpc-svc_cluster
(my-grpc-svc_cluster
STATIC型であってもよいアップストリーム情報の後端を表しCDS Service
動的に提供されます)
RDS Service
動的意味役割を生成することは上記の構成と同様です。まず見て、比較的単純なStreamRoutes
方法。
次のようにGRPC記述ファイル、この関数が定義されています。
service RouteDiscoveryService {
rpc StreamRoutes(stream DiscoveryRequest) returns (stream DiscoveryResponse) {
}
rpc DeltaRoutes(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) {
}
rpc FetchRoutes(DiscoveryRequest) returns (DiscoveryResponse) {
option (google.api.http) = {
post: "/v2/discovery:routes"
body: "*"
};
}
}
戻り値からわかるようにStreamRoutes
、ストリーム関数をある、RDSは、このプッシュ特使を通じてリアルタイムにデータをストリーミングすることができます。だから、大体実装モデルは、以下のようなものです:
func (r rds) StreamRoutes(ls envoy_api_v2.RouteDiscoveryService_StreamRoutesServer) error {
for{
select{
case x <- c>:
ls.Send(xxx)
}
}
}
Send
受け入れる関数DiscoveryResponse
ポインタを、このDiscoveryResponse
定義の動的構造によっては自明です。特定の種類のデータは、typeUrl
属性を決定しました。具体的なRoute
ことは、typeURL
「type.googleapis.com/envoy.api.v2.RouteConfiguration」である。(タイプ説明参照https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol.htmlを?タイプ=#%20urlハイライト資源タイプ)
データでResource
保存します。
Resource
ある[]*any.Any
タイプは、その白色汎用インタフェース{}です。だから、作成any.Any
特定のデータ型(「type.googleapis.com/envoy.api.v2.RouteConfiguration」)時間を指定する必要が。data
それは結果であるProtoMessage
バイナリエンコードされたデータ。だから、any.Anyは、次のようになります作成します。
data, err := proto.Marshal(xxxx)
if err != nil {
logrus.Errorf("Marshal Error. %s", err)
continue
}
any := &any.Any{
TypeUrl: "type.googleapis.com/envoy.api.v2.Cluster",
Value: data,
})
xxxx
RDSであること、データをルーティングの特使に復帰することが必要ですRouteConfiguration
。それを構築する方法で見てみましょうRouteConfiguration
。APIの定義には、いくつかのデータ項目を失う(項目は、プロト負けキャリブレーションプロファイルにより取得し、しかしとして直接APIドキュメントを参照してくださいではないことにします)。我々はルートシンプルな構成の開口部を達成したいとし、それはRouteConfiguration
このように定義する必要があります。
r:=&envoy_api_v2.RouteConfiguration{
Name: "local_route",
VirtualHosts: []*route.VirtualHost{
&route.VirtualHost{
Name: "local_service",
Domains: []string{
"*",
},
Routes: []*route.Route{
&route.Route{
Match: &route.RouteMatch{
PathSpecifier: &route.RouteMatch_Prefix{Prefix: "/MyService"},
},
Action: &route.Route_Route{Route: &route.RouteAction{
ClusterSpecifier: &route.RouteAction_Cluster{Cluster: "my-grpc-svc_cluster"},
}},
},
},
},
},
},
二つの場所に注意してください。
- 名前: "local_route"。RouteConfig名の名前は、ここではリスナーと一貫性の中で定義する必要があります。ない場合は、リスナーがこのルート設定をロードしません(つまり、これは、主キーに関連付けられている当事者の名前です)
- クラスタ名が一致している必要があります。ない場合は、後続の要求は、上流を転送する場合も同様に、それは検出されません
これらのステップの後、約完全なRoute DiscoveryResponse
定義は完了です。そして、あなたの後に送信を呼び出すことによって特使に送信することができます。
しかし、物事は終わりませんでした今回は、オープニングと述べStream
、同期全額をDelta
同期増分を。もう少し詳しくは、中StreamRoutes
であらゆるニーズ輸送現在のルートの設定だけでなく、すべてのデータ変更が発生していた個人は、多くの問題のため、このアプローチは、データ編成を感じ。が、それは本当に特使データ更新非常に便利(データの全額たびに、マージをしません)。何かをしようとしているユーザーを確認するために、常に時間のかかるものをマージし、特使は、ユーザーが実行できるようにすることを決めました。
だから我々は調整する必要がStreamRoutes
実装モデルを:
func (r rds) StreamRoutes(ls envoy_api_v2.RouteDiscoveryService_StreamRoutesServer) error {
for{
select{
case x <- c>:
// x表示变动的数据
n := merge(x) //对x进行merge操作,返回当前最新全量数据n
var srvRoute []*route.Route
for _, d := range n{
srvRoute = append(srvRoute, &route.Route{
Match: &route.RouteMatch{
PathSpecifier: &route.RouteMatch_Prefix{Prefix: xxxx},
},
Action: &route.Route_Route{Route: &route.RouteAction{
ClusterSpecifier: &route.RouteAction_Cluster{Cluster: xxxx},
}},
})
}
rc := []*envoy_api_v2.RouteConfiguration{
&envoy_api_v2.RouteConfiguration{
Name: "local_route",
VirtualHosts: []*route.VirtualHost{
&route.VirtualHost{
Name: "local_service",
Domains: []string{
"*",
},
Routes: srvRoute,
},
},
},
}
var resource []*any.Any
for _, rca := range rc {
data, err := proto.Marshal(rca)
if err != nil {
return err
}
resource = append(resource, &any.Any{
TypeUrl: "type.googleapis.com/envoy.api.v2.RouteConfiguration",
Value: data,
})
}
ls.Send(&envoy_api_v2.DiscoveryResponse{
VersionInfo: xxx,
Resources: resource,
Canary: false,
TypeUrl: "type.googleapis.com/envoy.api.v2.RouteConfiguration",
Nonce: time.Now().String(),
})
}
}
}
調整後、それぞれがルート特使最新のデータに戻ります。上記モデルは、単一の特使インスタンスの場合を考慮し、マルチインスタンスを考慮していません。マルチインスタンスリンクするとRDS Service
、Cから得られたデータは、すべての特使インスタンスデータが一貫していることができない保証非冪等のイベント、となります。
達成StreamRoutes
外観を実現する方法を、後にDeltaRoutes
。
Delta
デルタは、基準ストリームであり、それはプロトタイプを機能しなければならない、という観点から、関数プロトタイプのデータを同期させるために使用されるStreamRoutes
類似。あなたがそう思うなら、あなたは間違っています
Delta
のみ転送データへストリーム(推測が長い接続を維持するためにデータ伝送効率を向上させ、かつないことです)。各転送が完了すると、特使は、リンクを切断するためのイニシアチブを取るでしょう。言い換えれば、特使の呼び出しがタイムアウトしているDeltaRoutes
差分更新データを取得します。あなたが続く場合はstream
、ライト・ロジックへの実装モデルを、あなたは時間をかけて、このストリームが不可解になることがありますclosed
状態。その理由は、イベントに特使を受け取った後、ストリームをシャットダウンするためのイニシアチブをとるということです。
あなたが使用したいのであればDelta
モードを、それが(この時期の呼び出しがあるので)特使は、リアルタイムデータの変化に応答しない保証するものではありません。あなたが使用している場合やStream
モードを、ユーザーが独自のデータの正確性を維持するために(マージは非常に複雑である場合には、精度が低下します)が必要です。
だから、選択Stream
またはDelta
ユーザーのための問題があります。