grpc 基础和 http1.0 http2.0 http1.1 区别 HTTP 2.0区别

数据库

MySQL Connector 最新版本的安装、配置链接的 manual

MySQL Connector/C++ 8.0 Developer Guide (oracle.com)

MySQL Connector API 的不同语言 manual 目录。

MySQL :: Connectors and APIs

MySQL 有好几种 API。

最简单的是 mysql 本身有一套 tcp 通信协议:MySQL :: MySQL Internals Manual :: 14 MySQL Client/Server Protocol  是 classic MySQL protocol。然后 5.7 之后,有了 X Plugin,基于 google 的 protobuf 做了一套新的协议 X 协议:MySQL :: MySQL Internals Manual :: 15 X Protocol。比如 boost 最近要做真异步 cpp mysql connector 的提案了,所以就要基于这些协议从头做起:

GitHub - anarthal/mysql: MySQL C++ client based on Boost.Asio. Proposed for Boost

然后最生的就是 C API。MySQL :: MySQL 5.6 C API Developer Guide :: 5.1 Overview of the C API Basic Interface。用法基本就是 C 的函数过程式调用风格。MySQL的 shell 本身用的就是这些 api,他们在库 libmysqlclient 中提供,shipped with Mysql distributions。

JDBC 风格 API,由于 MySQL 和 Java 都经历了太阳+甲骨文,所以,API 的风格就是 Java 的 JDBC 风格。所以 C++ 的封装是,一开始是比如 mysql connector c++ 1.1 时候的 api,MySQL :: MySQL Connector/C++ 1.1 Developer Guide :: 7.1 Prerequisites and Background Information 他是利用 C++ 的 JDBC 风格,通过 libmysqlcppconn-dev (debian)提供封装,然后这个是基于其他两个包的,对于 1.1,就是基于纯 c 封装的 JDBC 风格。在8.0 库之后使用只需要引入 mysql/jdbc.h ,在 1.1 库的时候,需要引入一堆 cppconn/*.h。MySQL Connector/C++: Connector/C++ 8.0 legacy C++ API based on JDBC4 这里有教程(需要有libmysqlcppconn8)。

8.0 之后,支持 X API,X API 是一个把 MySQL 当成文档数据库(NoSQL)使用的 API,MySQL :: X DevAPI User Guide :: 2.1 Database Connection Example. 就是类似 LINQ 的东西。总之,新的应用程序就用这种 API 就行了。

持久层

根据 J2EE 多年的经验,一般而言,RDBMS 数据库的查询都是通过拼接 SQL,然后送查询的,以及,MySQL 的数据库部分是通过网络链接的,也就是,一个查询需要用一个长连接(Cpp 里面不用关闭,MySQL 的 Connection 类的析构函数写好了),所以一般客户端应当搞一个连接池。然后拼接字符串不安全,而且还有参数检验、过滤等。Mybatis 是一个持久层框架,主要是通过 mapper xml 配置参数检验、过滤、类的成员属性提取等。

首先是 entity 类型,在 Java 中一般有一个最基本的类型, Plain Ordinary Java Object,不被任何框架侵入。然后他是路由 JavaBean 的思路,无参数构造,getter + setter。之后的再套他就行了。

DAO 层,是 MVC 里面的 Model 中负责数据库模块的层(Data access object),此时处理的数据就是 DAO 类型,或者 PO,persistant object。Service 上实现逻辑的就是逻辑的 Object,实现 View 的就是 View Object。而涉及通信的比如 RPC,又是 DTO data transfer Object。然后就要进行映射和不断的 copy。总之这些都很麻烦,一般来说要进行一个映射。对于 Jvav 来说,因为有反射,而且 J2EE 赢,Java 用了这么多年,他们早就写好这些框架了(比如 beanUtils、 mapstruct 等框架)。mybatis-plus 还支持直接访问数据库然后生成类文件,这是由于 mysql 的 information_schema 表对于数据库用户是公开的,特别是 8.0 的 API 是非常方便的?不过之前的也不差。

传输协议

废话不多说,总之我们现在知道就是会有很多结构体转来转去的 grpc 的 proto 文件生成的就是 DTO,类似 Mybatis 或者写一个对 mysql 的 wrapper 来说,就是 PO,然后基础类型是 POJO(C 的 struct),这部分内容互转以及定义结构体的方法基本在于代码生成或者基于反射的内容 runtime 进行转换。

对于 Java 来说,有 GC 存在,对象随便造,而且过程中只要没有写深拷贝(clone),嗯造的全是指针,指针指向的那个东西才有内存的问题(当然 Java 的 String 的复制存在是因为旧版 JDK 的类似 string_view 的做法有一个问题就是有引用指向大对象,因此内存泄漏)。

C++ 是不敢摁造的,一个是内存管理只有底层的 malloc 器(你可以用 malloc 还是tcmalloc 任意),一不小心就调用 copy ctor 或者 copy assign 了,有 swap 和智能指针还好,没有就麻烦了。

protobuf 的解决方案是搞出一个 Arena Allocation 来,总之就是内存池吧, 实际就是批量 malloc,减少 malloc call,减少 incremental 的内存调用这个能工作是因为 message 是通过组合形成的。By default, protocol buffers performs heap allocations for each message object, each of its subobjects, and several field types, such as strings.These allocations occur in bulk when parsing a message and when building new messages in memory, and associated deallocations happen when messages and their subobject trees are freed.  With arena allocation, new objects are allocated out of a large piece of preallocated memory called the arena. Objects can all be freed at once by discarding the entire arena, ideally without running destructors of any contained object (though an arena can still maintain a "destructor list" when required. C++ Arena Allocation Guide  |  Protocol Buffers  |  Google Developers 一言以蔽之,就是预先分配一系列内存块(内部有一个列表)。创建Message和内部对象的时候全部在分配好的内存块上 placement new 出来。

直接用 raw 的 Arena 的时候,每个 mesage 的 free 责任都由他绑定的 arena 管理(相当与 RAII 的 arena 管理,一个 arena 实例就是一个内存池(初始化的固定大小避免重复 malloc),只不过 arena 可以拥有一组权限,所以叫竞技场地)。

arena 还能直接 own 一个堆上的对象,从而负责他们的析构。这样的话,就要通过 Reset 来重用 arena 上的内存了。对于对象中的 arena field,arena 还可以直接释放他们(protobuf 本身消息不支持继承,但是支持组合)。

arena 本身是 thread-safe 的,但是他们的对象不是,Reset 也不是 thread-safe 的(shared object 的析构很危险,因此使用 shared_ptr 是线程安全析构的最优解)。

然后这里就有一个问题是作者本身尽量做成 thread safe 的还是让使用者去负责线程安全呢比如 STL 就没有提供,以及,不同的线程安全、并发语义的要求也不一样。以及不同的数据结构可能有不同的用法和写法,比如无锁数据结构等。但是比如一个 concurrent 库呢?这种东西的一个 feature 就是提供没有并发负担地编写程序。总之,没有通用的做法。

说偏了,arena 还有一个问题讲完之后进入 grpc,就是他的内存泄漏问题,由于堆内存会被 preserve,采用了 arena 之后,会有多少内存被 arena 锁定呢?这个可以通过 ArenaOption 调整arena.h  |  Protocol Buffers  |  Google Developers,start_block_size\max_block_ssize。总之 arena 就是等于直接写了一个用户态 malloc,但是不会 free(析构才,或者 POD 干脆不析构)。

grpc 的 sync 调用服务器端不支持 arena,async 才支持 arena。客户端直接支持,因为客户端的 request 和 response 的内存生命周期都是由客户端自己指定的,然后 stub 进行一个复制和包的操作。而服务端的有问题就是,request 的内存实际来自发进来的网络包,response 的内存实际是在发出去的网络包,这样做是因为服务端的队列十分的多,而客户端的请求可能不会同时发送这么多。

然后是 grpc 的指针,他采用指针是因为对于 server 端,东西直接就在 protocol buffer 上搞出来的,收到二进制,解析,生成在一个明文 buffer 里面,准备发送的时候,一个 context 也是一个压缩 buffer。

context 的话可以用来得到 peer 信息,链接信息、压缩信息、deadline 之类的。

然后是 grpc 的底层多路复用:

grpc/grpc-polling-engines.md at master · grpc/grpc (github.com)

// grpc/grpc-polling-engines.md at master · grpc/grpc (github.com)
std::stringserver_address("0.0.0.0:11111");
BookSystemImplservice{a,b,c};
ServerBuilderbuilder;
builder.AddListeningPort(server_address,grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server>server(builder.BuildAndStart());
std::cout<<"Serverlisteningon"<<server_address<<std::endl;
server->Wait();

他本质是个类似 asio 的异步模型,典中典之 completion token:

我们再来看明白 gRPC 的整个过程,Core concepts, architecture and lifecycle | gRPC

客户端创建的 channel 也有 polling engine,这样同时可以发送多个请求  GRPC Core: Polling Engine Usage on gRPC client and Server。一个 channel 可以同时发送多个请求等待结果(subchannel)。

这里这个 channel 的概念太乱了。根据 grpc 的博客,gRPC on HTTP/2 Engineering a Robust, High-performance Protocol | gRPC,理清楚一点:

grpc 全部默认采用长连接,也就是一个 http 可以有多个 channel,但是这些 channel 可能说是用来发包的更加明白一些。下图中的 conn 是 HTTP2 连接。

grpc 就蹦到这里。best practice:根据Performance Best Practices | gRPCPerformance best practices with gRPC | Microsoft Docs 。懒得摘抄了。

还有一个 HTTP2 的问题,传统的是要么长连接请求,等结果,请求,等结果。现在 HTTP2 可以流水线,主要是这样的,由于三言两语讲不清楚,而且网上的图片基本不区分传播时延和传输时延,我画一幅图来阐述一下这个典吧:

虽然这幅图画得很垃圾,但是也是画了我几分钟的。也基本讲明白了 TCP 本身是有序的 HTTP/2 如何实现无序的传输了。

以上,理论(闲聊)部分就到这里截止。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值