同辕开发实战:从两套流水线到一码多芯的10个坑与全流程落地指南
【同辕开发实战】从两套流水线到一码多芯:我踩过的 10 个坑与全流程落地指南
大家好,我是做后端服务开发的,去年下半年开始公司业务全面迁移到鲲鹏平台。一开始我们走了最笨的路子:x86 一套代码分支,鲲鹏一套分支,两条独立的 CI/CD 流水线,每次改 bug、发版本都要搞两次,经常漏改合并,线上出过好几次问题,运维和开发都怨声载道。
直到去年年底接触了鲲鹏的「一码多芯、同辕开发」模式,前前后后折腾了两个多月,踩了无数坑,终于把我们核心的 12 个服务全部改成了同辕开发模式 —— 现在一套代码,一条流水线,同时出 x86 和鲲鹏两个版本的包,发版一次搞定,再也不用维护两套分支了,真的香。今天把我踩过的坑、全流程实操步骤整理出来,给正在做鲲鹏适配的兄弟们避避坑。
一、先搞懂:同辕开发到底解决了什么痛点
很多人刚接触同辕开发的时候,会觉得是个花架子,不就是跨架构编译吗?其实真不是,传统的多架构开发模式有三个致命的问题:
- 代码维护成本翻倍:两套分支,改一个功能要合并两次,很容易漏改,我们之前出过一次支付接口的 bug,x86 那边改了,鲲鹏那边忘了合并,线上跑了三天才发现
- 资源浪费:要搭两套构建环境,两套流水线,x86 一台构建机,鲲鹏一台构建机,成本高,维护麻烦
- 版本不一致:很容易出现 x86 和鲲鹏版本功能不一致的情况,测试要测两遍,工作量翻倍
而同辕开发的核心就是:基于 openEuler + 鲲鹏 DevKit + BoostKit,一套代码 + 一条流水线,同时构建出 x86 和鲲鹏两个平台的发布包,全程不用改代码。
说白了就是,你写代码的时候不用管是 x86 还是鲲鹏,写完提交,流水线自动给你出两个版本的包,直接部署就行,这才是真的解放生产力。
二、同辕开发全流程实操(我跑通的完整步骤)
2.1 环境准备(版本一定要按这个来,别用最新版!)
这是我踩的第一个大坑,一开始图新鲜装了最新版的毕昇编译器和 DevKit,结果各种编译报错,查了三天才发现是版本不兼容。官方推荐的稳定版本组合,我亲测没问题:
安装命令我整理好了,直接复制就行:
验证安装是否成功:
2.2 代码适配(90% 的项目不用改代码,只需要改构建脚本)
大部分 Java、Go、Python 项目基本不用改业务代码,只需要改构建脚本,加上跨架构编译的参数就行。我以最常用的 C++ 和 Java 项目为例:
C++ 项目 CMakeLists.txt 修改
只需要加几行架构判断,自动选择对应的编译器和优化参数:
Java 项目 pom.xml 修改
Java 项目更简单,基本不用改,只需要在打包的时候指定平台,用鲲鹏提供的 JDK 就行:
2.3 流水线接入(Jenkins 一小时搞定)
DevKit 提供了现成的 Jenkins 插件,不用自己写复杂的脚本。我是这么接的:
- 在 Jenkins 插件市场安装「Kunpeng DevKit Plugin」
- 新建一条流水线,同时添加 x86 和鲲鹏两个构建节点
- 构建阶段加一步「DevKit 跨架构构建」,选择对应的构建目标
- 构建完成后,自动上传两个版本的包到镜像仓库
我们现在的流水线跑一次大概 15 分钟,同时出两个平台的镜像,直接部署,非常方便。
三、我踩过的 10 个大坑 + 解决方案(都是血泪教训)
这部分是最核心的,每个坑我都踩过,有的查了好几天,大家直接抄解决方案就行。
1. 毕昇编译器版本不对,编译出来的包段错误
问题:装了最新的 3.1.0 版本毕昇编译器,编译 C++ 项目没问题,一运行就段错误,gdb 也查不出问题 解决方案:直接降级到 2.3.0 稳定版,亲测所有项目都能正常编译运行,官方文档里明确写了推荐 2.3.0,我当时没仔细看,踩了大坑。
2. 跨架构编译的时候,第三方依赖 so 库找不到
问题:构建的时候提示error while loading shared libraries: libxxx.so: cannot open shared object file 解决方案:不要用系统默认的 yum 源,用鲲鹏官方的源,大部分依赖都有 aarch64 版本:
实在找不到的依赖,用 DevKit 的依赖迁移工具,自动转成 aarch64 版本,别自己编译,太费时间。
3. NUMA 配置不对,性能比 x86 慢 30%
问题:服务迁到鲲鹏之后,压测 QPS 比 x86 低 30%,CPU 利用率只有 50% 解决方案:鲲鹏是 NUMA 架构,一定要绑定 CPU 核心,不要跨 NUMA 节点调度,我们用 numactl 绑定之后,QPS 直接涨了 40%:
4. 透明大页没关,Redis / 数据库偶尔卡顿
问题:Redis 偶尔会出现几百毫秒的卡顿,查了很久没找到原因 解决方案:鲲鹏平台一定要关闭透明大页,对内存密集型应用提升非常大:
我们关了之后,Redis 的平均响应时间从 8ms 降到了 2ms,再也没出现过卡顿。
5. ARM 弱内存模型导致的无锁队列偶发崩溃
问题:x86 上跑的好好的无锁队列,迁到鲲鹏上偶尔会出现崩溃,概率大概万分之一 解决方案:ARM 是弱内存模型,指令会重排序,无锁代码里要加内存屏障:
这个问题我查了整整两天,头发都掉了一把,大家写无锁代码一定要注意。
6. 向量化没开,C 程序性能暴跌 40%
问题:C 写的计算程序,在鲲鹏上跑比 x86 慢 40% 解决方案:毕昇编译器默认不会开最高级别的向量化,要手动加参数:
加了之后,我们的计算程序性能直接反超 x86,比原来快了 15%。
7. Jenkins 流水线接入的时候,权限不足报错
问题:流水线跑构建的时候,提示权限不足,无法访问 DevKit 工具 解决方案:给 Jenkins 用户加 DevKit 的执行权限:
别给 Jenkins 单独建用户,直接用 root 跑构建,省很多事。
8. 没装 jemalloc,Java 应用内存泄漏
问题:Java 应用跑几天,内存就会涨到 80% 以上,jstack 查不到泄漏 解决方案:鲲鹏平台 Java 应用一定要装 jemalloc,替换默认的内存分配器:
装了之后,内存占用稳定在 40% 左右,再也没出现过泄漏的问题。
9. 大页内存配置不对,MySQL 性能上不去
问题:MySQL 压测 TPS 只有 2000,远低于预期 解决方案:配置 1G 大页内存,MySQL 性能直接翻倍:
我们配置完之后,MySQL TPS 从 2000 涨到了 4500,提升了 125%。
10. 代码里有 x86 专属的汇编指令,编译失败
问题:老代码里有 x86 的 AVX2 汇编指令,鲲鹏上编译失败 解决方案:用宏判断架构,不同架构用不同的实现:
DevKit 有个迁移扫描工具,能自动扫出代码里的 x86 专属指令,跑一下就全出来了,不用自己找。
四、性能调优:我们的服务 QPS 从 1200 到 2100 的实战技巧
我们的核心 Java 服务,刚迁到鲲鹏的时候,压测 QPS 只有 1200,比 x86 的 1500 还低,经过一周的调优,最后做到了 2100 QPS,比 x86 还快 40%,核心就是这几个操作:
- 必装 jemalloc,替换默认内存分配器,内存占用降 30%,性能升 20%
- 关闭透明大页,所有服务都要关,尤其是数据库和缓存
- NUMA 绑定,所有服务都绑定到同一个 NUMA 节点,不要跨节点
- 用毕昇 JDK,不要用 OpenJDK,毕昇 JDK 对鲲鹏有专门优化,性能升 15%
- 开启 KAE 加速引擎,加密解密、压缩解压这些操作,用硬件加速,性能升 30%
- 调整 TCP 参数,openEuler 默认的 TCP 参数不适合高并发,改成高并发配置
给大家一个我整理的通用优化脚本,直接跑就行:
五、给新手的几点建议
- 严格按官方推荐的版本来,不要用最新的开发版,稳定大于一切,我已经踩过无数版本的坑了
- 遇到问题先去鲲鹏社区搜,90% 的问题都有现成的解决方案,不要自己瞎折腾,很多问题官方早就踩过了
- 不要上来就全量迁,先拿一个非核心服务跑通全流程,踩完坑再迁核心服务,我们一开始就是直接迁核心服务,出了很多问题
- 一定要做压测,迁完之后一定要压测,很多问题只有高并发下才会出现,不要直接上线
- 多和社区的人交流,鲲鹏社区的官方技术人员响应很快,我好几次遇到解决不了的问题,发帖当天就有官方的人联系我帮忙解决
最后说两句
说实话,同辕开发刚开始搭的时候确实麻烦,要踩很多坑,但是搭好之后真的太香了。我们现在 12 个服务,全部都是同辕开发,一套代码,一条流水线,发版一次搞定,开发和运维的工作量都减了一半。
国产化的路确实不好走,会遇到各种各样的问题,但是只要慢慢踩坑,慢慢优化,最后会发现鲲鹏的性能真的不比 x86 差,甚至很多场景下还要更好。
如果大家在同辕开发的过程中遇到什么问题,欢迎在评论区留言,我看到都会回复,大家一起交流,少踩坑。
同辕开发实战:从两套流水线到一码多芯的10个坑与全流程落地指南
【同辕开发实战】从两套流水线到一码多芯:我踩过的 10 个坑与全流程落地指南
大家好,我是做后端服务开发的,去年下半年开始公司业务全面迁移到鲲鹏平台。一开始我们走了最笨的路子:x86 一套代码分支,鲲鹏一套分支,两条独立的 CI/CD 流水线,每次改 bug、发版本都要搞两次,经常漏改合并,线上出过好几次问题,运维和开发都怨声载道。
直到去年年底接触了鲲鹏的「一码多芯、同辕开发」模式,前前后后折腾了两个多月,踩了无数坑,终于把我们核心的 12 个服务全部改成了同辕开发模式 —— 现在一套代码,一条流水线,同时出 x86 和鲲鹏两个版本的包,发版一次搞定,再也不用维护两套分支了,真的香。今天把我踩过的坑、全流程实操步骤整理出来,给正在做鲲鹏适配的兄弟们避避坑。
一、先搞懂:同辕开发到底解决了什么痛点
很多人刚接触同辕开发的时候,会觉得是个花架子,不就是跨架构编译吗?其实真不是,传统的多架构开发模式有三个致命的问题:
而同辕开发的核心就是:基于 openEuler + 鲲鹏 DevKit + BoostKit,一套代码 + 一条流水线,同时构建出 x86 和鲲鹏两个平台的发布包,全程不用改代码。
说白了就是,你写代码的时候不用管是 x86 还是鲲鹏,写完提交,流水线自动给你出两个版本的包,直接部署就行,这才是真的解放生产力。
二、同辕开发全流程实操(我跑通的完整步骤)
2.1 环境准备(版本一定要按这个来,别用最新版!)
这是我踩的第一个大坑,一开始图新鲜装了最新版的毕昇编译器和 DevKit,结果各种编译报错,查了三天才发现是版本不兼容。官方推荐的稳定版本组合,我亲测没问题:
安装命令我整理好了,直接复制就行:
验证安装是否成功:
2.2 代码适配(90% 的项目不用改代码,只需要改构建脚本)
大部分 Java、Go、Python 项目基本不用改业务代码,只需要改构建脚本,加上跨架构编译的参数就行。我以最常用的 C++ 和 Java 项目为例:
C++ 项目 CMakeLists.txt 修改
只需要加几行架构判断,自动选择对应的编译器和优化参数:
# 架构判断 if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") # 鲲鹏架构:用毕昇编译器,开启SVE2向量化 set(CMAKE_C_COMPILER "/opt/bisheng-compiler-2.3.0/bin/clang") set(CMAKE_CXX_COMPILER "/opt/bisheng-compiler-2.3.0/bin/clang++") add_compile_options(-march=armv8-a+sve2 -O3 -fvectorize) else() # x86架构:用GCC,开启AVX2优化 set(CMAKE_C_COMPILER "gcc") set(CMAKE_CXX_COMPILER "g++") add_compile_options(-march=haswell -O3 -mavx2) endif()Java 项目 pom.xml 修改
Java 项目更简单,基本不用改,只需要在打包的时候指定平台,用鲲鹏提供的 JDK 就行:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>11</source> <target>11</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>2.3 流水线接入(Jenkins 一小时搞定)
DevKit 提供了现成的 Jenkins 插件,不用自己写复杂的脚本。我是这么接的:
我们现在的流水线跑一次大概 15 分钟,同时出两个平台的镜像,直接部署,非常方便。
三、我踩过的 10 个大坑 + 解决方案(都是血泪教训)
这部分是最核心的,每个坑我都踩过,有的查了好几天,大家直接抄解决方案就行。
1. 毕昇编译器版本不对,编译出来的包段错误
问题:装了最新的 3.1.0 版本毕昇编译器,编译 C++ 项目没问题,一运行就段错误,gdb 也查不出问题 解决方案:直接降级到 2.3.0 稳定版,亲测所有项目都能正常编译运行,官方文档里明确写了推荐 2.3.0,我当时没仔细看,踩了大坑。
2. 跨架构编译的时候,第三方依赖 so 库找不到
问题:构建的时候提示
error while loading shared libraries: libxxx.so: cannot open shared object file解决方案:不要用系统默认的 yum 源,用鲲鹏官方的源,大部分依赖都有 aarch64 版本:实在找不到的依赖,用 DevKit 的依赖迁移工具,自动转成 aarch64 版本,别自己编译,太费时间。
3. NUMA 配置不对,性能比 x86 慢 30%
问题:服务迁到鲲鹏之后,压测 QPS 比 x86 低 30%,CPU 利用率只有 50% 解决方案:鲲鹏是 NUMA 架构,一定要绑定 CPU 核心,不要跨 NUMA 节点调度,我们用 numactl 绑定之后,QPS 直接涨了 40%:
4. 透明大页没关,Redis / 数据库偶尔卡顿
问题:Redis 偶尔会出现几百毫秒的卡顿,查了很久没找到原因 解决方案:鲲鹏平台一定要关闭透明大页,对内存密集型应用提升非常大:
我们关了之后,Redis 的平均响应时间从 8ms 降到了 2ms,再也没出现过卡顿。
5. ARM 弱内存模型导致的无锁队列偶发崩溃
问题:x86 上跑的好好的无锁队列,迁到鲲鹏上偶尔会出现崩溃,概率大概万分之一 解决方案:ARM 是弱内存模型,指令会重排序,无锁代码里要加内存屏障:
这个问题我查了整整两天,头发都掉了一把,大家写无锁代码一定要注意。
6. 向量化没开,C 程序性能暴跌 40%
问题:C 写的计算程序,在鲲鹏上跑比 x86 慢 40% 解决方案:毕昇编译器默认不会开最高级别的向量化,要手动加参数:
加了之后,我们的计算程序性能直接反超 x86,比原来快了 15%。
7. Jenkins 流水线接入的时候,权限不足报错
问题:流水线跑构建的时候,提示权限不足,无法访问 DevKit 工具 解决方案:给 Jenkins 用户加 DevKit 的执行权限:
别给 Jenkins 单独建用户,直接用 root 跑构建,省很多事。
8. 没装 jemalloc,Java 应用内存泄漏
问题:Java 应用跑几天,内存就会涨到 80% 以上,jstack 查不到泄漏 解决方案:鲲鹏平台 Java 应用一定要装 jemalloc,替换默认的内存分配器:
装了之后,内存占用稳定在 40% 左右,再也没出现过泄漏的问题。
9. 大页内存配置不对,MySQL 性能上不去
问题:MySQL 压测 TPS 只有 2000,远低于预期 解决方案:配置 1G 大页内存,MySQL 性能直接翻倍:
我们配置完之后,MySQL TPS 从 2000 涨到了 4500,提升了 125%。
10. 代码里有 x86 专属的汇编指令,编译失败
问题:老代码里有 x86 的 AVX2 汇编指令,鲲鹏上编译失败 解决方案:用宏判断架构,不同架构用不同的实现:
DevKit 有个迁移扫描工具,能自动扫出代码里的 x86 专属指令,跑一下就全出来了,不用自己找。
四、性能调优:我们的服务 QPS 从 1200 到 2100 的实战技巧
我们的核心 Java 服务,刚迁到鲲鹏的时候,压测 QPS 只有 1200,比 x86 的 1500 还低,经过一周的调优,最后做到了 2100 QPS,比 x86 还快 40%,核心就是这几个操作:
给大家一个我整理的通用优化脚本,直接跑就行:
五、给新手的几点建议
最后说两句
说实话,同辕开发刚开始搭的时候确实麻烦,要踩很多坑,但是搭好之后真的太香了。我们现在 12 个服务,全部都是同辕开发,一套代码,一条流水线,发版一次搞定,开发和运维的工作量都减了一半。
国产化的路确实不好走,会遇到各种各样的问题,但是只要慢慢踩坑,慢慢优化,最后会发现鲲鹏的性能真的不比 x86 差,甚至很多场景下还要更好。
如果大家在同辕开发的过程中遇到什么问题,欢迎在评论区留言,我看到都会回复,大家一起交流,少踩坑。