lizining1231 opened a new issue, #3726:
URL: https://github.com/apache/dubbo-go/issues/3726

   ### 摘要
   
    #3718 已在服务端与客户端 IDL接入 `marshalAppender` 快路径(`marshalToPool` + 池化 
buffer),唯独**客户端非 IDL 请求**(`protoWrapperCodec`)未实现 `MarshalAppend`:类型断言 
`w.codec.(marshalAppender)` 必然失败,整条路径回退到 `codec.Marshal` 慢路径,该优化在客户端非 IDL 
请求场景并未生效。
   
   ### 相关代码
   
   | 位置                                                                         
                                                                             | 
为什么优化未覆盖                                                                        
                                     |
   | 
-------------------------------------------------------------------------------------------------------------------------------------------------------
 | 
--------------------------------------------------------------------------------------------------------------------
 |
   | 
https://github.com/apache/dubbo-go/blob/develop/protocol/triple/triple_protocol/codec.go#L267-L292
                      | 只实现了 `Marshal`,**没有** 
`MarshalAppend`;类型断言命中不了,`marshalToPool` 快路径无从进入                                
               |
   | 
https://github.com/apache/dubbo-go/blob/develop/protocol/triple/triple_protocol/option.go#L116-L122
                  | 客户端非 IDL 的唯一入口,构造 `newProtoWrapperCodec(&hessian2Codec{})` 
/ `newProtoWrapperCodec(&msgpackCodec{})`,未暴露 appender 能力 |
   | 
https://github.com/apache/dubbo-go/blob/develop/protocol/triple/triple_protocol/envelope.go#L69-L95
                         | gRPC wire 的 appender 
探测点(`w.codec.(marshalAppender)`)。因 wrapper 未实现而失败,落到 `marshalWithFallback` 慢路径  
                |
   | 
https://github.com/apache/dubbo-go/blob/develop/protocol/triple/triple_protocol/protocol_triple.go#L504-L523
       | Triple wire 的 unary 生产入口,同为探测点,同样必然失败                                  
                                              |
   | 
https://github.com/apache/dubbo-go/blob/develop/protocol/triple/triple_protocol/marshal_perf_regression_test.go#L721-L755
 | 当前显式断言`protoWrapperCodec`不得实现`marshalAppender`(名为 `proto wrapper (hessian 
inner)` 的 never 用例)     |
   
   ### 建议优化
   
   为 `protoWrapperCodec` 增加 `MarshalAppend`:内层语义逐字保持,仅把外层 wrapper 
编码从"新分配"改为"追加进调用方缓冲区"。
   
   **1. codec 层:新增可选方法(不改** **`Codec`** **接口)**
   
   ```go
   // MarshalAppend appends the TripleRequestWrapper encoding of message to dst.
   // The inner payload encoding is intentionally identical to Marshal: this
   // extension only changes where the outer wrapper bytes are written.
   func (c *protoWrapperCodec) MarshalAppend(dst []byte, message any) ([]byte, 
error) {
        reqs, ok := message.([]any)
        if !ok {
                reqs = []any{message}
        }
   
        reqsLen := len(reqs)
        reqsBytes := make([][]byte, reqsLen)
        reqsTypes := make([]string, reqsLen)
        for i, req := range reqs {
                reqBytes, err := c.innerCodec.Marshal(req) // unchanged: inner 
payload stays as-is
                if err != nil {
                        return nil, err
                }
                reqsBytes[i] = reqBytes
                reqsTypes[i] = getArgType(req)
        }
   
        wrapperReq := &interoperability.TripleRequestWrapper{
                SerializeType: c.innerCodec.Name(),
                Args:          reqsBytes,
                ArgTypes:      reqsTypes,
        }
   
        return proto.MarshalOptions{}.MarshalAppend(dst, wrapperReq)
   }
   ```
   
   `proto.MarshalOptions.MarshalAppend` 把调用方 `dst` 直接交给编码器,`cap(dst)-len(dst) 
>= size` 时跳过 `make + copy` 走纯 append(生成代码的 `Size` + append 编码函数,`sizecache` 缓存 
size),**零分配、零清零**。
   
   **2. 发送路径:零调用点改动**
   
   快路径探测是类型断言(`w.codec.(marshalAppender)`),因此 wrapper 
一旦实现该方法,`envelopeWriter.Marshal` 与 `tripleUnaryMarshaler.Marshal` 
**自动命中**现有池化管道(`marshalToPool` → `bufferPool`)。
   
   **3. 回退语义与 #3718 保持一致**
   
   仅 marshal 失败才回退 `backupCodec`;写失败(I/O、压缩、`sendMaxBytes` 
超限)为终止性错误,绝不回退重试。`MarshalAppend` 的错误语义与 `Marshal` 等价(同一错误对象直接向上返回,由快路径转成 
`CodeInternal`)。
   
   **4. 零开关、零配置回退**
   
   不新增配置项、不改公开接口:任何未实现 `marshalAppender` 的 codec(hessian2 / msgpack / JSON / 
第三方)行为完全不变,整体回退无需发布开关。
   
   ### 测试
   
   本提案**只新增 wrapper 定向测试**;发送管道层(池、压缩、回退、并发)的测试直接复用 #3718,不重复实现。
   
   新增测试:
   
   1. `TestMarshalPerfClientWrapperFastPath`:两条 wire 均命中快路径(防单侧探测点失效导致一半流量白优化)+ 
快慢路径 wire 字节对拍(防协议漂移),覆盖 hessian2 / msgpack × 压缩开 / 关;
   2. `TestNonIDLUnary_PublicEntry_MarshalAppendEffective`:经真实 `NewClient` → 
`CallUnary` 入口确认优化确实生效——wrapper 一旦丢掉 `MarshalAppend` 或探测点失效即失败,不静默退回优化前行为;
   3. `TestMarshalPerfTypeGuard`(就地扩围):正向断言 wrapper 必须实现 `marshalAppender`,反向断言 
`hessian2` / `msgpack` / `json` 仍不实现。
   
   复用已合入的测试
   
   `TestMarshalPerfPoolInvariants` / `TestMarshalPerfBackupCodecFallback` / 
`TestMarshalPerfCompressionAndMaxBytes` / `TestMarshalPerfConcurrentSend` 
验证对象是**发送管道**(`marshalToPool` + `bufferPool` + 压缩 + 回退 + 并发)而非具体 
codec,wrapper可被覆盖
   
   ### 参考实现
   
   本提案与 #3718 为同做法,仅作用对象不同
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to