著者| Tiechengdubbo-goコミュニティコミッター
ソース| AlibabaCloudネイティブ公式アカウント
この記事では、dubbogoを使用してdubbogoまたはdubboが提供するサービスプロバイダーに電話をかける方法について説明します。
序文
この記事は、dubbogoバージョン1.5.4に基づいています。
最近、dubbogoの開発とテストに参加し始めましたが、以前 はサンプル例を使って機能を検証していましたが、今回は機能的な問題を再現するために、dubbo -goとdubbocallプロジェクトをゼロから構築する予定です。 dubbogoの落とし穴、参考のためにこのプロセスを記録してください。
この記事を通して、あなたは学ぶことができます:
- dubboおよびdubbogoサービスプロバイダーを呼び出すようにdubbogoコンシューマーを定期的に構成する方法。
- 実際のBUGを通じて問題を解決するというアイデアを紹介します。
問題を解く
1.ダボサービスプロバイダーを準備します
1)基本的な定義
定義されたDemoService
インターフェース:
public interface DemoService {
String sayHello(String name);
String sayHello(User user);
String sayHello(User user, String name);
}
定義されたUser
オブジェクト:
public class User implements Serializable {
private String name;
private int age;
......
}
2)ダボサービスプロバイダーを開始します
public static void main(String[] args) throws IOException {
// 服务实现
DemoService demoService = new DemoServiceImpl();
// 当前应用配置
ApplicationConfig application = new ApplicationConfig();
application.setName("demoProvider");
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("127.0.0.1:2181");
registry.setProtocol("zookeeper");
registry.setUsername("");
registry.setPassword("");
// 服务提供者协议配置
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(12345);
protocol.setThreads(200);
// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口
// 服务提供者暴露服务配置
ServiceConfig<DemoService> service = new ServiceConfig<>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏
service.setApplication(application);
service.setRegistry(registry); // 多个注册中心可以用setRegistries()
service.setProtocol(protocol); // 多个协议可以用setProtocols()
service.setInterface(DemoService.class);
service.setRef(demoService);
service.setVersion("1.0.0");
service.setGroup("tc");
service.setTimeout(60 * 1000);
// 暴露及注册服务
service.export();
System.in.read();
}
登録が成功したかどうかを確認するために動物園の飼育係をチェックしてください:
$ls /dubbo/com.funnycode.DemoService/providers
[dubbo%3A%2F%2F127.0.0.1%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D18167%26release%3D2.7.7%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timestamp%3D1606896020691%26version%3D1.0.0]
上記の出力は、サービスプロバイダーが開始したことを示しています。
2.消費者にサービスを提供するためにdubbogoを準備します
1)基本的な定義
User
オブジェクトを定義し ます。
type User struct {
Name string
Age int
}
func (User) JavaClassName() string {
return "com.funnycode.User"
}
定義されたDemoProvider
インターフェース:
type DemoProvider struct {
SayHello func(ctx context.Context, name string) (string, error) `dubbo:"sayHello"`
SayHello2 func(ctx context.Context, user User) (string, error) `dubbo:"sayHello"`
SayHello3 func(ctx context.Context, user User, name string) (string, error) `dubbo:"sayHello"`
}
func (p *DemoProvider) Reference() string {
return "DemoProvider"
}
2)dubbogoコンシューマーを開始します
func main() {
config.Load()
gxlog.CInfo("\n\n\nstart to test dubbo")
res, err := demoProvider.SayHello(context.TODO(), "tc")
if err != nil {
panic(err)
}
gxlog.CInfo("response result: %v\n", res)
user := User{
Name: "tc",
Age: 18,
}
res, err = demoProvider.SayHello2(context.TODO(), user)
if err != nil {
panic(err)
}
gxlog.CInfo("response result: %v\n", res)
res, err = demoProvider.SayHello3(context.TODO(), user, "tc")
if err != nil {
panic(err)
}
gxlog.CInfo("response result: %v\n", res)
initSignal()
}
3.結果分析を要求する
1)直接電話
問題の存在を確認します。
最初のインターフェースのパラメーターは文字列であり、通常どおりに返すことができます[2020-12-03/18:59:12 main.main: client.go: 29] response result: Hello tc
。
2番目と3番目のインターフェイスには User
オブジェクトがあり、正常に呼び出すことができません。エラーメッセージは次のとおりです。
2020-12-02T17:10:47.739+0800 INFO getty/listener.go:87 session{session session-closed, Read Bytes: 924, Write Bytes: 199, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:Fail to decode request due to: java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, sayHello
at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:134)
at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:80)
at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57)
at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:44)
at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
}, will be closed.
エラー は問題で説明されているものとまったく同じです。エラー情報はコンシューマーに返されるため、Java側でエラースタック情報を確認できるので、直接アクセスしてくださいDecodeableRpcInvocation.decode#134
。
2)ブレークポイントビュー
コードは次のように表示されます。
// 反序列化
public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Decodeable {
public Object decode(Channel channel, InputStream input) throws IOException {
......
if (serviceDescriptor != null) {
// 方法描述里面根据方法名查找
MethodDescriptor methodDescriptor = serviceDescriptor.getMethod(getMethodName(), desc);
if (methodDescriptor != null) {
pts = methodDescriptor.getParameterClasses();
this.setReturnTypes(methodDescriptor.getReturnTypes());
}
}
// 表示没有找到方法
if (pts == DubboCodec.EMPTY_CLASS_ARRAY) {
if (!RpcUtils.isGenericCall(path, getMethodName()) && !RpcUtils.isEcho(path, getMethodName())) {
throw new IllegalArgumentException("Service not found:" + path + ", " + getMethodName());
}
pts = ReflectUtils.desc2classArray(desc);
}
......
}
}
- チェック
MethodDescriptor
、つまり、メソッドが存在するかどうかを確認しますParameterClasses
。存在する場合は、設定されます。 - 上記が見つからない場合は
pts == DubboCodec.EMPTY_CLASS_ARRAY
条件を満たし、一般化呼び出しかエコー呼び出しかを判断し、どちらも見つからない場合はメソッドエラーを検出できません。 - descはい
Ljava/lang/Object
、明らかに、パラメータがObjectであるメソッドはないため、エラーが報告されることになります。
補足:メソッドクエリ。
**
コードは次のとおりです。
public MethodDescriptor getMethod(String methodName, String params) {
Map<String, MethodDescriptor> methods = descToMethods.get(methodName);
if (CollectionUtils.isNotEmptyMap(methods)) {
return methods.get(params);
}
return null;
}
メリット:旧バージョンと比較して、メソッドのメタ情報がキャッシュされ、リフレクションを使用しないことで効率が向上し、時間と空間が交換されていることがわかります。
4.問題を解決します
コードを直接保持することはできないため、比較して問題を確認できます。
1)ダボサービスコンシューマーを開始します
apiモードから始めます。公式の例を参照してください。これは、Javaバージョンの送信コンテンツを表示するためにアクティブ化されます。
public static void main(String[] args) throws InterruptedException {
// 当前应用配置
ApplicationConfig application = new ApplicationConfig();
application.setName("demoProvider2");
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("127.0.0.1:2181");
registry.setProtocol("zookeeper");
registry.setUsername("");
registry.setPassword("");
// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接
// 引用远程服务
ReferenceConfig<DemoService> reference
= new ReferenceConfig<>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
reference.setApplication(application);
reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
reference.setInterface(DemoService.class);
reference.setVersion("1.0.0");
reference.setGroup("tc");
reference.setCheck(true);
reference.setTimeout(1000 * 60);
// 和本地bean一样使用xxxService
DemoService demoService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用
System.out.println(demoService.sayHello(new User("tc", 18)));
TimeUnit.MINUTES.sleep(10);
}
desc裸眼では Lcom/funnycode/User
、これは正しいオブジェクトです。
2)dubbogoを見つけるのが間違っているのはなぜですか
コードの場所:protocol/dubbo/impl/hessian.go:120#marshalRequest
コード:
func marshalRequest(encoder *hessian.Encoder, p DubboPackage) ([]byte, error) {
service := p.Service
request := EnsureRequestPayload(p.Body)
encoder.Encode(DEFAULT_DUBBO_PROTOCOL_VERSION)
encoder.Encode(service.Path)
encoder.Encode(service.Version)
encoder.Encode(service.Method)
args, ok := request.Params.([]interface{})
if !ok {
logger.Infof("request args are: %+v", request.Params)
return nil, perrors.Errorf("@params is not of type: []interface{}")
}
types, err := getArgsTypeList(args)
if err != nil {
return nil, perrors.Wrapf(err, " PackRequest(args:%+v)", args)
}
encoder.Encode(types)
for _, v := range args {
encoder.Encode(v)
}
......
}
戻り値のタイプがすでにありObject
、返されていない場合は、ブレークポイントを見つけることができますUser
。その後、コードの内部を調べます。
protocol/dubbo/impl/hessian.go:394#getArgsTypeList
protocol/dubbo/impl/hessian.go:418#getArgType
func getArgType(v interface{}) string {
// 常见的类型处理
......
default:
t := reflect.TypeOf(v)
if reflect.Ptr == t.Kind() {
t = reflect.TypeOf(reflect.ValueOf(v).Elem())
}
switch t.Kind() {
case reflect.Struct:
return "java.lang.Object"
}
......
}
明らかにreflect.Struct
、彼が戻ったときに見つかった場合java.lang.Object
、引数はになりますObject
。これは、向こうのJavaコードが失敗したため、このタイプの呼び出しに依存しているためです。
3)他のバージョンの検証
2.7.7ではフィードバックがエラーだったため、最初に前のバージョンが正常に機能しているかどうかを検討し、サービスプロバイダーをdubbo 2.7.3に切り替えたところ、次のように通話にエラーが残っていることがわかりました。
2020-12-02T21:52:25.945+0800 INFO getty/listener.go:85 session{session session-closed, Read Bytes: 4586, Write Bytes: 232, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:org.apache.dubbo.rpc.RpcException: Failed to invoke remote proxy method sayHello to registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demoProvider&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.0.113%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26bind.ip%3D192.168.0.113%26bind.port%3D12345%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D23889%26register%3Dtrue%26release%3D2.7.3%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timeout%3D60000%26timestamp%3D1606916702204%26version%3D1.0.0&pid=23889®istry=zookeeper&release=2.7.3×tamp=1606916702193, cause: Not found method "sayHello" in class com.funnycode.DemoServiceImpl.
org.apache.dubbo.rpc.RpcException: Failed to invoke remote proxy method sayHello to registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demoProvider&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.0.113%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26bind.ip%3D192.168.0.113%26bind.port%3D12345%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D23889%26register%3Dtrue%26release%3D2.7.3%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timeout%3D60000%26timestamp%3D1606916702204%26version%3D1.0.0&pid=23889®istry=zookeeper&release=2.7.3×tamp=1606916702193, cause: Not found method "sayHello" in class com.funnycode.DemoServiceImpl.
at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:107)
at org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke(DelegateProviderMetaDataInvoker.java:56)
at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)
at org.apache.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:55)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:92)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:48)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:81)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:96)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:148)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:41)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$CallbackRegistrationInvoker.invoke(ProtocolFilterWrapper.java:157)
at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:152)
at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:102)
at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:193)
at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:51)
at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.dubbo.common.bytecode.NoSuchMethodException: Not found method "sayHello" in class com.funnycode.DemoServiceImpl.
at org.apache.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java)
at org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:47)
at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:84)
... 27 more
}, will be closed.
コードは2.7.7とは異なりますが、プロキシ拡張クラスでメソッドが見つからないことや、リフレクションでメソッドが見つからない可能性が高いことがエラーからわかりますので、最終的な分析でもパラメータの問題です。
4)問題を修正する
修復は比較的簡単で、struct
定義することJavaClassName
です。
case reflect.Struct:
v, ok := v.(hessian.POJO)
if ok {
return v.JavaClassName()
}
return "java.lang.Object"
5)検証結果
コンシューマーを再度実行すると、操作(プロバイダー2.7.7および2.7.3)は正常になり、出力は次のようになります。
[2020-12-03/20:04:06 main.main: client.go: 29] response result: Hello tc
...
[2020-12-03/20:04:09 main.main: client.go: 41] response result: Hello tc You are 18
...
[2020-12-03/20:04:09 main.main: client.go: 48] response result: Hello tc You are 18
詳細について話す
1.dubbogoコンシューマーを構成する方法
注意深く、私のdubbogoのコンシューマーインターフェイスが呼び出されDemoProvider
、次にプロバイダーが呼び出されることを発見しましたDemoService
。これはどのように正常に機能しますか?
実際、構成ファイルに関連するclient.yml
構成項目でreferences
、、などが指定されているinterface
場合はversion
、group
情報やその他のメソッドを渡してタイムアウトメソッドを構成することもできます。
references:
"DemoProvider":
# 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册
registry: "zk1"
protocol: "dubbo"
interface: "com.funnycode.DemoService"
cluster: "failover"
version: "1.0.0"
group: "tc"
methods:
- name: "SayHello"
retries: 3
......
2.グローバルグループとバージョンを構成する方法
構成ファイルは次のとおりです。
# application config
application:
organization: "dubbogoproxy.com"
name: "Demo Micro Service"
module: "dubbogoproxy tc client"
version: "1.0.0"
group: "tc"
owner: "ZX"
environment: "dev"
references:
"DemoProvider":
# 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册
registry: "zk1"
protocol: "dubbo"
interface: "com.funnycode.DemoService"
cluster: "failover"
# version: "1.0.0"
# group: "tc"
methods:
- name: "SayHello"
retries: 3
用語を使用しての習慣から、確かにapplication
グローバルコンフィギュレーションを表すが、私が活性化されるとことがわかっapplication
た構成version
とgroup
以下のようにプロバイダが見つからないとインターフェースに割り当てされることはありません、サービスを開始することは報告されます。
2020-12-03T20:15:42.208+0800 DEBUG zookeeper/registry.go:237 Create a zookeeper node:/dubbo/com.funnycode.DemoService/consumers/consumer%3A%2F%2F30.11.176.107%2FDemoProvider%3Fapp.version%3D1.0.0%26application%3DDemo+Micro+Service%26async%3Dfalse%26bean.name%3DDemoProvider%26cluster%3Dfailover%26environment%3Ddev%26generic%3Dfalse%26group%3D%26interface%3Dcom.funnycode.DemoService%26ip%3D30.11.176.107%26loadbalance%3D%26methods.SayHello.loadbalance%3D%26methods.SayHello.retries%3D3%26methods.SayHello.sticky%3Dfalse%26module%3Ddubbogoproxy+tc+client%26name%3DDemo+Micro+Service%26organization%3Ddubbogoproxy.com%26owner%3DZX%26pid%3D38692%26protocol%3Ddubbo%26provided-by%3D%26reference.filter%3Dcshutdown%26registry.role%3D0%26release%3Ddubbo-golang-1.3.0%26retries%3D%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1606997742%26version%3D
version
そしてgroup
、彼らは空です。あなたはDemoProvider
下にいversion
てgroup
コメントを開いている必要があります。
3.呼び出されたメソッドの名前を指定する方法
1)go 调用 java
goは大文字のメソッド名であり、javaは小文字のメソッド名であるため、dubbogoはdubboを呼び出します。そのため、次のエラーが発生します。
2020-12-02T17:10:47.739+0800 INFO getty/listener.go:87 session{session session-closed, Read Bytes: 924, Write Bytes: 199, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:Fail to decode request due to: java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, SayHello
java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, SayHello
at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:134)
at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:80)
at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57)
at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:44)
at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
}, will be closed.
注意深い読者が気づいたかもしれませんが、私はインターフェースのコンシューマー側がそこにあることを宣言しdubbo:"sayHello"
、メソッド名がsayHelloであることを示して、サービスプロバイダーがsayHelloメソッド名を取得できるようにします。
さらに、私が宣言した3つのメソッドはすべて、メソッド名を指定しますdubbo:"sayHello"
。これは、Javaが同じメソッド名でオーバーロードされる可能性があり、goがメソッド名を複製できないためです。
2)go 调用 go
実行できるコードを直接貼り付けます。
私のプロバイダーインターフェイス:
type DemoProvider struct{}
func (p *DemoProvider) SayHello(ctx context.Context, name string) (string, error) {
return "Hello " + name, nil
}
func (p *DemoProvider) SayHello4(ctx context.Context, user *User) (string, error) {
return "Hello " + user.Name + " You are " + strconv.Itoa(user.Age), nil
}
func (p *DemoProvider) SayHello5(ctx context.Context, user *User, name string) (string, error) {
return "Hello " + name + " You are " + strconv.Itoa(user.Age), nil
}
func (p *DemoProvider) Reference() string {
return "DemoProvider"
}
func (p *DemoProvider) MethodMapper() map[string]string {
return map[string]string{
"SayHello": "sayHello",
}
}
私の消費者インターフェース:
type DemoProvider struct {
// 调用 java 和 go
SayHello func(ctx context.Context, name string) (string, error) `dubbo:"sayHello"`
// 只调用 java
SayHello2 func(ctx context.Context, user *User) (string, error) `dubbo:"sayHello"`
SayHello3 func(ctx context.Context, user *User, name string) (string, error) `dubbo:"sayHello"`
// 只调用 go
SayHello4 func(ctx context.Context, user *User) (string, error)
SayHello5 func(ctx context.Context, user *User, name string) (string, error)
}
サービスコンシューマーを開始します。
func main() {
config.Load()
gxlog.CInfo("\n\n\nstart to test dubbo")
res, err := demoProvider.SayHello(context.TODO(), "tc")
if err != nil {
panic(err)
}
gxlog.CInfo("response result: %v\n", res)
user := &User{
Name: "tc",
Age: 18,
}
res, err = demoProvider.SayHello4(context.TODO(), user)
if err != nil {
panic(err)
}
gxlog.CInfo("response result: %v\n", res)
res, err = demoProvider.SayHello5(context.TODO(), user, "tc")
if err != nil {
panic(err)
}
gxlog.CInfo("response result: %v\n", res)
initSignal()
}
MethodMapper
メソッドは、このメソッドのメソッド名間のマッピングを構成する必要がある場合があることに注意してください。そうしないと、見つからないエラーメソッドが表示されます。
このような構成なdubbo:"sayHello"
ので、リクエストの内部に移動するSayHello
とsayHello
、サービスMethodMapper
プロバイダーはsayHello
、小文字と移動がjava小文字で公開されるように構成されているようになりますsayHello
。
4.hessian2を使用する理由
古いドライバーは、dubboのSPIメカニズムのデフォルト値がhessian2であることを知っています
@SPI("hessian2")
public interface Serialization {
}
そしてdubbo-goで:
func NewDubboCodec(reader *bufio.Reader) *ProtocolCodec {
s, _ := GetSerializerById(constant.S_Hessian2)
return &ProtocolCodec{
reader: reader,
pkgType: 0,
bodyLen: 0,
headerRead: false,
serializer: s.(Serializer),
}
}
5.ヘシアンシリアル化ソースコード
独自のブレークポイントで確認できます。2つの側面は基本的に同じです。比較して比較します。RpcInvocation.getParameterTypesDesc()はメソッドパラメータです。
- コードに行く
protocol/dubbo/impl/hessian.go:120#marshalRequest
- javaコード
org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeRequestData(org.apache.dubbo.remoting.Channel, org.apache.dubbo.common.serialize.ObjectOutput, java.lang.Object, java.lang.String)
6.dubbogoサービスプロバイダーのメソッドオブジェクトはポインターオブジェクトである必要があります
前の例はすべてコピーされましたが、今回は純粋なハンドプレイであり、この問題が発見されました。
オファーが:に類似しているfunc (p *DemoProvider) SayHello4(ctx context.Context, user User) (string, error)
場合、次のエラーが表示されます。
2020-12-03T12:42:32.834+0800 ERROR getty/listener.go:280 OnMessage panic: reflect: Call using *main.User as type main.User
github.com/apache/dubbo-go/remoting/getty.(*RpcServerHandler).OnMessage.func1
内部のパラメータUser
を変更する必要があります*User
。
7. dubbogoサービスコンシューマーのメソッドオブジェクトは、非ポインターオブジェクトにすることができます
SayHello4 func(ctx context.Context, user *User) (string, error)
// or
SayHello4 func(ctx context.Context, user User) (string, error)
パラメータがシリアル化されるとポインタが操作されるため:
t := reflect.TypeOf(v)
if reflect.Ptr == t.Kind() {
t = reflect.TypeOf(reflect.ValueOf(v).Elem())
}
8.構成ファイルの説明
dubbogoには3つの主要な構成ファイルがあります。
- server.yamlサービスプロバイダー構成ファイル
- client.yamlサービスコンシューマー構成ファイル
- log.yamlログファイル
何も設定しない場合は、次のように表示されます。
2021/01/11 15:31:41 [InitLog] warn: log configure file name is nil
2021/01/11 15:31:41 [consumerInit] application configure(consumer) file name is nil
2021/01/11 15:31:41 [providerInit] application configure(provider) file name is nil
通常は使用できません。サービスプロバイダーの場合はserver.yamlファイルを構成する必要があります。サービスコンシューマーの場合はclient.yamlを構成する必要があります。実際には、アプリケーションはコンシューマーとプロバイダーの両方である必要があるため、多くの場合、両方のファイルが必要です。構成済み。
サービスプロバイダーの通常の起動では、次の出力が得られます。
2021-01-11T15:36:55.003+0800 INFO protocol/protocol.go:205 The cached exporter keys is dubbo://:20000/DemoProvider?accesslog=&app.version=1.0.0&application=Demo+Micro+Service&auth=&bean.name=DemoProvider&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=tc&interface=com.funnycode.DemoService&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=3&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&methods.SayHello4.loadbalance=random&methods.SayHello4.retries=3&methods.SayHello4.tps.limit.interval=&methods.SayHello4.tps.limit.rate=&methods.SayHello4.tps.limit.strategy=&methods.SayHello4.weight=0&methods.SayHello5.loadbalance=random&methods.SayHello5.retries=3&methods.SayHello5.tps.limit.interval=&methods.SayHello5.tps.limit.rate=&methods.SayHello5.tps.limit.strategy=&methods.SayHello5.weight=0&module=dubbogoproxy+tc+client&name=Demo+Micro+Service&organization=dubbogoproxy.com&owner=ZX¶m.sign=®istry.role=3&release=dubbo-golang-1.3.0&retries=&serialization=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cgeneric_service%2Cexecute%2Cpshutdown&side=provider&ssl-enabled=false×tamp=1610350614&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=1.0.0&warmup=100!
2021-01-11T15:36:55.003+0800 INFO dubbo/dubbo_protocol.go:86 Export service: dubbo://:20000/DemoProvider?accesslog=&app.version=1.0.0&application=Demo+Micro+Service&auth=&bean.name=DemoProvider&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=tc&interface=com.funnycode.DemoService&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=3&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&methods.SayHello4.loadbalance=random&methods.SayHello4.retries=3&methods.SayHello4.tps.limit.interval=&methods.SayHello4.tps.limit.rate=&methods.SayHello4.tps.limit.strategy=&methods.SayHello4.weight=0&methods.SayHello5.loadbalance=random&methods.SayHello5.retries=3&methods.SayHello5.tps.limit.interval=&methods.SayHello5.tps.limit.rate=&methods.SayHello5.tps.limit.strategy=&methods.SayHello5.weight=0&module=dubbogoproxy+tc+client&name=Demo+Micro+Service&organization=dubbogoproxy.com&owner=ZX¶m.sign=®istry.role=3&release=dubbo-golang-1.3.0&retries=&serialization=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cgeneric_service%2Cexecute%2Cpshutdown&side=provider&ssl-enabled=false×tamp=1610350614&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=1.0.0&warmup=100
9.コードを複製します
-
https://github.com/cityiron/java_study/tree/master/dubbo2.7.7/dg-issue900
- https://github.com/cityiron/golang_study/tree/master/dubbogo/1.5.4/arg-bug
参照
-
https://dubbo.apache.org/zh/docs/v2.7/user/configuration/api/
- https://github.com/apache/dubbo-go/issues/257
スペースに限りがありますので、ここでやめましょう。興味のある学生は、読んでくれてありがとう、dubbogo3.0の構築に参加することを歓迎します。
著者について
Iron City(GithubID cityiron)、dubbo -goコミュニティコミッショナー、主にdubbo -go 1.5バージョンの反復、dubbo-go 3.0サービスルーティングとクラウドネイティブ作業、およびdubbo-go-proxyプロジェクトリーダーに関与。クラウドネイティブやマイクロサービスなどのテクノロジーの方向性に焦点を当て、Java / Go言語の使用に長けています。