从计算机网络形成至今,其面对企业、行业、社会的种种不同需求,核心内容早已与最初的样子大相径庭。而在近年来,计算机的革新依然在继续,尤其是在数字化和智能化发展浪潮推动下,太多的业务架构由于不堪重负走上变革之路。这世上没有绝对最佳的架构,也没有任何企业能够从一开始就划定好自己未来的目标。也正因为这些元素的存在,迁移和调优这两个核心任务从未在产业中从未停下过脚步。
7 月 11 日,华为启动全国 18 城鲲鹏创新中心开发者创享日系列沙龙活动,其关注的核心要素便正是应用代码迁移与性能调优。天津鲲鹏创新中心作为线下活动的主办场地之一,也吸引到了诸多开发者的热情参与。在天津站的活动中,不仅有华为鲲鹏计算专家对于软件代码迁移时可能遇到的问题和迁移策略进行了全面讲解,同时针对迁移后的性能调优以及可能涉及到的开发工具提供了实战经验。而为了让现场开发者更好的消化讲述内容,沙龙还设置了实操演练环节,由技术专家全程指导参与者进行鲲鹏调优实践的线上实验。
迁移如搬山,按部当就班
万物感知、万物互联、万物智能,这是智能世界的三大特征,而连接与计算则是智能的两大基础。华为便围绕鲲鹏和昇腾开启构建开放的产业生态,以行业聚集应用,以区域整合产业,以联盟孵化标准,以社区培养开发者。华为沃土计划投入 15 亿美金扩大开发者规模,使能全球软件合作伙伴发展应约及解决方案。
此次举办活动的天津鲲鹏生态创新中心,便承担了其中的五项工作:
发展软件生态。通过政策扶持和资金补贴,牵引行业解决方案迁移到鲲鹏生态上,并在优势行业建立应用示范树立标杆。
人才培养。通过与区域高效科研院所培训机构合作,培养鲲鹏产业人才,吸收行业领军人物加入。
孵化标准。通过与产业联盟、标准组织合作制定当地计算产业标准,规范行业生态,加速产业发展。
扩大产业空间。聚合区域内外生态伙伴,共同构建行业解决方案竞争力,形成多方共赢利益方向机制。
构建产业联盟。天津鲲鹏计算产业联盟正在不断聚拢天津优秀产业伙伴加入,共同推动产业发展。
产业联盟的构建并不容易,尤其是在当前的数字化时代里,业务和数据的多样性对计算架构和算力都提出了新的需求。而为了解决智能世界的算力需求,使能各个行业,加速数字化转型,将已有软件从 x86 平台迁移到鲲鹏计算平台成为很多企业的选择。
但是迁移的过程却并不简单。众所周知,软件要运行在硬件上面,必须要先让硬件能够识别指令集。但是在 x86 平台和鲲鹏计算平台上,同样的代码却会产生完全不同的效果。原因在于:
x86 平台从内存取值到寄存器用的是 MOV 指令,相加用的是 ABB 指令,再写回寄存器还是用的 MOV 指令;而鲲鹏取值则用的是 LDR 指令,写回是 STR 指令,汇编指令全然不同。
两个平台的指令长度也不一样,x86 指令包括了 24 位或者 16 位的不定长指令,鲲鹏则采用的是 32 位定长指令。
汇编指令涉及到寄存器的部分命名不一样,在 x86 上的 EDX 和 EAX 的部分,在鲲鹏上是 X1 或者 X0。
这三点不同,决定了在两大架构上程序编译出来的汇编也不一样,这就是为什么需要进行迁移的原因所在。
鲲鹏迁移五步走
迁移的过程主要可以分为 5 步,迁移准备、迁移分析、编译迁移、性能调优以及测试与认证。
迁移准备的过程首先便是需要进行软硬件信息的收集,其中包括了用来进行 x86 服务器匹配硬件信息;以及操作系统、虚拟机、中间件、编译器、上层依赖的开源软件、商业软件、业务软件等软件栈信息。
迁移分析需要对收集到的信息和软件栈做初步分析,评估迁移工作量。自研软件需要注意语言类型差异,编译型语言需要重新编译之后才能运行在新环境上,解释型语言来则只需要更好虚拟机;开源软件可以直接使用下载在 ARM 上已经被编译好的安装包即可,不支持的话可以自行下载原码编译;对于商用软件,可以通过联系厂商获取它对应 ARM 架构下软件版本,如果没有则可以寻找类似开源软件替换。
编译迁移过程分成两类,自研软件相关迁移和软件包迁。解释性语言开发的应用代码不需要迁移,而像 C/C++ 这种编译性语言需要重新进行编译。对软件包迁移来说,先要扫描该软件包是否存在依赖库或者依赖的可执行程序,同样 C 语言写的是需要重新编译的,编译之后重新把软件包打包即可。迁移完成后可以对整体功能进行验收,这样便算完成迁移了。
性能调优时,首先要建立一个标准,针对当前组网环境和逻辑架构设计新的目标;然后对软件进行压力测试,同时要记住变化,分析压力测试下各种数据指标,对单一指标进行优化;然后继续压力测试,检验优化是否达到效果,并固化或回退,循环该过程从而实现调优。
测试与认证注意包括了功能方面、性能方面和长稳以及安全类内容,保障软件能够达到商用水准后,即可规模上线。此外也可以拿软件和系统到鲲鹏上做鲲鹏展翅认证,扩展应用的软件使用空间并加入鲲鹏生态。
不同语言下的迁移工程
从上面不难看出,C/C++编译型语言是一个比较麻烦的点,其需要先编译成汇编,再编译成二进制文件。编译构建流程大体如下,在获取源代码之后,选择所需的编译环境,安装编译器 gcc 等;根据源码的编译脚本生成 Makefile 文件,再用 Makefile 编译生成可持续文件;担任如果代码之中有依赖 x86 平台的 SO 库,那么这部分的依赖库是需要重新编译替换的;在编译完成之后进行安装部署,之后进入到实际的系统之中进行测试。
在这一过程中需要注意的有很多,比如 x86 下 -m64 代码的主要功能是将应用程序编译为 64 位,对应到鲲鹏上是用 -mabi=lp64 的编译选项,其需要在脚本中修改;gcc 编译器所自带的 x86 编译选项就是 x86_64,对应到鲲鹏平台上是 aarch64,对编译宏下的代码需要机箱内对应的移植;Builtin 函数是编译器自带的函数,需要移植的普通 builtin 函数并不多,大部分需移植的 builtin 函数集中在 SSE intrinsic 函数内;SSE Intrinsic 函数,涉及到向量化预算加速技术,如果有开源工程可以直接应用。
Python 跟 C 语言关系密切,一些组件为了效率会用 C 语言实现,也会引用到 Python 里面去。其需要从编译环境和 SO 库两方面入手修改。环境上推荐使用 python3,可以通过脚本安装;SO 库有多种类型,但对于各种方式的 SO 库,最后都是对应为一个 SO,定义为 SO 库,需要的步骤大体包括了装配环境、重新编译、重新替换等。
JAVA 跟 Python 大体一样,首先需要安装运行环境 JDK,Java 源码通过 Java 编译器之后就会生成一个 Java 的字节码,这时候可能 jar 包会有一些 SO 库的依赖,需要链接进行打包。
Maven 软件仓库则可用来管理 Java 项目。Maven 可以把所有的开源软件编辑成一个 jar 包放在 Maven 仓库上面,需要时直接在 Maven 上调用,被称为.jar 的依赖管理,其可以分为分本地仓库、远程仓库和中央仓库。鲲鹏 Maven 仓实质就是一个远程仓,里有各种各样适用于鲲鹏平台的 jar 包。当用户在在本地仓没有找到合适的 jar 包时,就到鲲鹏的远程仓找,下载出来就是在鲲鹏平台可以使用的 jar 包,无需重复校验、编译,提升开发效率。
软件包迁移其实应该被叫做软件包重构,第一阶段扫描软件包,看编译型语言编译出来的二进制文件,对二进制文件进行重新编译,把重新编译的二进制文件,不管 SO 库还是包含 SO 库的 Jar 包,重新打到 RPM 包里面,安装上进行验证,这就可以完成手动重构。用户也可以使用利用 Dependency Advisor 工具进行扫描,可以对 RPM 包进行重构,成为鲲鹏上可以使用的软件包。
迁移之后的鲲鹏性能调优
鲲鹏软件性能调优,本质上就是五步骤当中性能调优,但由于性能调优是细活,所以被单独拿出来作为独立课程讲解。
冯·诺依曼架构用了几十年从未变过,多年的使用可以总结出四个调优方向,控制器和运算器合起来 CPU,其和内存可以一起优化;外存储器磁盘;输入输出设备中的典型网卡;运行在架构上面应用程序,这边是优化的四个主要方向。
CPU 和内存优化
CPU 和内存的优化主要可以分为硬件优化和软件优化。
硬件优化相当于内置加速卡,鲲鹏处理器便提供了这种加速。硬件优化又可以分为硬加速和软加速,硬加速在加解密、解压缩、大数据运算和 EC 上进行了优化,软加速又分成单核加速和多核加速,单核在编译方面进行了优化,多核则主要是在 NUMA-Aware 亲和性优化。
软件优化主要集中在编译层面,优化主要涉及四个方面:指令流水布局的优化、内存布局的优化、循环优化、除法优化。JDK 的优化则没有太大突破,主要是采用了 JIT 编译优化、GC 内存回收管理优化提升内存,在 JVM 循环方面采用向量化、序列化技术,提升程序执行性能。
2006 年多核是爆发式增长的一年,第一种架构叫 SMP 对称多处理器架构,每一个核访问每一个内存,距离相等,不过这样的话,随着核数的增加访问内存的整线就变成了瓶颈。而非统一内存访问架构(Non-uniform memory access,NUMA 架构)便很好的解决了这一问题。
不过,NUMA 架构也有自己的问题,因为内存在物理上是分布式的,不同的核访问不同内存的时间不同。因此想要发挥 NUMA 性能,就需要克服内存访问速度不均匀带来的挑战;通过 NUMA-Aware 亲和性资源规划,利用 CPU 亲和性与内存分配策略,能够让内存访问找到最短路径,让进程与内存的距离更短。
磁盘优化
磁盘是存储程序主要的地方,大量程序存在磁盘里,每一次调用都会在磁盘里找数据,但是磁盘速度、内存速度和缓冲速度各不相同,这就会造成性能上损耗。
那么磁盘是如何工作的呢?磁盘有一个磁盘缓冲区,读取调用时会先读到磁盘缓冲区,再读到操作系统和文件系统,最后到内存,关键路径就在文件系统中,因此不论哪种类型的文件系统,都有这三种优化方向:文件预读,脏数据刷新,IO 调度算法和选择。CFQ,DeaDLine、NOOP 等适合固态硬盘的场景都有三种数据刷新,如果磁盘预取可以充分利用磁盘带宽,因为使用过的数据可以很快会被使用,使用过的数据相邻的数据也可以很快被使用。
网卡优化
在收到网络请求时,其会带来一个包由网卡告知 CPU,由 CPU 处理,如不能处理完再返回,便会告知网卡驱动,然后产生一个硬中断,后面的数据由网卡来处理,网卡驱动把软中断放在中断队列里,等到中断队列到软中断以后,会把包拷贝到程序 Socket 里面去,等到程序运行后 CPU 再处理这个包,这是包处理的过程。
该过程中不难发现,一二两步有性能方面的大影响,这个片断会占用大量 CPU 时间线,产生性能损耗。因此可以通过调整网卡中断聚合,在低时延和高吞吐取平衡点,可以设置此时中断处理一次,或者设置每 200 毫秒之后处理一次,找到低延时和高吞吐的平衡点。如果系统程序要求非常高的时延,必须快速响应,这两个值设置小一点;如果对于时延没有那么高,保证吞吐量大一点,把两个值设置高一点,数值的高低取决于具体业务场景。
应用优化
鲲鹏平台的优势在于核数比较多,处理并发量比较高的程序有天然优势。因此,可以让程序运行速度得到质的提升。不过,鲲鹏多核架构虽然善于处理多并发,但并发其实并不容易处理好。并发多了之后,有些公共数据要加锁,数据不可预测,加锁之后多个线程抢占一个锁,就容易出现性能损耗。此时便可以针对这种情况进行代码优化,实现无锁编程,或者把大锁编程小锁,实现高性能原子操作,不会触发上述情况,这三类处理方式均可实现性能提升。
总结下来,在性能调优的四个方面还有其他的一些小技巧,比如 CPU 和内存优化时,可以通过调整内存页大小,CPU 预取,修改线程调度策略实现提升;磁盘优化方面,脏数据刷新、异步文件操作(libaio)以及文件系统参数调整都可以有一些效果;网卡可以利用网卡多队列、开启网卡 TSO、开启网卡 CSUM 实现优化;应用层面则能够利用优化编译选项、文件缓存机制、缓存执行结果、NEON 指令加速等让系统运行更加流畅。
鲲鹏展翅·智耀津门
对于开发大神而言,仅仅有以上的一些教程,却没有一个可以实践操作的舞台想必是最为苦恼的事情了。而为了加快鲲鹏行业解决方案孵化,也为了给各路豪侠提供一个展现自我的舞台,华为联合各地鲲鹏创新中心面向开发者举办了鲲鹏应用创新大赛。
作为一个全国性的开发大赛,鲲鹏应用创新大赛在全国开设了 13 个区域赛,可谓含金量满满。天津赛区的奖项激励达到了 34 万,提供了金融、政府以及开放命题等 5 个赛题 11 个奖项,只要你能够基于鲲鹏计算技术构建功能完备、商业前景广、创新易用的产品解决方案,便有机会赢取这笔丰厚的奖金。
本场比赛报名已经开始,并将于 8 月 7 日截止报名,如果你想要与各位大神同台竞技,感受鲲鹏的别样魅力,那么便点击链接报名参赛吧!
https://competition.huaweicloud.com/information/1000041268/introduction?track=110
评论