Author | Tiecheng dubbo-go Community Committer
Source | Alibaba Cloud Native Official Account
This article will teach you how to use dubbogo to call the service provider provided by dubbogo or dubbo.
Preface
This article is based on dubbogo version 1.5.4 .
Recently I started to participate in some development and testing of dubbogo. Before, I used the examples of samples to verify the function. This time, in order to reproduce a functional problem, I plan to build a dubbo-go and dubbo call project from scratch. Some new people use it. The pit of dubbogo, record this process for your reference.
Through this article, you can learn:
- How to routinely configure dubbogo consumers to call dubbo and dubbogo service providers.
- Introduce the idea of solving the problem through an actual BUG.
Solve the problem
1. Prepare dubbo service provider
1) Basic definition
Defined DemoService
interfaces:
public interface DemoService {
String sayHello(String name);
String sayHello(User user);
String sayHello(User user, String name);
}
Defined User
objects:
public class User implements Serializable {
private String name;
private int age;
......
}
2) Start dubbo service provider
The official dubbo sample code used :
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();
}
Check zookeeper to see if the registration is successful:
$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]
The above output indicates that the service provider has started.
2. Prepare dubbogo to serve consumers
1) Basic definition
Define the User
object:
type User struct {
Name string
Age int
}
func (User) JavaClassName() string {
return "com.funnycode.User"
}
Defined DemoProvider
interfaces:
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) Start dubbogo consumer
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. Request result analysis
1) Direct call
Confirm the existence of the problem.
The parameter of the first interface is a string, which can be returned normally [2020-12-03/18:59:12 main.main: client.go: 29] response result: Hello tc
.
The second and third interfaces have User
objects and cannot be called successfully. The error message is as follows:
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.
The error is exactly the same as described in the issue , because the error information is returned to the consumer, you can see the error stack information on the Java side, so go directly to it DecodeableRpcInvocation.decode#134
.
2) Breakpoint view
code show as below:
// 反序列化
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);
}
......
}
}
- Check
MethodDescriptor
, that is, find whether the method exists, if it exists, it will be setParameterClasses
. - If the above is not found, the
pts == DubboCodec.EMPTY_CLASS_ARRAY
conditions will be met, and then it will be judged whether it is a generalized call or an echo call. If neither is found, the service cannot find a method error. - desc Yes
Ljava/lang/Object
, obviously there is no method whose parameter is Object, so an error is bound to be reported.
Supplementary note: method query.
** The
code is as follows:
public MethodDescriptor getMethod(String methodName, String params) {
Map<String, MethodDescriptor> methods = descToMethods.get(methodName);
if (CollectionUtils.isNotEmptyMap(methods)) {
return methods.get(params);
}
return null;
}
Advantages : Compared with the previous version, the meta information of the method is cached, and the efficiency can be improved by not using reflection, and it can be understood that space is exchanged for time.
4. Solve the problem
Because you can't hold the code directly, you can check the problem by comparing.
1) Start dubbo service consumer
Start by api mode, refer to the official example. This is activated to view the transmission content of the Java version.
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 To the naked eye Lcom/funnycode/User
, this is the right object.
2) Why is it wrong to find dubbogo
Code location:protocol/dubbo/impl/hessian.go:120#marshalRequest
Code:
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)
}
......
}
Breakpoints can be found, when the types of returns is already Object
, and did not return User
, then continue with the inside look at the code.
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"
}
......
}
Obviously when found reflect.Struct
when he returned java.lang.Object
, so the argument becomes Object
, because then the Java code over there so I rely on this type of call failed.
3) Verification of other versions
Because the feedback was an error in 2.7.7, we first considered whether the previous version was functioning normally, so we switched the service provider to dubbo 2.7.3 and found that the call still had an error, as follows:
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.
Although the code is different from 2.7.7, it can be seen from the error that the method cannot be found in the proxy enhancement class, and there is a high probability that reflection cannot find the method, so in the final analysis it is also a parameter problem.
4) Fix the problem
Repair is relatively simple, is to get struct
defined JavaClassName
.
case reflect.Struct:
v, ok := v.(hessian.POJO)
if ok {
return v.JavaClassName()
}
return "java.lang.Object"
5) Verification result
Execute the consumer again, the operation (provider 2.7.7 and 2.7.3) is normal, and the output is as follows:
[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
Talk about the details
1. How to configure dubbogo consumer
Carefully, have you discovered that the consumer interface of my dubbogo is called DemoProvider
, and then the provider is called DemoService
. How does this work normally?
In fact, and client.yml
the configuration items references
related to the configuration file specifies interface
, version
, group
etc., you can also pass information and other methods to configure the timeout method.
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. How to configure the global group and version
The configuration file is as follows:
# 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
From the habit of using terms, certainly application
represents a global configuration, but I found that when activated in application
the configuration version
and group
the provider can not be found and will not be assigned to the interface, start the service will be reported as follows:
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
And group
they are empty. You must be DemoProvider
under version
and group
comment open.
3. How to specify the name of the called method
1) go adjustment java
dubbogo calls dubbo, because go is an uppercase method name, and java is a lowercase method name, so the following error will occur:
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.
Careful readers may have noticed, I declare the consumer side of the interface is there dubbo:"sayHello"
, showing the method name is sayHello, so that service providers can get sayHello method name.
In addition, the three methods I declared all specify their method names dubbo:"sayHello"
. This is because Java can be overloaded with the same method name, and go cannot duplicate method names.
2) go adjustment go
Directly paste the code that can run through.
My provider interface:
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",
}
}
My consumer interface:
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)
}
Start service consumer:
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()
}
It should be noted that MethodMapper
the method sometimes need to configure the mapping between the method name in this method, or otherwise not found error method will appear.
Because such configuration dubbo:"sayHello"
, so go inside the request SayHello
becomes sayHello
, the service provider by MethodMapper
the method such that the provider is configured sayHello
so that the lower and go are exposed java lowercase sayHello
.
4. Why use hessian2
Old drivers know that the default value of the SPI mechanism in dubbo is hessian2
@SPI("hessian2")
public interface Serialization {
}
And in 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. Hessian serialization source code
You can check by your own breakpoints. The two sides are basically the same. I also compare them by comparing them. RpcInvocation.getParameterTypesDesc() is the method parameter.
- go code
protocol/dubbo/impl/hessian.go:120#marshalRequest
- java code
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. The method object of the dubbogo service provider needs to be a pointer object
The previous examples were all copied, this time it was pure hand-playing, and I discovered this problem.
If your offer is similar to:, func (p *DemoProvider) SayHello4(ctx context.Context, user User) (string, error)
then the following error will appear:
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
Inside the parameters User
need to be changed *User
.
7. The method object of dubbogo service consumer can be a non-pointer object
SayHello4 func(ctx context.Context, user *User) (string, error)
// or
SayHello4 func(ctx context.Context, user User) (string, error)
Because the pointer is operated on when the parameter is serialized:
t := reflect.TypeOf(v)
if reflect.Ptr == t.Kind() {
t = reflect.TypeOf(reflect.ValueOf(v).Elem())
}
8. Configuration file description
There are three main configuration files for dubbogo:
- server.yaml service provider configuration file
- client.yaml service consumer configuration file
- log.yaml log file
If you do not configure anything, it will appear:
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
This cannot be used normally. If you are a service provider, you must configure the server.yaml file. If you are a service consumer, you must configure client.yaml. Actually, our application should be both a consumer and a provider, so often both files are required. Configured.
The normal startup of the service provider will have the following output:
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. Reproduce the code
-
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
reference
-
https://dubbo.apache.org/zh/docs/v2.7/user/configuration/api/
- https://github.com/apache/dubbo-go/issues/257
Space is limited, so let’s stop here. Interested students are welcome to participate in the construction of dubbogo3.0 , thanks for reading.
About the Author
Iron City (GithubID cityiron) , dubbo-go community committer, mainly involved in dubbo-go 1.5 version iteration, dubbo-go 3.0 service routing and cloud native work, and dubbo-go-proxy project leader. Good at using Java/Go language, focusing on technology directions such as cloud native and microservices.