已发表的技术专栏
0 grpc-go、protobuf、multus-cni 技术专栏 总入口
1 grpc-go 源码剖析与实战 文章目录
2 Protobuf介绍与实战 图文专栏 文章目录
3 multus-cni 文章目录(k8s多网络实现方案)
4 grpc、oauth2、openssl、双向认证、单向认证等专栏文章目录)
经过前面几篇文章分析,我们已经服务器端接收到数据帧后,经历抽样流控,链路流控,流级别流控;
那么,接下来我们要考虑的问题是,服务器端如何来维护接收到数据帧呢?
换句话说,服务器端接收到不止一个数据帧时,按照什么原则来存储这些数据帧? 是随意存储,还是存储到单链表里呢?
1、数据帧存储到recvBuffer里的整体流程图? |
1.1、存储模型图? |
1.2、存储流程图? |
主要流程说明:
2、从源码的视角进行分析 |
2.1、将接收到数据帧封装到类型为bytes.Buffer对象里 |
分析入口在:
在gRPC-go源码中提供了测试用例,随便找一个服务器端的启动文件main.go ,参考下面的调用链即可找到:
main.go->s.Serve->s.handleRawConn(rawConn)->s.serveStreams(st)->st.HandleStreams(func(stream *transport.Stream)->handleData方法
或者
直接进入grpc-go/internal/transport/http2_server.go文件中的handleData方法里:
1.func (t *http2Server )handleData(f *http2.DataFrame) {
2. // ---省略掉----流控相关代码-----
3. s := t.getStream(f)
4. if size > 0 {
5.
6. if len(f.Data()) > 0 {
7. buffer := t.bufferPool.get()
8. buffer.Reset()
9. buffer.Write(f.Data())
10. s.write(recvMsg{buffer: buffer})
11. }
12. }
13. // ---省略掉----不相关代码-----
14.}
本次分析,只关心第7-10行:
主要流程说明:
2.2、gRPC-go框架是如何存储bytes.Buffer对象的?也就是,如何来存储接收到的数据帧的 |
接着上面,直接点击write方法:(进入grpc-go/internal/transport/transport.go文件中Stream结构体的Write方法里:)
func (s *Stream) write(m recvMsg) {
s.buf.put(m)
}
可见,实际调用的是类型recvBuffer的put方法:
进入grpc-go/internal/transport/transport.go文件中recvBuffer结构体的put方法里:
1.func (b *recvBuffer) put(r recvMsg) {
2. b.mu.Lock()
3. if b.err != nil {
4. b.mu.Unlock()
5. // An error had occurred earlier, don't accept more
6. // data or errors.
7. return
8. }
9. b.err = r.err
10. if len(b.backlog) == 0 {
11. select {
12. case b.c <- r:
13. b.mu.Unlock()
14. return
15. default:
16. }
17. }
18. b.backlog = append(b.backlog, r)
19. b.mu.Unlock()
20.}
主要流程说明:
假设客户端将一个数据帧分多次发送,服务端第一次接收到数据帧后是存储到通道b.c里了,以后的数据帧呢? |
可能场景一: |
可能场景二: |
如果前一个数据还没有被消费的话,就存储到切片b.backlog里;
这种方式,
其实是保证了数据是按照顺序存储的 |
到目前为止,已经将接收到数据帧真正的存储到本地内存了,至于如何读取,再后面的章节,会介绍。
3、总结 |
其实,本篇文章在解决一种场景,接收端接收到多次请求后,如何保证按顺序存储,为以后按顺序读取数据奠定了基础。
底层采用了通道+切片的方式实现。 |
在自己的项目中,如果有类似的场景,是不是可以作为一种参考方案呢?
将别人的经验,别人的源码,经过抽象整理后,灵活运用到我们自己的场景中,才是我们的最终目的。 |
下一篇文章
服务器端在真正执行客户端的请求方法前,是如何完整的读取到请求参数值的?
点击下面的图片,返回到专栏大纲 |