php环境软件-从php5.6到golang1.19——Library App的性能转型之路

作者|百度文库App

指导

介绍

本文深入浅出地分享了百度文库App服务器技术栈从PHP迁移到Go的实践经验,包括技术选型、基础设施建设、流量迁移的具体解决方案以及核心项目案例的建设实践。

全文6209字,预计阅读时间16分钟。

极客谈话

01

动机

多年来,百度文库App服务器采用PHP作为主要开发语言,高效支撑了业务的迭代开发。 随着平台流量的不断下降,服务器端的负载越来越大,逐渐逼近系统困境。 为了提高系统的负载能力,我们采取了一些优化方法,最快、最有效的方法就是减少在线集群的实例数量。 据悉,lua开发项目也已经用来承接一些逻辑简单、访问量大的socket来分担负载。 由于lua本身的一些限制,不适合复杂的业务逻辑。

随着IT技术的发展,我们积极响应公司降本增效的号召php环境软件,决定在2022年中进行服务器端技术栈的迁移和建设。 致力于升级技术框架,提高系统负载能力。

技术栈迁移和项目建设的时机很难把握,尤其是成熟团队需要进行重大系统变更时。 如果没有真正的痛点,虽然研发同事觉得技术实现上有很多不合理、有风险的设计,但往往不被允许在技术项目上花费大量的时间。 但一旦连业务人员(产品总监、销售、运营)都觉得系统功能需要升级,比如在用户体验方面,App文档搜索界面的延迟比较长,产品朋友觉得如果首屏渲染可以明显加速,点击率和付费率都会大幅提升php环境软件,而且开发端无法再基于旧的技术栈进行优化,非常适合迁移和此时此刻的施工。

恰逢其时,产品朋友提出了一些提高用户体验同时适合项目建设的需求,例如:加速搜索结果页首页渲染、全新App首页、AIGC智能创作等。 这些大量的需求非常有利于迁移和施工工作的启动,并且最大限度地减少了迁移和施工所需的额外人力。 在现有功能上进行迁移和构建,更快、更稳定的socket响应带来流畅的用户体验,有利于推动整体团队okr目标的实现。

回过头来,整理一下当时基于php5.6的服务器的技术主张:

1、底层技术:语言版本老,功能过时,存在执行效率低、安全风险、资源浪费等缺陷;

2、开发质量和效率:业务逻辑交叉耦合、大量废弃的socket和离线的业务逻辑增加了代码的可读性和可维护性,不断降低项目迭代的难度。

环境软件工程_php环境软件_环境软件和硬件的区别是什么

△技术债

极客谈话

02

启动前状态

服务部署方面,Library App的服务器部署方式为nginx+hhvm(HipHopVM3.0.1;baiduversion:1.1.6(rel)),HHVM是Facebook开发的高性能PHP虚拟机,是传统的nginx +php-fpm 的性能优化版本。 近年来,hhvm原班人马的不断维护和迭代,早已荡然无存。 其支持的句型特征和执行效率都比较落后,存在一定的安全风险。

迁移开始时检查服务器实例剂量,具体取决于日常运维。 首先,确保在线服务实例的CPU、内存、C盘使用率在合理阈值内,排除利用率低造成的资源浪费和利用率。 如果速率太低,就会存在容灾风险。 在应用程序层,我们使用了数千个 php5 实例。

极客谈话

03

想象

建设的投资和回报不是线性的。

——《领域驱动设计:软件核心复杂性的解决方案》

直观地说,我们希望服务器端的升级能够带来更少的代码、更稳定的系统、更高的质量效率、更好的用户体验。 这表现在以下几点:

1、技术升级:采用先进的语言框架,支持项目高效迭代,提供强大的底层引擎、安全性和成熟的应用生态;

2、完善设计:梳理代码逻辑,纠正冗余,解决代码中的不良品味,建立高复用、低耦合、可扩展的业务架构;

3、降本增效:一方面,基础升级,提高代码执行效率,减少平坦噪音,提高服务可用性和可观测性; 另一方面,在运维实践中,合理分配容器实例的cpu、显存、c盘配额,优化资源性能。

