- 云原生
- 集群管理
- 容器编排
- 任务调度
【免费下载链接】mesos
Apache Mesos
导读
Apache Mesos 使用 Google Protocol Buffers(protobuf)作为其内部消息传递与对外 API 的核心数据交换格式。为了保证构建的可复现性与运行时的一致性,Mesos 选择在仓库中捆绑特定版本的 protobuf(当前为 3.5.0),并围绕它构建出一整套下载、打补丁、编译和代码生成的流水线。本文以 3rdparty/protobuf.md 为主体,结合仓库中的 CMake / Autotools 构建脚本与.proto文件布局,完整讲解:为什么捆绑 3.5.0、如何重新打包 protobuf 源码、如何通过--with-protobuf切换到系统版本,以及 protoc 是如何为 Mesos 的公共与内部 API 生成 C++ / Java / gRPC 代码的。读完本文,你将掌握 Mesos 中 protobuf 依赖管理的完整机制,并能独立处理源码打包、补丁应用与构建参数选择。
为什么 Mesos 要捆绑 Protobuf 3.5.0
捆绑动机:C++ move 语义与额外优化
3rdparty/protobuf.md中明确说明了捆绑版本的选型理由:
We bundle 3.5.0 in order to take advantage of C++ move support and additional optimizations.
即:Mesos 捆绑 protobuf 3.5.0,是为了利用该版本引入的C++ move 支持以及随之而来的额外性能优化。
在 Mesos 这种对性能敏感的大规模集群调度系统中,protobuf 对象会频繁地在各个组件(master、agent、scheduler、executor)之间被复制与传递。C++11 move 语义允许编译器以"窃取资源"的方式转移对象内部指针,避免深拷贝带来的堆分配与内存拷贝开销。这一点也在 3rdparty/libprocess/src/tests/benchmarks.cpp 的基准测试注释中得到印证——该测试专门构造了"不支持 move 的 protobuf 对象"与支持 move 的对象进行对照,用于测量消息传递路径的性能差异。
从版本约束角度看,Mesos 1.5 及之后的版本要求 protobuf 3+,这在 docs/upgrades.md 的升级说明中有明确记载:"Protobuf version 3+ is required to build Mesos",因此捆绑 3.5.0 也符合整体版本下限要求。
版本与校验信息集中在两处
Mesos 同时维护两套构建系统(Autotools 与 CMake),protobuf 的版本与校验和在这两套系统中分别登记:
- CMake 侧:3rdparty/cmake/Versions.cmake 定义
PROTOBUF_VERSION = "3.5.0"与PROTOBUF_HASH = "SHA256=F046682F05C39605E1687DC37E2E0EEBCEB8298CA1B046D64EE00AE124924EBC"; - Autotools 侧:3rdparty/versions.am 定义
PROTOBUF_VERSION = 3.5.0。
同时仓库根目录下存放着对应的源码压缩包protobuf-3.5.0.tar.gz与两个平台补丁protobuf-3.5.0.patch、protobuf-3.5.0_s390x.patch。这种"一处登记、多处引用"的设计保证了版本号在构建脚本中始终同步。
如何重新打包 Bundled Protobuf
3rdparty/protobuf.md给出了标准的重新打包流程。这一流程的核心思路是:从 GitHub 拉取官方源码、解压、运行 autogen.sh 生成构建脚本、再重新压缩为 tar.gz。注意这一步骤并非构建 Mesos 时所执行,而是维护者在升级/新增捆绑依赖时执行的一次性操作:
curl -L -O https://github.com/google/protobuf/archive/<version>.tar.gz tar -xzf <version>.tar.gz cd <version> ./autogen.sh cd .. tar -czf <version>.tar.gz <version>逐步拆解如下:
curl -L -O ...:下载指定<version>的官方源码包(-L跟随重定向,-O保持原文件名)。tar -xzf:解压到同名目录。./autogen.sh:关键步骤。protobuf 的源码树并不直接携带configure脚本,autogen.sh会调用 autoconf/automake/libtool 生成configure与各类 Makefile 模板。因此打包时必须先运行它,否则后续 Autotools 构建(./configure && make)无法进行。tar -czf <version>.tar.gz <version>:重新打包成与 Mesos 仓库命名约定一致的protobuf-3.5.0.tar.gz形式。
生成的新包最终被放置到仓库的3rdparty/目录下(即当前仓库中的protobuf-3.5.0.tar.gz),并由版本登记文件锁定版本号与 SHA256 校验值。以 CMake 构建为例,3rdparty/CMakeLists.txt 会以FETCH_URL拼接出protobuf-${PROTOBUF_VERSION}.tar.gz的下载地址,并在ExternalProject_Add中通过URL_HASH校验包的完整性。
补丁:为平台兼容性做的两处修改
捆绑版本并非"原样使用"。仓库为 protobuf 3.5.0 准备了两个补丁,分别针对不同的平台/编译器场景,这体现了 Mesos 对构建兼容性的精细管理。
protobuf-3.5.0.patch:类型安全的强制转换(Windows / MSVC)
3rdparty/protobuf-3.5.0.patch 对repeated_field.h与wire_format_lite.h做了三处修改:
- 在
CalculateReserve中,将std::distance(begin, end)的返回值用static_cast<int>显式收窄,避免在 MSVC 的 strict 警告设置下产生 narrowing conversion 告警; - 在
RepeatedPtrField::erase的两个重载中,将std::distance的结果显式转换为size_type; - 在
WireFormatLite::ZigZagDecode32/64中,将-(n & 1)改写为(~(n & 1) + 1)。注释指出此处使用无符号类型是为了防止 undefined behavior,显式的取反加一写法在窄整型环境下语义更明确。
该补丁只在Windows构建中被应用:见 3rdparty/CMakeLists.txt,if (WIN32) PATCH_CMD(PROTOBUF_PATCH_CMD protobuf-${PROTOBUF_VERSION}.patch),同时将protobuf_MSVC_STATIC_RUNTIME关闭以动态链接 CRT。
protobuf-3.5.0_s390x.patch:s390x 架构的原子操作修复
3rdparty/protobuf-3.5.0_s390x.patch 为 IBM s390x(大型机)架构补充了Release_CompareAndSwap的 GCC 内建实现。它基于__atomic_compare_exchange_n实现带 RELEASE/ACQUIRE 内存序的 CAS,填补了atomicops_internals_generic_gcc.h中 64 位原子操作在该架构上的缺口。
Autotools 构建中对该补丁的应用逻辑位于 3rdparty/Makefile.am:通过$(PROTOBUF)_s390x-stamp规则调用patch -d protobuf-3.5.0 -p1打补丁,并先于$(PROTOBUF)-build-stamp执行。CMake 侧则在非 Windows 分支中统一应用该补丁(3rdparty/CMakeLists.txt)。
构建集成:Autotools 与 CMake 双轨
Autotools:--with-protobuf[=DIR]参数与版本探测
Mesos 的configure脚本通过 configure.ac 注册了--with-protobuf[=DIR]参数,其语义是:
Excludes building and using the bundled protobuf package in lieu of an installed version at a location prefixed by the given path.
即:放弃捆绑版本,改用一个已安装的 protobuf;若提供了=DIR,则以DIR/include、DIR/lib作为头文件与库的搜索前缀(configure.ac)。
具体的探测流程(configure.ac):
- 若指定了
--with-protobuf或未开启 bundled 模式,则进入"使用系统 protobuf"分支; - 先检查头文件
google/protobuf/map.h(该头文件是 protobuf 3 的标志),再通过链接测试google::protobuf::ShutdownProtobufLibrary()确认库可用; - 若探测失败,
configure会直接报错退出,提示"no suitable protobuf (version 3+) could be found",并要求通过--with-protobuf=DIR指定前缀路径; - 若成功,则设置
PROTOCOMPILER指向系统protoc,并用AC_CHECK_FILE校验protobuf.jar(Java 侧)与wrappers.proto等文件。
这里有一个容易踩坑的约束:如果使用非捆绑的 gRPC,则必须同时显式指定--with-protobuf=DIR。configure.ac(configure.ac)会强制要求这样做,理由是"避免使用相互冲突的 protobuf 版本"。
Bundled 模式下(3rdparty/Makefile.am),构建流程为:解包 →(s390x 打补丁)→ 进入protobuf-3.5.0/执行./configure并传入 zlib 相关的CPPFLAGS/LDFLAGS(注意 protobuf 的--with-zlib是开关而非路径参数,所以 zlib 路径必须走环境变量传递,这一点在 3rdparty/Makefile.am 有专门注释)→make产出libprotobuf.la与protoc,最后通过 3rdparty/Makefile.am 的安装规则安装。
CMake:ExternalProject 集成
CMake 侧使用ExternalProject_Add将 protobuf 作为外部依赖构建(3rdparty/CMakeLists.txt):
- 通过 3rdparty/cmake/External.cmake 的
EXTERNAL(protobuf ${PROTOBUF_VERSION} ...)生成目标目录命名,如protobuf-3.5.0; - 以
SOURCE_SUBDIR cmake指明使用 protobuf 自身的 CMake 构建;以CMAKE_ARGS传入-Dprotobuf_BUILD_TESTS=OFF关闭测试以加快构建; PATCH_COMMAND按平台选择补丁(Windows 用protobuf-3.5.0.patch,其他平台用_s390x.patch);- 构建产物被导出为三个 imported 目标:
protobuf(libprotobuf 库)、libprotoc以及protoc可执行文件(3rdparty/CMakeLists.txt); - 库的 Debug 后缀处理:Debug 构建下
libprotobuf文件名带d后缀(libprotobufd),Ninja / Visual Studio 生成器分别用不同的IMPORTED_LOCATION属性登记(3rdparty/CMakeLists.txt); - 安装阶段会将
libprotobuf、libprotoc与protoc分别安装到库目录与运行时目录,并在ENABLE_INSTALL_MODULE_DEPENDENCIES开启时把src/google下的头文件一并安装(3rdparty/CMakeLists.txt)。
protoc 代码生成:Mesos 如何把.proto变成可编译代码
捆绑 protobuf 的最终目的,是用其protoc编译器把 Mesos 自身的.proto定义编译成 C++ / Java 代码。
Mesos 的 proto 文件布局
仓库中的 proto 文件分为三类(可用find_files以*.proto模式枚举):
- 公共 API proto:位于
include/mesos/,例如核心的 include/mesos/mesos.proto(proto2 语法、package mesos、option cc_enable_arenas = true,定义FrameworkID、TaskID、OfferID、Status等基础消息),以及 v1 版本 API 的 include/mesos/v1/scheduler/scheduler.proto 等; - 内部消息 proto:位于
src/,如 src/messages/messages.proto、src/master/registry.proto、src/resource_provider/state.proto 等,用于 master / agent 之间的内部通信与状态持久化; - 外部库(LIB 模式)proto:如 CSI 插件规范
csi/v0/csi.proto、gRPC 相关测试 proto 等。
PROTOC_GENERATE 函数
CMake 构建中,所有 proto 编译均由 src/cmake/MesosProtobuf.cmake 的PROTOC_GENERATE函数驱动。该函数支持四个选项:
| 选项 | 作用 |
|---|---|
| 默认(无选项) | 编译include/mesos/下的公共 proto,输出到build/include/ |
INTERNAL | 编译src/下的内部 proto,输出到build/src/(不能与LIB共用) |
LIB | 编译外部依赖库 include 目录中的 proto,如 CSI 规范 |
JAVA | 额外生成 Java 代码到src/java/generated(org/apache/.../Protos.java) |
GRPC | 额外生成.grpc.pb.h/.grpc.pb.cc,并依赖grpc_cpp_plugin |
其核心命令构造如下(src/cmake/MesosProtobuf.cmake):
set(PROTOC_OPTIONS -I${MESOS_PUBLIC_INCLUDE_DIR} -I${MESOS_SRC_DIR} -I${PROTOBUF_INCLUDE_DIR} --cpp_out=${CPP_OUT})随后通过add_custom_command执行protoc ${PROTOC_OPTIONS} ${PROTO}(src/cmake/MesosProtobuf.cmake)。生成的.pb.cc路径会以副作用形式追加到PUBLIC_PROTOBUF_SRC/INTERNAL_PROTOBUF_SRC列表变量中,供上层add_library引用。
版本化 API 与 evolve/devolve 机制
Mesos 对 API 兼容性的保证同样建立在 protobuf 之上。文档 docs/versioning.md 明确:"The API compatibility is determined by the corresponding protobuf guarantees"——例如,为请求"新增可选字段"被视为向后兼容,而"重命名/删除已有字段"则是破坏性变更。
为此 Mesos 将版本化 API protobuf(include/mesos/v1/...)与内部未版本化 protobuf(include/mesos/...)解耦,并通过 src/internal/evolve.hpp 中的evolve系列转换函数(如v1::AgentID evolve(const SlaveID&)、v1::TaskInfo evolve(const TaskInfo&))以及对应的devolve反向转换,在两者之间来回翻译。这套机制保证了 scheduler / executor 可以按各自的 API 版本与 Mesos 通信,而集群内部始终使用统一的消息格式。
网络传输中的 protobuf:RecordIO 流式协议
protobuf 不仅在内存中承载数据,还承担了线格式职责。Mesos 的 HTTP API 支持以application/x-protobuf编码请求体,而流式响应则采用 RecordIO 格式(每条消息前附加 10 进制字节长度前缀)。相关约定记录在 docs/recordio.md:客户端通过Accept: application/recordio请求流式响应,并用Message-Accept/Message-Content-Type头声明/标识流内每条数据的媒体类型,目前仅支持application/json与application/x-protobuf。scheduler 的/api/v1/scheduler端点即以此协议提供流式事件推送(见 docs/scheduler-http-api.md)。
操作速查
确认当前捆绑版本
# Autotools 侧 grep PROTOBUF_VERSION 3rdparty/versions.am # CMake 侧 grep PROTOBUF_VERSION 3rdparty/cmake/Versions.cmake重新打包捆绑源码(维护者操作)
按3rdparty/protobuf.md的流程执行curl → tar -xzf → ./autogen.sh → tar -czf,产物放入3rdparty/,并在Versions.cmake与versions.am中登记版本与 SHA256。
使用系统 protobuf 构建
./configure --with-protobuf=/usr # 或指定具体前缀路径注意:3+ 版本是硬性要求(google/protobuf/map.h会被探测);若同时使用非捆绑 gRPC,则必须显式给出--with-protobuf=DIR,否则configure报错退出。
CMake 构建中的关键开关
-Dprotobuf_BUILD_TESTS=OFF:默认传入,关闭 protobuf 自带测试;-Dprotobuf_MSVC_STATIC_RUNTIME=OFF:仅 Windows,动态链接 CRT;- 构建产物
protoc作为 imported 可执行目标被PROTOC_GENERATE直接消费,无需额外安装即可完成代码生成。
总结
从3rdparty/protobuf.md的寥寥数行出发,可以看到 Mesos 对 protobuf 的管理远不止"选一个版本打包进来"这么简单:版本与校验和在Versions.cmake/versions.am中统一登记;protobuf-3.5.0.tar.gz对应重新打包产物;两个平台补丁分别解决 MSVC 类型安全与 s390x 原子操作问题;Autotools 通过--with-protobuf[=DIR]提供系统版本切换与严格的版本探测;CMake 通过ExternalProject_Add完成下载、打补丁、编译与 imported 目标导出;最终protoc由PROTOC_GENERATE驱动,为公共 API、内部消息、CSI 规范乃至 gRPC 服务生成代码,支撑起 Mesos 整个集群从状态持久化到 HTTP 流式 API 的全链路通信。
对于想要深入理解或定制 Mesos 构建体系的开发者,本文涉及的 3rdparty/cmake/Versions.cmake、3rdparty/CMakeLists.txt、src/cmake/MesosProtobuf.cmake、configure.ac 与 src/internal/evolve.hpp 是继续探索的最佳起点。
- 云原生
- 集群管理
- 容器编排
- 任务调度
【免费下载链接】mesos
Apache Mesos
相关推荐
Apache Mesos 3rdparty 目录解析:捆绑第三方依赖的管理机制与升级实践
Apache Mesos 3rdparty 目录解析:捆绑第三方依赖的管理机制与升级实践 Apache Mesos 将构建所需的第三方开源组件直接以源码包形式捆
集群管理任务调度后端Apache Mesos 中 gRPC 依赖的打包、补丁与集成实践
Apache Mesos 中 gRPC 依赖的打包、补丁与集成实践 本篇技术指南以仓库中的 3rdparty/grpc.md https://link.gitc
集群管理任务调度后端Apache Mesos 的 gRPC 第三方依赖打包指南:版本选型、补丁维护与构建系统集成
Apache Mesos 的 gRPC 第三方依赖打包指南:版本选型、补丁维护与构建系统集成 本篇技术指南以 Apache Mesos 仓库中 3rdparty
云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考