著者: Wang Yuxuan (github: DMwangnima)、Kitex コミッター
1. 背景
Kitex は、ByteDance インフラストラクチャ サービス フレームワーク チームによって開始された Go マイクロサービス RPC フレームワークであり、Thrift、Kitex Protobuf、gRPC などのメッセージ プロトコルをサポートしており、高いパフォーマンスと強力な拡張性を特徴としています。 2021 年 9 月に正式にオープンソース化されて以来、多くの外部企業での導入に成功し、実際のコスト、パフォーマンス、安定性のメリットをもたらしています。
Kitex 変換サービスを使用する過程で、多くの企業ユーザーは既存の Dubbo フレームワークによって実装されたサービスと通信する必要があります。これは、エコシステムを積極的に拡大するという CloudWeGo コミュニティの目標と一致します。そのため、Dubbo 相互運用性プロジェクトcodec-dubbo が必要になります。誕生しました。
コミュニティの学生の熱心な支援により、コーデック ダボは現在、Kitex と Dubbo-Java、Kitex と Dubbo-Go の間で相互運用できるようになり、Dubbo ユーザーが Kitex に移行できるようにサポートしています。
この記事では、Kitex と codec-dubbo を使用して成功した Founder Securities のサービス変革を例に挙げ、変革プロセスで使用される codec-dubbo の主な機能を説明し、実装の詳細を簡単に分析します。
2. 企業導入事例
Founder Securities のオリジナル サービスは Java および Dubbo フレームワークで記述されており、どちらも安定しており、多数のシナリオで検証されており、運用および開発のニーズを満たしています。リクエスト数が多い Xiaofang の個別株詳細ページを例にとると、ピーク時のインターフェイス QPS は 3 ~ 4k で、16 台の 16 コア 64G 仮想マシンがホスティングに使用されています。
クラウド ネイティブ アーキテクチャの台頭により、Go はメモリ使用量と実行効率における利点、およびクラウド ネイティブへの自然な適応性により、エンタープライズ サービスを構築するための重要なテクノロジ オプションとなりました。コストの削減と効率の向上を図るため、コスト、パフォーマンス、安定性などの要素を総合的に考慮した結果、新しいアプリケーションを Java から Go に切り替えることを決定し、サービスの開発と再構築には Kitex、Hertz などの CloudWeGo プロジェクトを導入し、移行しました。 Kubernetes 環境全体。
再構築プロセス中、codec-dubbo は、ネイティブの Kitex + Thrift に近いユーザー エクスペリエンスと、Dubbo の概念の優れたサポートに依存して、使用コストと理解コストを削減し、Kitex <-> Dubbo の相互運用性の問題を解決することに成功しました。 Kitexサーブ オリジナルのダボサービスをスムーズに呼び出します。
現在、codec-dubbo を使用した Kitex サービスは正常に開始され、2 か月間安定して実行されています。 Xiaofang の個別の株式詳細ページを例にとると、Kitex と Hertz はこのページのインターフェイスの約半分をホストしています。QPS が変更されない場合、提供する必要があるのは 4 コア 4G ポッドのみであり、リソース使用量が大幅に削減されます。
3. コーデックダボの機能特徴
ダボプロトコルコーデック
Dubbo サービスは主に通信に Dubbo プロトコルを使用します。Kitex <-> Dubbo の相互運用性をサポートするには、Kitex に Dubbo プロトコルを実装する必要があります。 Kitex の優れたスケーラビリティのおかげで、codec-dubbo は、Kitex が提供する Codec インターフェイスに基づいて、コア コーデックである DubboCodec を実装します。Dubbo プロトコルを使用するには、初期化中に DubboCodec を挿入するだけで済みます。
型のマッピングと拡張
型マッピング
Dubbo は主に Hessian2 シリアル化プロトコルを使用してペイロードをエンコードおよびデコードします。その最大の特徴は、自己記述型シリアル化タイプです。つまり、外部スキーマやインターフェイス定義に依存しません。シリアル化プロセスは、プログラミング言語の型と Hessian2 型の間のマッピングに依存します。例として、Go 型から Java 型への変換を取り上げます。
分析の結果、Hessian2 の基本的な型システムは基本的に Thrift と重複していることがわかりました。 Kitex + codec-dubbo の使用体験が基本的に Kitex + Thrift と同じであることを保証するために、Thrift IDL に基づいて Kitex Dubbo-Hessian2 スキャフォールディング コードを生成します。このときの型変換プロセスは次のとおりです。
Dubbo の公式のdubbo-go-hessian2タイプ マッピングを参照してください。 codec-dubbo は次のタイプ マッピングを提供します (ここにはマッピングの一部のみが含まれています。詳細な注意事項については、codec-dubbo Readme を参照してください)。
codec-dubbo によって提供されるタイプ マッピングに従って、Dubbo インターフェイス定義を Thrift IDL に簡単に変換し、Kitex コマンド ライン ツールを使用してプロジェクト スキャフォールディング コードを生成し、最後に DubboCodec を挿入して Kitex -> Dubbo 通信を完了することができます。例として、次の Dubbo インターフェイス定義を取り上げます。
package org.cloudwego.kitex.samples.api;
public interface GreetProvider {
GreetResponse Greet(GreetRequest req) throws Exception;
}
public class GreetRequest implements Serializable {
String req;
public GreetRequest(String req) {
this.req = req;
}
}
public class GreetResponse implements Serializable {
String resp;
public GreetResponse(String resp) {
this.resp = resp;
}
}
対応する api.thrift ファイルは次のとおりです。その中の構造定義には、Dubbo インターフェイス定義のパッケージ + クラス名に対応する JavaClassName の注釈を付ける必要があることに注意してください。
struct GreetRequest {
1: required string req,
} (JavaClassName="org.cloudwego.kitex.samples.api.GreetRequest")
struct GreetResponse {
1: required string resp,
} (JavaClassName="org.cloudwego.kitex.samples.api.GreetResponse")
service GreetService {
GreetResponse Greet(1: GreetRequest req)
}
Kitex コマンド ライン ツールを使用して、プロトコルを Hessian2 として指定します。
kitex -module demo-client -protocol Hessian2 ./api.thrift
次に、DubboCodec を初期化し、生成されたコードを使用して次のクライアント コードを記述し、Kitex -> Dubbo 呼び出しを実装します。
javaClass := "org.cloudwego.kitex.samples.api.GreetProvider"
cli, err := greetservice.NewClient("helloworld",
// 指定想要访问的服务端地址,也支持 ZooKeeper 服务发现
client.WithHostPorts("127.0.0.1:21000"),
// 配置 DubboCodec
client.WithCodec(
// 指定想要调用的 Dubbo Interface
dubbo.NewDubboCodec(dubbo.WithJavaClassName(javaClass))
),
)
if err != nil {
panic(err)
}
resp, err := cli.Greet(context.Background(),
&hello.GreetRequest{Req: "world"})
if err != nil {
klog.Error(err)
return
}
klog.Infof("resp: %s", resp.Resp)
Kitex + codec-dubbo サーバー側のプロセスは基本的にクライアント側のプロセスと同様です。具体的な例については、プロジェクトのホームページを参照してください。
型拡張
Hessian2 のスキーマフリー機能により、Dubbo の実装は「非常に柔軟」になり、あらゆる型を使用できます。 Dubbo Hessian2 の型使用の柔軟性に適応するために、codec-dubbo は型拡張をサポートします。これには主にカスタム マッピングと Java 共通型拡張が含まれます。
カスタムマッピング
boolean
Java の基本型には、やなどの対応するラッパー型がありますjava.lang.Boolean
。型マッピングにおけるbool
Go 型から Java 型へのデフォルトのマッピングでは、 の使用はカバーされていません。ユーザーエクスペリエンスを統一し、 Kitex 側の型のみを使用できるようにするには、Thrift メソッド定義の後にアノテーションを追加し、thriftgo の IDL リフレクション機能を使用して、事前に IDL メタ情報を生成し、それをコーデックに注入します。 dubbo を実行すると、デフォルトのマッピング タイプを に動的に書き換えます。具体的な節約の定義は次のとおりです。java.lang.Boolean
boolean
bool
hessian.argsType="boolean"
java.lang.Boolean
boolean
service EchoService {
bool EchoBoolean(1: bool req) (hessian.argsType="boolean")
}
boolean
およびと同様にjava.lang.Boolean
、他の Java 基本型およびラッパー型もこの方法でカスタマイズできます。現時点では、codec-dubbo によって提供される完全な型マッピングは次のとおりです。
Javaの共通型の拡張
Thrift 型の制限により、Java クラス ライブラリで提供される一般的な型を直接使用することはできません。この目的のために、codec-dubbo は、提供される idl-ref 関数の助けを借りて、Thrift がサポートしていない Java タイプ (たとえば、) と対応するjava.thrift をcodec-dubbo/javaパッケージ内で維持します。 thriftgo により、Thrift を直接使用できます。これらの型は IDL で参照され、対応するコードが生成されます。現在の java.thrift は次のようになります。java.lang.Object
java.util.Date
struct Object {} (JavaClassName="java.lang.Object")
struct Date {} (JavaClassName="java.util.Date")
struct Exception {} (JavaClassName="java.lang.Exception")
これらのタイプを有効にするには、拡張パッケージをプルするためにinclude "java.thrift"
Kitex コマンド ライン ツールを使用してコードを生成するときに、Thrift IDL にインポートし、パラメーターを追加する必要があります。-hessian2 java_extension
Kitex コマンド ライン ツールは java.thrift を自動的にダウンロードします。手動でダウンロードしてプロジェクトのルート ディレクトリに置くこともできます。 java.thrift の型を参照する Thrift IDL の例:
include "java.thrift"
service EchoService {
// java.lang.Object
i64 EchoString2ObjectMap(1: map<string, java.Object> req)
// java.util.Date
i64 EchoDate(1: java.Date req)
}
メソッドのオーバーロード
Go はメソッドのオーバーロードをネイティブにサポートしていません。オーバーロードのような効果を実現するには、複数のメソッドを定義する必要があります。 Go の複数のメソッドを Java のオーバーロードされたメソッドにマッピングするには、カスタム マッピング セクションと同様に、Thrift のメソッド定義の後に JavaMethodName タグを追加し、thriftgo の IDL リフレクション機能を使用して実行時に Go を動的にマッピングします。メソッド名は、JavaMethodName で指定された Java のオーバーロードされたメソッドに書き換えられます。
Java 側の EchoMethod を例として取り上げます。
String EchoMethod(Boolean req);
String EchoMethod(Integer req);
String EchoMethod(int req);
String EchoMethod(Boolean req1, Integer req2);
次の Thrift 定義を作成して、Go と Java の間のオーバーロードされたメソッドのマッピングを完了します。JavaMethodName
と はhessian.argsType
同時に使用できることに注意してください。
service EchoService {
string EchoMethodA(1: bool req) (JavaMethodName="EchoMethod")
string EchoMethodB(1: i32 req) (JavaMethodName="EchoMethod")
string EchoMethodC(1: i32 req) (JavaMethodName="EchoMethod", hessian.argsType="int")
string EchoMethodD(1: bool req1, 2: i32 req2) (JavaMethodName="EchoMethod")
}
例外処理
codec-dubbo は、Java の例外を Go のエラーにマップします。これらのエラーは、次のインターフェイスを均一に実装します。
type Throwabler interface {
Error() string
JavaClassName() string
GetStackTrace() []StackTraceElement
}
Dubbo が公式に推奨する例外処理方法と企業ユーザーの現在のニーズに基づいて、ユーザーの基本的なニーズとスケーラビリティのニーズを考慮して、例外を一般的な例外とカスタム例外に分類します。
一般的な例外
codec-dubbo は、pkg/hessian2/Exceptionパッケージで一般的な Java 例外を提供し、現在 java.lang.Exception をサポートしています。
一般的な例外は、Kitex コマンド ライン ツールからのサポートを必要とせず、直接引用できます。以下は、クライアントによって抽出された例外とサーバーによって返された例外の例です。
クライアント抽出例外
resp, err := cli.Greet(context.Background(),
&hello.GreetRequest{Req: "world"})
if err != nil {
// FromError 返回 Throwabler
exceptionRaw, ok := hessian2_exception.FromError(err)
if !ok {
// 视作常规错误处理
} else {
// 若不关心 exceptionRaw 的具体类型,直接调用 Throwabler 提供的方法即可
klog.Errorf("get %s type Exception", exceptionRaw.JavaClassName())
// 若想获得 exceptionRaw 的具体类型,需要进行类型转换,但前提是已知该具体类型
exception := exceptionRaw.(*hessian2_exception.Exception)
}
}
サーバー側が例外を返す
func (s *GreetServiceImpl) Greet(ctx context.Context, req *hello.GreetRequest) (resp *hello.GreetResponse, err error) {
return nil, hessian2_exception.NewException("Your detailed message")
}
カスタム例外
Java のカスタム例外は、多くの場合、基本例外を継承します。ここでは、CustomizedException
例CustomizedException
例外を継承しますjava.lang.Exception
。
public class CustomizedException extends Exception {
private final String customizedMessage;
public CustomizedException(String customizedMessage) {
super();
this.customizedMessage = customizedMessage;
}
}
thriftgo はネスト構造の生成をサポートしているため、Kitex 側で対応する例外を定義するために、Thrift で次の定義を記述します。
exception CustomizedException {
// thrift.nested=“true” 注解让 thriftgo 生成嵌套结构体
1: required java.Exception exception (thrift.nested="true")
2: required string customizedMessage
}(JavaClassName="org.cloudwego.kitex.samples.api.CustomizedException")
exception
フィールド アノテーション に注目してくださいthrift.nested="true"
。これにより、thriftgo はネストされた構造を生成して、継承と同様の効果を実現できます。
Java 共通タイプ拡張機能と同様に、kitex スキャフォールディング ツールを使用して-hessian2 java_extension
拡張パッケージをプルするコードを生成するときにパラメーターを追加する必要があります。生成されるコードは次のとおりです。
type EchoCustomizedException struct {
java.Exception `thrift:"exception,1,required" frugal:"1,required,java.Exception" json:"exception"`
CustomizedMessage string `thrift:"customizedMessage,2,required" frugal:"2,required,string" json:"customizedMessage"`
}
使用方法は一般的な例外と一致しているため、ここでは繰り返しません。
サービスの登録と検出
Dubbo は、インターフェイス レベルとアプリケーション レベルの両方のサービス登録および検出モデルを提供します。エンタープライズ ユーザーの現在の運用環境のニーズに基づいて、Dubbo レジストリ - Zookeeper に基づくインターフェイス レベルのモデルを優先することを選択します。
私たちがよく知っているアプリケーションレベルのモデルとは異なり、インターフェースレベルのモデルはインターフェース名 => サービス (マイクロサービスとは異なり、ハンドラーに近い) のマッピング関係を維持する必要があり、1 つのインターフェース名が複数のサービスにマッピングされます。これらのサービスはプロセス内で同じに存在する場合があります。
Dubbo のインターフェイス レベルのサービス モデルは Kitex のサービス モデルとは大きく異なり、Dubbo registry-zookeeper は使用するために codec-dubbo にバインドされる必要があることを考慮すると、kitex-contrib 内の元の registry-zookeeper を変更して dubbo レジストリを作成することは考慮されていません。 -zookeeper codec-dubbo のサブ go モジュールが均一に開発および保守されています。
Dubbo インターフェイス レベルのサービス モデル、Kitex API、およびユーザー エクスペリエンスを考慮して、次の構成レベルを提供します。
- registry/options.goおよびsolver/options.goの WithServers 関数と WithRegistryGroup 関数は、レジストリ レベルの構成を提供し、それぞれ動物園管理者のアドレスとこれらの動物園管理者が属するグループを指定します。ユーザーはこれらの関数を使用して Kitex
registry.Registry
とdiscovery.Resolver
インスタンスを生成します。 - サービスレベルの設定は
client.WithTag
と でserver.WithRegistryInfo
渡され、 registries/common.go は、Dubbo のサービス メタデータに 1 対 1 で対応するタグ キーを提供します。
リゾルバの例
intfName := "org.cloudwego.kitex.samples.api.GreetProvider"
res, err := resolver.NewZookeeperResolver(
// 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个
resolver.WithServers("127.0.0.1:2181"),
)
if err != nil {
panic(err)
}
cli, err := greetservice.NewClient("helloworld",
// 配置 ZookeeperResolver
client.WithResolver(res),
// 指定想要调用的 dubbo Interface
client.WithTag(registries.DubboServiceInterfaceKey, intfName),
)
if err != nil {
panic(err)
}
// 使用 cli 进行 RPC 调用
レジストリの例
intfName := "org.cloudwego.kitex.samples.api.GreetProvider"
reg, err := registry.NewZookeeperRegistry(
// 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个
registry.WithServers("127.0.0.1:2181"),
)
if err != nil {
panic(err)
}
svr := greetservice.NewServer(new(GreetServiceImpl),
server.WithRegistry(reg),
// 配置dubbo URL元数据
server.WithRegistryInfo(&kitex_registry.Info{
Tags: map[string]string{
registries.DubboServiceInterfaceKey: intfName,
// application请与dubbo所设置的ApplicationConfig保持一致,此处仅为示例
registries.DubboServiceApplicationKey: "application-name",
}
}),
)
// 启动 svr
要約する
Kitex は Dubbo プロトコルをサポートしており、これは CloudWeGo にとって、Java から Go への変換、および Java と Go の共存における多くの企業ユーザーの問題点を解決する大きな一歩となります。アクセスしてみてください。使用中に問題が発生した場合は、Feishu ユーザー グループに参加するか、Github でフィードバックをお送りください。
「Celebrated More Than Years 2」の海賊版リソースが npm にアップロードされたため、npmmirror は unpkg サービスを停止せざるを得なくなり、 最初の創設者の 数百人が参加して、一斉に米国に向かいました。 フロントエンド視覚化ライブラリと Baidu の有名なオープンソース プロジェクト ECharts - Fish 詐欺師をサポートするために「海へ行く」が、TeamViewer を使用して 398 万を送金しました。リモート デスクトップ ベンダーは何をすべきでしょうか? 周宏宜: Google に残された時間はあまり多くありません。すべての製品をオープンソースにすることが推奨されています。 ある有名なオープンソース企業の元従業員が、部下から異議を申し立てられた後、激怒しました。妊娠中の女性従業員を解雇しました。Google は Android 仮想マシンで ChromeOS を実行する方法を示しました。 ここで time.sleep(6) はどのような役割を果たしますか? マイクロソフト、中国のAIチームが「米国のために荷造りしている」という噂に反応 人民日報オンラインはオフィスソフトのマトリョーシカのような課金についてコメント:「セット」を積極的に解決することによってのみ、私たちは未来を手に入れることができる