服务器端升级的成功可以从两个方面来实现,即技术栈的迁移和现有代码设计构建的改进。

极客谈话

04

做好技术选型

我们不会使用相对冷门且生态孤立的语言作为图书馆App服务器的技术栈。 同时,参考兄弟团队技术栈的升级方向,两个厂内框架最终进入了技术选拔世界冠军圈,基于php7的odp3框架(OnlineDevelopPlatform)和基于go的gdp2框架( Go开发平台)。

选项一:PHP7框架和Phaster

PHP7框架是公司发布的在线业务开发平台,提供标准webserver环境、标准php环境、AP框架、基础库、资源访问层、通用服务等组件,统一业务逻辑和部署结构。 该框架的亮点是Phaster。 Phaster允许您使用PHP语言开发高性能的Http、Fastcgi和Nshead服务,进行宽性能的RPC调用,并以极低的成本实现业务代码并行化。

Phaster与其他行业框架的对比如下。

Phaster 可以用作 httpserver 或 fastcgiserver。 与传统的nginx+cgi形式相比,Phaster基于以上能力实现了数倍的性能提升。 具有以下亮点:

1、传统的hhvm或者php-fpm处理请求的逻辑是,在处理每个请求时,首先要初始化php上下文,当请求结束时,清除上下文并回收各种资源。 当phaster启用上下文重用时,可以节省类加载、文件加载、初始化等过程所花费的时间。 举个反例,如果你的socket每次都需要读取一个大文件配置,你可以把读取操作放在初始化文件中。 100个请求内,只执行一次这个读操作就足够了;

2. hhvm或php-fpm不直接支持http合约,常常添加nginx作为http服务器,两者通过fastcgi进行通信。 并且Phaster可以直接作为http服务器启动,减少了一层nginx的处理和转发;

3、协程的支持为IO密集型业务场景提供了高并发基础。 对于阻塞IO,可以加载到polling中,将阻塞变为非阻塞。 在使用同步编程方案的同时,享受异步效果带来的IO性能提升。

值得一提的是,Go 支持这种能力。

选项二:Go 框架

Go语言于2009年由Google发布,近年来随着云计算、微服务、分布式的发展迅速崛起。 它已成为主流编程语言之一。 与Java类似,它是一种静态的强类型语言。 它是一种编译型编程语言,为并发而生,因此天然适合并发编程(网络编程)。

GDP2(GoDevelopPlatform)框架是一个Go开发框架,对厂内基础设施支持良好,扩展性好,易于配置,易于组装,易于测试。 凭借已建立的RPCClient和RPCServer能力,以及配套的通用基础库,可以用来开发API、Web、前端服务等各种应用。 具有以下亮点:

1、厂内基础设施配套良好;

2、可扩展性好,配置组装方便;

3. 易用性好,对测试友好(易于mock,多个testServer、testClient);

4、元件内部状态易于观察;

5、全链路超时&流程控制机制,稳定性好;

6.工厂大规模应用,稳定可靠(基本上都用Go项目,使用的项目有上千个)。

对比两个框架的上述特点以及实施和其他激励措施的可行性,我们更倾向于迁移到GDP框架。

极客谈话

05

建设的关键路径

做出技术选型后,我们将开始下一步。 与常见的Web项目一样,文库App业务迭代速度快、任务重,无法保证常年投入足够的人力进行技术项目。 因此,升级构建技术栈的前提是保证业务需求持续进行,需要有持续解构的意识,往往采用“敏捷迭代”。

5.1 敏捷迭代

第一步是工作量估算。 通过日志聚合分析,可以获取当前App的socket路由有流量(老项目很多socket没有流量,关联需求已经下线)。 实际运行中发现,按照qps值从大到小排序的top50个socket占总流量的99%+,这也决定了socket迁移顺序的优先级。

环境软件和硬件的区别是什么_环境软件工程_php环境软件

第二步是制定策略。 服务器端技术栈向go迁移的实现,本质上表现为将php承担的流量转移到go上。 当所有流量都运行在go实例上,且不依赖php项目底层调用时,即可认为升级完成。 因此,不断扩大Go实例集群在App服务器上总流量的比例是我们迁移的目标。 这大致可以概括为两种形式:

