1.golangï¼contextä»ç»
2.Java教程:dubbo源码解析-网络通信
3.gRPC 基础概念详解
4.Dubbo源码解析:网络通信
golangï¼contextä»ç»
1 åè¨
æè¿å®ç°ç³»ç»çåå¸å¼æ¥å¿ä¸äºå¡ç®¡çæ¶,å¨å¯»æ±æè°çå ¨å±å¯ä¸Goroutine IDæ æä¹å,å³å®è¿æ¯ç®åå©ç¨Contextæºå¶å®ç°äºåºæ¬çæ³æ³,ä¸å¤é«æ,ä½æ¯å¥½ç¨.äºæ¯å¯¹å®å½åç设计æ¯è¾å¥½å¥,便æäºæ¤æ.
Contextæ¯golangå®æ¹å®ä¹çä¸ä¸ªpackage,å®å®ä¹äºContextç±»å,éé¢å å«äºDeadline/Done/Erræ¹æ³ä»¥åç»å®å°Contextä¸çæååéå¼Value,å ·ä½å®ä¹å¦ä¸ï¼
typeContextinterface{ //è¿åContextçè¶ æ¶æ¶é´ï¼è¶ æ¶è¿ååºæ¯ï¼Deadline()(deadlinetime.Time,okbool)//å¨Contextè¶ æ¶æåæ¶æ¶ï¼å³ç»æäºï¼è¿åä¸ä¸ªå ³éçchannel//å³å¦æå½åContextè¶ æ¶æåæ¶æ¶,Doneæ¹æ³ä¼è¿åä¸ä¸ªchannel,ç¶åå ¶ä»å°æ¹å°±å¯ä»¥éè¿å¤æDoneæ¹æ³æ¯å¦æè¿åï¼channelï¼,å¦ææå说æContextå·²ç»æ//æ å ¶å¯ä»¥ä½ä¸ºå¹¿æéç¥å ¶ä»ç¸å ³æ¹æ¬Contextå·²ç»æ,请åç¸å ³å¤ç.Done()<-chanstruct{ }//è¿åContextåæ¶çåå Err()error//è¿åContextç¸å ³æ°æ®Value(keyinterface{ })interface{ }}é£ä¹å°åºä»ä¹Contextï¼å¯ä»¥åé¢ææå¯ä»¥ç解为ä¸ä¸æ,æ¯è¾çæçæè¿ç¨/线ç¨ä¸çº¿æ,å ³äºgolangä¸çä¸ä¸æ,ä¸å¥è¯æ¦æ¬å°±æ¯ï¼ goroutineçç¸å ³ç¯å¢å¿«ç §,å ¶ä¸å å«å½æ°è°ç¨ä»¥åæ¶åçç¸å ³çåéå¼. éè¿Contextå¯ä»¥åºåä¸åçgoroutine请æ±,å 为å¨golang Seversä¸,æ¯ä¸ªè¯·æ±é½æ¯å¨å个goroutineä¸å®æç.
æè¿å¨å ¬å¸åægRPCæºç ,protoæ件çæç代ç ,æ¥å£å½æ°ç¬¬ä¸ä¸ªåæ°ç»ä¸æ¯ctx context.Contextæ¥å£,å ¬å¸ä¸å°åäºé½ä¸äºè§£è¿æ ·è®¾è®¡çåºåç¹æ¯ä»ä¹,å ¶å®æä¹ä¸äºè§£å ¶èåçåç.ä»å¤©è¶ç妮妲å°é£å¦¹åæ£é¢ç»éæ·±å³,å ¨å¸åå·¥,å课,åä¸,å¨å®¶ä¼æ¯æ¾äºä¸äºèµæç 究æç©ä¸æ.
Contexté常被è¯ä½ä¸ä¸æ,å®æ¯ä¸ä¸ªæ¯è¾æ½è±¡çæ¦å¿µ.å¨å ¬å¸ææ¯è®¨è®ºæ¶ä¹ç»å¸¸ä¼æå°ä¸ä¸æ.ä¸è¬ç解为ç¨åºåå çä¸ä¸ªè¿è¡ç¶æ,ç°åº,å¿«ç §,èç¿»è¯ä¸ä¸ä¸åå¾å¥½å°è¯ éäºå ¶æ¬è´¨,ä¸ä¸ä¸ä¸åæ¯åå¨ä¸ä¸å±çä¼ é,ä¸ä¼æå å®¹ä¼ éç»ä¸.å¨Goè¯è¨ä¸,ç¨åºåå ä¹å°±æçæ¯Goroutine.
æ¯ä¸ªGoroutineå¨æ§è¡ä¹å,é½è¦å ç¥éç¨åºå½åçæ§è¡ç¶æ,é常å°è¿äºæ§è¡ç¶æå°è£ å¨ä¸ä¸ªContextåéä¸,ä¼ éç»è¦æ§è¡çGoroutineä¸. ä¸ä¸æåå ä¹å·²ç»æä¸ºä¼ éä¸è¯·æ±åçåå¨æåéçæ åæ¹æ³.å¨ç½ç»ç¼ç¨ä¸,å½æ¥æ¶å°ä¸ä¸ªç½ç»è¯·æ±Request,å¤çRequestæ¶,æ们å¯è½éè¦å¼å¯ä¸åçGoroutineæ¥è·åæ°æ®ä¸é»è¾å¤ç,å³ä¸ä¸ªè¯·æ±Request,ä¼å¨å¤ä¸ªGoroutineä¸å¤ç. èè¿äºGoroutineå¯è½éè¦å ±äº«Requestçä¸äºä¿¡æ¯;åæ¶å½Request被åæ¶æè è¶ æ¶çæ¶å,ææä»è¿ä¸ªRequestå建çææGoroutineä¹åºè¯¥è¢«ç»æ.
注ï¼å ³äºgoroutineçç解å¯ä»¥ç§»æ¥è¿é.
2 为ä»ä¹ä½¿ç¨contextç±äºå¨golang seversä¸,æ¯ä¸ªrequesté½æ¯å¨å个goroutineä¸å®æ,并ä¸å¨å个goroutineï¼ä¸å¦¨ç§°ä¹ä¸ºAï¼ä¸ä¹ä¼æ请æ±å ¶ä»æå¡ï¼å¯å¨å¦ä¸ä¸ªgoroutineï¼ç§°ä¹ä¸ºBï¼å»å®æï¼çåºæ¯,è¿å°±ä¼æ¶åå¤ä¸ªGoroutineä¹é´çè°ç¨.å¦ææä¸æ¶å»è¯·æ±å ¶ä»æå¡è¢«åæ¶æè è¶ æ¶,åä½ä¸ºæ·±é·å ¶ä¸çå½ågoroutine Béè¦ç«å³éåº,ç¶åç³»ç»æå¯åæ¶Bæå ç¨çèµæº. å³ä¸ä¸ªrequestä¸é常å å«å¤ä¸ªgoroutine,è¿äºgoroutineä¹é´é常ä¼æ交äº.
é£ä¹,å¦ä½ææ管çè¿äºgoroutineæ为ä¸ä¸ªé®é¢ï¼ä¸»è¦æ¯éåºéç¥åå æ°æ®ä¼ éé®é¢ï¼,Googleç解å³æ¹æ³æ¯Contextæºå¶,ç¸äºè°ç¨çgoroutineä¹é´éè¿ä¼ écontextåéä¿æå ³è,è¿æ ·å¨ä¸ç¨æ´é²ågoroutineå é¨å®ç°ç»èçåæä¸,ææå°æ§å¶ågoroutineçè¿è¡.
å¦æ¤ä¸æ¥,éè¿ä¼ éContextå°±å¯ä»¥è¿½è¸ªgoroutineè°ç¨æ ,并å¨è¿äºè°ç¨æ ä¹é´ä¼ ééç¥åå æ°æ®. è½ç¶goroutineä¹é´æ¯å¹³è¡ç,没æ继æ¿å ³ç³»,ä½æ¯Context设计ææ¯å å«ç¶åå ³ç³»ç,è¿æ ·å¯ä»¥æ´å¥½çæè¿°goroutineè°ç¨ä¹é´çæ åå ³ç³».
3 æä¹ä½¿ç¨contextçæä¸ä¸ªContext主è¦æ两类æ¹æ³ï¼
3.1 顶å±Contextï¼Backgroundè¦å建Contextæ ,é¦å å°±æ¯è¦åå»ºæ ¹èç¹
//è¿åä¸ä¸ªç©ºçContext,å®ä½ä¸ºææç±æ¤ç»§æ¿Contextçæ ¹èç¹funcBackground()Context该Contexté常ç±æ¥æ¶requestç第ä¸ä¸ªgoroutineå建,å®ä¸è½è¢«åæ¶,没æå¼,ä¹æ²¡æè¿ææ¶é´,常ä½ä¸ºå¤çrequestç顶å±contextåå¨.
3.2 ä¸å±Contextï¼WithCancel/WithDeadline/WithTimeoutæäºæ ¹èç¹ä¹å,æ¥ä¸æ¥å°±æ¯å建ååèç¹.为äºå¯ä»¥å¾å¥½çæ§å¶ååèç¹,Contextå æä¾çå建æ¹æ³åæ¯å¸¦æ第äºè¿åå¼ï¼CancelFuncç±»åï¼,å®ç¸å½äºä¸ä¸ªHook,å¨ågoroutineæ§è¡è¿ç¨ä¸,å¯ä»¥éè¿è§¦åHookæ¥è¾¾å°æ§å¶ågoroutineçç®çï¼é常æ¯åæ¶,å³è®©å ¶åä¸æ¥ï¼.åé åContextæä¾çDoneæ¹æ³,ågoroutineå¯ä»¥æ£æ¥èªèº«æ¯å¦è¢«ç¶çº§èç¹Cancelï¼
select{ case<-ctx.Done()://dosomecleanâ¦}注ï¼ç¶èç¹Contextå¯ä»¥ä¸»å¨éè¿è°ç¨cancelæ¹æ³åæ¶åèç¹Context,èåèç¹Contextåªè½è¢«å¨çå¾ .åæ¶ç¶èç¹Contextèªèº«ä¸æ¦è¢«åæ¶ï¼å¦å ¶ä¸çº§èç¹Cancelï¼,å ¶ä¸çææåèç¹Contextåä¼èªå¨è¢«åæ¶.
æä¸ç§å建æ¹æ³ï¼
//带cancelè¿åå¼çContext,ä¸æ¦cancel被è°ç¨,å³åæ¶è¯¥å建çcontextfuncWithCancel(parentContext)(ctxContext,cancelCancelFunc)//带æææcancelè¿åå¼çContext,å³å¿ é¡»å°è¾¾æå®æ¶é´ç¹è°ç¨çcacelæ¹æ³æä¼è¢«æ§è¡funcWithDeadline(parentContext,deadlinetime.Time)(Context,CancelFunc)//å¸¦è¶ æ¶æ¶é´cancelè¿åå¼çContext,类似Deadline,åè æ¯æ¶é´ç¹,åè 为æ¶é´é´é//ç¸å½äºWithDeadline(parent,time.Now().Add(timeout)).funcWithTimeout(parentContext,timeouttime.Duration)(Context,CancelFunc)ä¸é¢æ¥çæ¹ç¼èªAdvanced Go Concurrency Patternsè§é¢æä¾çä¸ä¸ªç®åä¾åï¼
packagemainimport("context""fmt""time")funcsomeHandler(){ //å建继æ¿Backgroundçåèç¹Contextctx,cancel:=context.WithCancel(context.Background())godoSth(ctx)//模æç¨åºè¿è¡-Sleep5ç§time.Sleep(5*time.Second)cancel()}//æ¯1ç§workä¸ä¸,åæ¶ä¼å¤æctxæ¯å¦è¢«åæ¶,å¦ææ¯å°±éåºfuncdoSth(ctxcontext.Context){ vari=1for{ time.Sleep(1*time.Second)select{ case<-ctx.Done():fmt.Println("done")returndefault:fmt.Printf("work%dseconds:\n",i)}i++}}funcmain(){ fmt.Println("start...")someHandler()fmt.Println("end.")}è¾åºç»æï¼
注æ,æ¤æ¶doSthæ¹æ³ä¸caseä¹doneçfmt.Println("done")并没æ被æå°åºæ¥.
è¶ æ¶åºæ¯ï¼
packagemainimport("context""fmt""time")functimeoutHandler(){ //å建继æ¿Backgroundçåèç¹Contextctx,cancel:=context.WithTimeout(context.Background(),3*time.Second)godoSth(ctx)//模æç¨åºè¿è¡-Sleepç§time.Sleep(*time.Second)cancel()//3ç§åå°æååæ¶doSthgoroutine}//æ¯1ç§workä¸ä¸,åæ¶ä¼å¤æctxæ¯å¦è¢«åæ¶,å¦ææ¯å°±éåºfuncdoSth(ctxcontext.Context){ vari=1for{ time.Sleep(1*time.Second)select{ case<-ctx.Done():fmt.Println("done")returndefault:fmt.Printf("work%dseconds:\n",i)}i++}}funcmain(){ fmt.Println("start...")timeoutHandler()fmt.Println("end.")}è¾åºç»æï¼
4 contextæ¯ä¸ä¸ªä¼é ç设计å?ç¡®å®,éè¿å¼å ¥Contextå ,ä¸ä¸ªrequestèå´å æægoroutineè¿è¡æ¶çåæ¶å¯ä»¥å¾å°æRæçæ§å¶.ä½æ¯è¿ç§è§£å³æ¹å¼å´ä¸å¤ä¼é .
4.1 context åç æ¯ä¸æ ·æ©æ£ä¸æ¦ä»£ç ä¸æå¤ç¨å°äºContext,ä¼ éContextåéï¼é常ä½ä¸ºå½æ°ç第ä¸ä¸ªåæ°ï¼ä¼åç æ¯ä¸æ ·è延å¨åå¤è°ç¨å®çå°æ¹. æ¯å¦å¨ä¸ä¸ªrequestä¸å®ç°æ°æ®åºäºå¡æè åå¸å¼æ¥å¿è®°å½, å建çcontext,ä¼ä½ä¸ºåæ°ä¼ éå°ä»»ä½ææ°æ®åºæä½ææ¥å¿è®°å½éæ±çå½æ°ä»£ç å¤. å³æ¯ä¸ä¸ªç¸å ³å½æ°é½å¿ é¡»å¢å ä¸ä¸ªcontext.Contextç±»åçåæ°,ä¸ä½ä¸ºç¬¬ä¸ä¸ªåæ°,è¿å¯¹æ å ³ä»£ç å®å ¨æ¯ä¾µå ¥å¼ç.
æ´å¤è¯¦ç»å 容å¯åè§ï¼Michal Strba çcontext-should-go-away-go2æç«
Google Groupä¸ç讨论å¯ç§»æ¥è¿é.
4.2 Context ä¸ä» ä» åªæ¯cancelä¿¡å·Contextæºå¶ææ ¸å¿çåè½æ¯å¨goroutineä¹é´ä¼ écancelä¿¡å·,ä½æ¯å®çå®ç°æ¯ä¸å®å ¨ç.
Cancelå¯ä»¥ç»å为主å¨ä¸è¢«å¨ä¸¤ç§,éè¿ä¼ écontextåæ°,让è°ç¨goroutineå¯ä»¥ä¸»å¨cancel被è°ç¨goroutine.ä½æ¯å¦ä½å¾ç¥è¢«è°ç¨goroutineä»ä¹æ¶åæ§è¡å®æ¯,è¿é¨åContextæºå¶æ¯æ²¡æå®ç°ç.èç°å®ä¸çç¡®åæä¸äºè¿æ ·çåºæ¯,æ¯å¦ä¸ä¸ªç»è£ æ°æ®çgoroutineå¿ é¡»çå¾ å ¶ä»goroutineå®ææå¯å¼å§æ§è¡,è¿æ¯contextææ¾ä¸å¤ç¨äº,å¿ é¡»åå©sync.WaitGroup.
funcserve(lnet.Listener)error{ varwgsync.WaitGroupvarconnnet.Connvarerrerrorfor{ conn,err=l.Accept()iferr!=nil{ break}wg.Add(1)gofunc(cnet.Conn){ deferwg.Done()handle(c)}(conn)}wg.Wait()returnerr}4.3 context.valuecontext.Valueç¸å½äºgoroutineçTLSï¼Thread Local Storageï¼,ä½å®ä¸æ¯éæç±»åå®å ¨ç,ä»»ä½ç»æä½åéé½å¿ é¡»ä½ä¸ºå符串形å¼åå¨.åæ¶,ææcontexté½ä¼å¨å ¶ä¸å®ä¹åé,å¾å®¹æé æå½åå²çª.
5 æ»ç»contextå éè¿æ建æ åå ³ç³»çContext,æ¥è¾¾å°ä¸ä¸å±Goroutineè½å¯¹ä¼ éç»ä¸ä¸å±Goroutineçæ§å¶.对äºå¤çä¸ä¸ªRequest请æ±æä½,éè¦éç¨contextæ¥å±å±æ§å¶Goroutine,以åä¼ éä¸äºåéæ¥å ±äº«.
Context对象ççåå¨æä¸è¬ä» 为ä¸ä¸ªè¯·æ±çå¤çå¨æ.å³é对ä¸ä¸ªè¯·æ±å建ä¸ä¸ªContextåéï¼å®ä¸ºContextæ ç»æçæ ¹ï¼;å¨è¯·æ±å¤çç»æå,æ¤éæ¤ctxåé,éæ¾èµæº.
æ¯æ¬¡å建ä¸ä¸ªGoroutine,è¦ä¹å°åæçContextä¼ éç»Goroutine,è¦ä¹å建ä¸ä¸ªåContextå¹¶ä¼ éç»Goroutine.
Contextè½çµæ´»å°åå¨ä¸åç±»å,ä¸åæ°ç®çå¼,并ä¸ä½¿å¤ä¸ªGoroutineå®å ¨å°è¯»åå ¶ä¸çå¼.
å½éè¿ç¶Context对象å建åContext对象æ¶,å¯åæ¶è·å¾åContextçä¸ä¸ªæ¤éå½æ°,è¿æ ·ç¶Context对象çå建ç¯å¢å°±è·å¾äºå¯¹åContextå°è¦è¢«ä¼ éå°çGoroutineçæ¤éæ.
å¨åContextè¢«ä¼ éå°çgoroutineä¸,åºè¯¥å¯¹è¯¥åContextçDoneä¿¡éï¼channelï¼è¿è¡çæ§,ä¸æ¦è¯¥ä¿¡éè¢«å ³éï¼å³ä¸å±è¿è¡ç¯å¢æ¤éäºæ¬goroutineçæ§è¡ï¼,åºä¸»å¨ç»æ¢å¯¹å½å请æ±ä¿¡æ¯çå¤ç,éæ¾èµæºå¹¶è¿å.
6 è´è°¢pkg/context
context-should-go-away-go2
ç解 Go Context æºå¶
context-isnt-for-cancellation
context-is-for-cancelation
thread-local-a-convenient-abomination
Java教程:dubbo源码解析-网络通信
在之前的内容中,我们探讨了消费者端服务发现与提供者端服务暴露的相关内容,同时了解到消费者端通过内置的负载均衡算法获取合适的调用invoker进行远程调用。接下来,我们聚焦于远程调用过程,即网络通信的支付宝药品怎么查溯源码细节。
网络通信位于Remoting模块中,支持多种通信协议,包括但不限于:dubbo协议、rmi协议、hessian协议、ty进行网络通讯,NettyClient.doOpen()方法中可以看到Netty的相关类。序列化接口包括但不限于:Serialization接口、Hessian2Serialization接口、Kryo接口、FST接口等。
序列化方式如Kryo和FST,性能往往优于hessian2,能够显著提高序列化性能。这些高效Java序列化方式的引入,可以优化Dubbo的序列化过程。
在配置Dubbo RPC时,引入Kryo和FST非常简单,只需在RPC的XML配置中添加相应的属性即可。
关于服务消费方发送请求,Dubbo框架定义了私有的加好友网站源码RPC协议,消息头和消息体分别用于存储元信息和具体调用消息。消息头包括魔数、数据包类型、消息体长度等。消息体包含调用消息,如方法名称、参数列表等。请求编码和解码过程涉及编解码器的使用,编码过程包括消息头的写入、序列化数据的存储以及长度的写入。解码过程则涉及消息头的读取、序列化数据的解析以及调用方法名、参数等信息的提取。
提供方接收请求后,服务调用过程包含请求解码、调用服务以及返回结果。解码过程在NettyHandler中完成,通过ChannelEventRunnable和DecodeHandler进一步处理请求。服务调用完成后,通过Invoker的invoke方法调用服务逻辑。响应数据的编码与请求数据编码过程类似,涉及数据包的构造与发送。
服务消费方接收调用结果后,首先进行响应数据解码,获得Response对象,并传递给下一个处理器NettyHandler。扫码巡检源码处理后,响应数据被派发到线程池中,此过程与服务提供方接收请求的过程类似。
在异步通信场景中,Dubbo在通信层面为异步操作,通信线程不会等待结果返回。默认情况下,RPC调用被视为同步操作。Dubbo通过CompletableFuture实现了异步转同步操作,通过设置异步返回结果并使用CompletableFuture的get()方法等待完成。
对于异步多线程数据一致性问题,Dubbo使用编号将响应对象与Future对象关联,确保每个响应对象被正确传递到相应的Future对象。通过在创建Future时传入Request对象,可以获取调用编号并建立映射关系。线程池中的线程根据Response对象中的调用编号找到对应的Future对象,将响应结果设置到Future对象中,供用户线程获取。
为了检测Client端与Server端的连通性,Dubbo采用双向心跳机制。HeaderExchangeClient初始化时,开启两个定时任务:发送心跳请求和处理重连与断连。心跳检测定时任务HeartbeatTimerTask确保连接空闲时向对端发送心跳包,而ReconnectTimerTask则负责检测连接状态,当判定为超时后,客户端选择重连,极致打赏源码服务端采取断开连接的措施。
gRPC 基础概念详解
gRPC基础概念详解 本文将为您介绍gRPC的基础概念。首先通过关系图直观展示基础概念之间的关联,介绍异步gRPC的Server和Client的逻辑;然后介绍RPC的类型,阅读和抓包分析gRPC的通信过程协议,以及gRPC上下文;最后,分析grpc.pb.h文件的内容,包括Stub的能力、Service的种类以及与核心库的关系。一、基本概念概览
上图展示了gRPC的基础概念及其关系。其中包括:Service(定义)、RPC、API、Client、Stub、Channel、Server、Service(实现)、ServiceBuilder等。以example/helloworld为例进行说明
.proto文件定义了服务Greeter和APISayHello。类GreeterClient是Client,是对Stub的封装,通过Stub可以真正调用RPC请求。
Channel提供一个与特定gRPC server的主机和端口建立的连接。 Stub是spring企业项目源码在Channel的基础上创建而成的。Server端需要实现对应的RPC,所有的RPC组成了Service:
Server的创建需要一个Builder,添加上监听的地址和端口,注册上该端口上绑定的服务,最后构建出Server并启动。RPC和API的区别
RPC(Remote Procedure Call)是一次远程过程调用的整个动作,而API(Application Programming Interface)是在实现RPC中的不同语言的具体接口。一个RPC可能对应多种API,比如同步的、异步的、回调的。一次RPC是对某个API的一次调用,例如: 不管是哪种类型的RPC,都是由Client发起请求。二、异步相关概念
无论是Client还是Server,异步gRPC都利用CompletionQueueAPI进行异步操作。基本流程如下: 官方文档Asynchronous-API tutorial中有详细介绍,包括异步client和server的解释,对应文件greeter_async_client.cc和greeter_async_server.cc。1. 异步Client
greeter_async_client.cc是异步Client的Demo,逻辑相对简单。2. 异步Server
RequestSayHello函数没有详细说明,文档和注释中的解释可能不够清晰。通过增加日志打印,可以更清晰展示Server的逻辑。3. 关系图
通过关系图展示异步Client和异步Server的逻辑。右侧为创建对象中的内存内容,左侧使用相同颜色的小块进行表示。4. 异步Client 2
在example/cpp/helloworld中,还有另一个异步Client,对应文件greeter_async_client2.cc。此示例中使用两个线程分别进行请求发送和返回处理。5. 回调方式的异步调用
在example/cpp/helloworld中,提供回调相关的Client和Server。使用回调方式结构与同步方式相似,但并发方式不同。可以通过文件对比查看其中差异。5.1 回调Client
发送单个请求,在调用SayHello时,除了传入Request、Reply的地址,还需要传入接收Status的回调函数。 例子中只有一个请求,因此在SayHello后直接通过condition_variable的wait函数等待回调结束,然后进行后续处理。这种情况下不能进行并发,与同步请求类似。大规模并发时需要额外封装。5.2 回调Server
与同步Server不同之处在于...三、流相关概念
可以按照Client和Server一次发送/返回的是单个消息还是多个消息,将gRPC分为:1. Server对RPC的实现
Server需要实现proto中定义的RPC,每种RPC的实现都需要将ServerContext作为参数输入。2. Client对RPC的调用
Client调用一元(Unary)RPC时,像调用普通函数一样,除了传入ClientContext之外,将Request和Response的地址传入,返回的是RPC状态。四、通信协议
本节通过介绍gRPC协议文档描述和对helloworld的抓包,来说明gRPC是如何基于HTTP2传输的。1. ABNF语法
ABNF语法是一种描述协议的标准,gRPC协议也是使用ABNF语法描述,包括几种常见的运算符。2. 请求协议
* 表示element会重复多次(最少0次),理解概况描述。3. 返回协议
()表示括号中的内容作为单个元素对待,/表示前后两个元素可选其一。Response的定义说明,可以有两种返回形式。五、上下文
gRPC支持上下文的传递,其主要用途有:客户端添加自定义的metadata key-value对没有特别的区分,而服务端添加的,则有initial和trailing两种metadata的区别。
六、生成代码
通过protoc生成gRPC相关的文件,除了用于消息体定义的xxx.pb.h和xxx.pb.cc文件之外,就是定义RPC过程的xxx.grpc.pb.h和xxx.grpc.pb.cc。以helloworld.proto生成的文件为例,看看.xxx.grpc.pb文件具体定义了些什么。1. Stub
.proto中的一个service只有一个Stub,该类中会提供对应每个RPC的所有同步、异步、回调等方式的函数,而该类继承自接口类StubInterface。2. Service
有几个概念都叫Service:proto文件中RPC的集合、proto文件中service产生源文件中的Greeter::Service类、gRPC框架中的::grpc::Service类。本小节说的Service就是helloworld.grpc.pb.h中的Greeter::Service。3. Service的种类
helloworld.grpc.pb.h文件中7种Service中有3对Service的实际含义相同,实际只剩下4种Service。4. 与::grpc核心库的关系
Stub类中主要是用到gRPCChannel和不同类型RPC对应的实现方法。总结
通过本文,您应该对gRPC的基础概念有了全面的了解。从基本概念到异步操作、流相关概念、通信协议、上下文到生成代码,每个环节都进行了详细的阐述。希望本文能帮助您在gRPC开发中更加得心应手。Dubbo源码解析:网络通信
<dubbo源码解析:深入理解网络通信
在之前的章节中,我们已经了解了消费者如何通过服务发现和负载均衡机制找到提供者并进行远程调用。本章将重点解析网络通信的实现细节。
网络通信主要在Dubbo的Remoting模块中进行,涉及多种通信协议,包括dubbo协议、RMI、Hessian、HTTP、WebService、Thrift、REST、gRPC、Memcached和Redis等。每个协议都有其特定的优缺点,如Dubbo协议适用于高并发场景,而RMI则使用标准JDK序列化。
Dubbo的序列化机制支持多种方式,如Hessian2、Kryo、FST等。近年来,高效序列化技术如Kryo和FST的出现,可提升性能,只需在配置中简单添加即可优化。
关于数据格式和粘包拆包问题,Dubbo采用私有RPC协议,消息头存储元信息,如魔法数和数据类型,消息体则包含调用信息。消费者发送请求时,会通过MockClusterInvoker封装服务降级逻辑,然后通过序列化转换为网络可传输的数据格式。
服务提供方接收请求时,首先对数据包进行解码,确认其格式正确性,然后调用服务逻辑。提供方返回调用结果时,同样经过序列化和编码,最后通过NettyChannel发送给消费者。
在心跳检测方面,Dubbo采用双向心跳机制,客户端和服务端定期发送心跳请求以维持连接。此外,还通过定时任务处理重连和断连,确保连接的稳定性和可靠性。
总的来说,Dubbo的网络通信模块精细且灵活,通过多种协议和优化技术确保服务调用的高效和可靠性。