从零搭建 dubbogo
作者 | 鐵城??dubbo-go 社區 committer
來源|阿里巴巴云原生公眾號
本文將手把手教你使用 dubbogo 調用 dubbogo 或 dubbo 提供的服務提供方。
前言
本文基于 dubbogo 1.5.4 版本。
最近開始參與 dubbogo 的一些開發測試,之前都是直接拿 samples?的例子驗證功能,而這次為了復現一個功能問題,打算從零開始搭建一個 dubbo-go 和 dubbo 調用的工程,踩到了一些新人使用 dubbogo 的坑,把這個過程記錄下供大家參考。
通過本文你可以了解到:
- 如何常規配置 dubbogo 消費方去調用 dubbo 和 dubbogo 服務提供方。
- 通過一個實際的 BUG 介紹解決問題的思路。
解決問題
1. 準備 dubbo 服務提供者
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)啟動 dubbo 服務提供者
用的 dubbo 官方示例代碼:
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(); }查看 zookeeper 看是否注冊成功:
$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 stringAge 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`。第二、三兩個接口存在?`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, sayHelloat 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.錯誤正如 issue?中描述的一模一樣,因為錯誤信息返回到了消費端,可以看到 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 就會滿足條件,進而判斷是否是泛化調用或者是 echo 調用,如果都不是則報服務找不到方法錯誤。
- desc 是 Ljava/lang/Object ,很明顯并沒有參數是 Object 的方法,所以必然是會報錯的。
補充說明:方法查詢。
**
代碼如下:
優點:比之前的版本加了方法的元信息緩存起來,不使用反射可以提高效率,可以理解用空間換時間。
4. 解決問題
因為直接擼代碼并 hold 不住,所以通過比較來查看問題所在。
1)啟動?dubbo 服務消費者
通過 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一樣使用xxxServiceDemoService 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.Servicerequest := 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)}...... }斷點可以發現,types 返回的時候就已經是 Object 了,沒有返回 User,那么繼續跟進去查看代碼。
- protocol/dubbo/impl/hessian.go:394#getArgsTypeList
- protocol/dubbo/impl/hessian.go:418#getArgType
很明顯當發現是 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 等,你還可以通過 methods 配置方法的超時時間等信息。
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. 全局的 group 和 version 怎么配置
配置文件如下:
# 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%3Dversion 和 group 都是空。必須把 DemoProvider 下的 version 和 group 注釋打開。
3. 怎么指定調用的方法名
1)go 調用 java
dubbogo 調用 dubbo,因為 go 是大寫的方法名,java 里面是小寫的方法名,所以會出現如下錯誤:
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, SayHelloat 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 這個方法名。
還有我聲明的三個方法都指明它們的方法名叫 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 和 goSayHello func(ctx context.Context, name string) (string, error) `dubbo:"sayHello"`// 只調用 javaSayHello2 func(ctx context.Context, user *User) (string, error) `dubbo:"sayHello"`SayHello3 func(ctx context.Context, user *User, name string) (string, error) `dubbo:"sayHello"`// 只調用 goSayHello4 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",所以在 go 里面請求 SayHello 變成了 sayHello,那么服務提供方通過 MethodMapper 方法配置后使得提供方也是 sayHello,這樣 go 和 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. hessian 序列化源碼
可以自行斷點查看,兩邊基本上一樣,我也是通過兩邊比出來的,RpcInvocation.getParameterTypesDesc() 就是方法的參數.
- go 代碼 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 服務提供者的方法對象需要是指針對象
之前的例子都是 copy 的,這次是純手打的,才發現了這個問題。
如果你的提供類似:func (p *DemoProvider) SayHello4(ctx context.Context, user User) (string, error),那么會出現如下錯誤:
參數里面的 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 主要有三個配置文件:
- 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=1009. 復現代碼
-
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 的建設,感謝閱讀。如果你有任何疑問,歡迎釘釘搜索群號:31363295,加入交流群。
作者簡介
鐵城(GithubID cityiron),dubbo-go 社區 committer,主要參與 dubbo-go 1.5 版本迭代、 dubbo-go 3.0 服務路由和云原生方面工作、以及 dubbo-go-proxy 項目負責人。擅長使用 Java/Go 語言,專注于云原生和微服務等技術方向。
原文鏈接:https://developer.aliyun.com/article/781292?
版權聲明:本文內容由阿里云實名注冊用戶自發貢獻,版權歸原作者所有,阿里云開發者社區不擁有其著作權,亦不承擔相應法律責任。具體規則請查看《阿里云開發者社區用戶服務協議》和《阿里云開發者社區知識產權保護指引》。如果您發現本社區中有涉嫌抄襲的內容,填寫侵權投訴表單進行舉報,一經查實,本社區將立刻刪除涉嫌侵權內容。總結
以上是生活随笔為你收集整理的从零搭建 dubbogo的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mPaas 厂商 push 不通排查指南
- 下一篇: 阿里云MongoDB,一直被模仿,从未被