1、根据业务需求,根据socket重要性和流量占比确定优先级,并进行迁移;

2、新需求的代码实现与php项目没有强依赖,直接在go项目中开发。

相当长一段时间,处于php+go混合编程的并存状态。 由于App B/S架构的特点,完成的socket需要通过接入层网段进行转发,并切换服务器接收流量的具体应用层集群(php->go),以保持客户端路径不变,实现老版本App的高可用。 在构建初期采用混合编程的思想,可能会出现一些特殊的需求,例如:同一段业务逻辑需要用go编写,又需要用php编写,这无疑会减少一定的工作量工作量。 其实,这也是不可避免的。 。

建造时要避免一个误解:大瀑布模型,它是一次性建造整个项目的。 从时间、人力成本和稳定性来看,这些方法风险都比较大,不推荐。 整体来看,socket精细度是批量打造的,这样无论是内部的技术迭代,还是外部的业务影响,都有显着的感知。 更适合作为实现流量迁移的一种形式。

5.2 支持golang的基本构建

它与PHP项目的工作流程有以下几点不同。

1、脚手架:go除了定义路由、逻辑分层、生成配置等框架属性外,还需要额外封装轮询,为开发朋友提供开箱即用的脚手架。

2. Publish:封装构建逻辑,实现包编译和环境变量管理。

3、部署:覆盖整个二补代码文件,需要重启服务。 使用热重启模块可以实现无损上线,上线速度更快。

4、流量:基于CS的App的socket迁移需要接入层重绘路由,协调网段变化。

5、监控:日志分级,微服务间透传痕迹,各种日志按照Agent收集的格式规范入盘。

5.3 写入第一个套接字

一方面,在开始技术栈的迁移时,需要了解Go语言支持并发,可以轻松开发强类型语言的异步程序。 Go 是一种强类型静态语言。 类型是在编译时确定的。 它不像PHP那么灵活,而且更严谨、更安全。 它可以在编译阶段检测出大部分隐藏的问题。

△类型转换

另一方面,构建项目如何清理过时的代码? 简而言之,你可以参考《重构——改进现有代码的设计》一书中提出的23种代码坏品味,有针对性地构建代码,将其驯服为干净易读的代码。

一旦确定了预检查和迁移策略,实际的代码开发就显得得心应手了。 当从旧套接字迁移流量时,我们需要在新套接字上使用 go 重新实现它。 调用方式与旧的socket完全相同,包括路径、方法、签名验证、头规则、参数结构、响应结构、错误码。 只是应用层的虚拟域名不同。

5.4 质量保证

代码已经准备好了。 与PHP项目的常规测试流程不同,Go无法绕过性能测试。 因为我们写PHP的时候几乎不需要关注GC和内存窃取,而Go则需要,所以有时候自动测试、黑盒测试就可以了,而当线上遇到某些并发业务场景时,问题就会暴露出来,往往表现为实例cpu或显存利用率持续下降直至崩溃。

解决go的内存窃取问题。 一方面,需要减少测试过程中的压测环节; 另一方面,需要更加关注监控仪表板的实例资源使用率、界面声级、稳定性指标是否达到预期,因为一些隐藏的Bug是压测无法覆盖的。 这个时候就需要提高Go服务的可观测性,方便及时发现风险。

Go质量保证能力全景矩阵如下:

建立线下质量保证能力:

建立在线质量保证能力:

5.5 流量迁移

如上图所示,go项目上线后,实际流量仍然由老项目承担。 开始流量迁移。 用户流量首先到达接入层。 在这一层,我们根据不同的访问域名和路由,将其分流到不同的应用层负载均衡器。 完成流量迁移。 在接入层的网段上进行流量分流,并将分流到PHP的规则应用到Go应用层的负载均衡器上,完成流量迁移。 注意,如果是非常核心的socket,我们需要灰度发布,可以采用nginx+lua的形式来实现,或者知名的开源网段ApiSix、BFE项目,它们都支持灰度发布。

5.6 核心功能建设实践

本次建设比较突出的亮点是百度文库App新版首页和搜索结果页的优化。