经典的PHP应用程序是单线程的,繁重的负载(当然,除非您在微框架上编写),而且每次请求后都会不可避免地终止进程……这样的应用程序既繁琐又缓慢,但是我们可以通过杂交使它重获新生。 为了加快速度-我们演示并优化内存泄漏以实现更好的性能-我们将引入自己的Golang RoadRunner PHP应用程序服务器以增加灵活性-简化PHP代码,扩展堆栈并在服务器和应用程序之间分担责任。 本质上,我们将使我们的应用程序像使用Java或其他语言编写应用程序一样工作。
多亏了杂交,以前缓慢的应用程序停止了在负载下出现502错误的情况,平均请求时间缩短了,生产率提高了,并且由于应用程序的统一以及以nginx + php-fpm的形式消除了不必要的绑定,部署和组装变得更加容易。
Anton Titov (
Lachezis )是SpiralScout LLC的首席技术官和联合创始人,在PHP方面拥有12年的活跃商业开发经验。 在过去的几年中,他一直在公司的开发堆栈中积极实施Golang。 安东(Anton)在
2019年俄罗斯PHP大会上谈到了一个例子。
PHP应用程序生命周期
在示意图上,具有特定框架的抽象应用程序设备看起来像这样。

当我们向流程发送请求时,它发生了:
- 项目初始化;
- 加载共享库,框架和ORM;
- 加载特定项目所需的库;
- 路由;
- 将请求路由到特定控制器;
- 响应生成。
这是具有单个入口点的经典
单线程应用程序的操作原理,在每次执行后,该入口点将完全销毁或清除其状态。 所有代码均从内存中卸载,工作程序被清除或仅重置其状态。
延迟加载
加快速度的标准且简便的方法是
延迟加载系统或按需加载库的实现。

对于延迟加载,我们仅请求必需的代码。
访问特定控制器时,仅将必要的库加载到内存中,进行处理,然后再卸载。 这使您可以
减少项目的平均响应时间,并极大地简化了服务器上的工作过程。 在我们当前使用的所有框架中,都实现了延迟加载的原理。
缓存频繁的计算
该方法更加复杂并且在例如Symfony框架,模板引擎,ORM方案和路由中得到积极使用。 这不像memcached或Redis这样的用户数据缓存。 该系统会
预先预热部分代码 。 在第一个请求时,系统会生成代码或缓存文件,而在随后的请求中,将不再执行例如编译模板所需的这些计算。

缓存显着
加快了应用程序的速度 ,但同时又
使其复杂化 。 例如,在使缓存无效和更新应用程序方面存在问题。 不要将用户缓存与应用程序缓存混淆-一种是数据随时间变化,另一种是仅在更新代码后才发生变化。
要求处理
从外部PHP-FPM服务器收到请求时,请求入口点和初始化将匹配。
事实证明,客户的请求就是我们流程的状态。
更改此状态的唯一方法是完全销毁该工作程序并以新的请求重新开始。

这是具有优势的单线程经典模型。
- 请求结束时,所有工作人员都会死亡。
- 内存泄漏,竞争条件,死锁不是PHP固有的。 您不必担心。
- 代码很简单:我们编写,处理请求,死亡并继续前进。
另一方面,对于每个请求,我们完全加载框架,所有库,执行一些计算,重新编译模板。 围绕每个请求,我们进行了大量的操作和不必要的工作。
在服务器上的工作方式
一堆nginx和PHP很可能会起作用。 Nginx将充当反向代理:向用户提供部分静态信息,并将部分请求委托给下面的PHP流程管理器PHP-FPM。 经理已经为请求提出了一个单独的工作人员并对其进行处理。 之后,工人被销毁或清理。 接下来,为下一个请求创建一个新的工作程序。

这样的模型运行稳定-几乎不可能终止该应用程序。 但是在繁重的工作量下,初始化和销毁工作者的工作量会影响系统性能,因为即使对于简单的GET请求,我们也经常不得不拉出一堆依赖关系并重新提升数据库连接。
加快应用程序
引入缓存和延迟加载后如何加快经典应用程序的速度? 还有什么其他选择?
转向语言本身 。
- 使用OPCache。 我认为没有人在没有启用OPCache的情况下在生产环境中运行PHP吗?
- 等待RFC:预加载 。 它允许您将一组文件预加载到虚拟机中。
- JIT-严重加速了CPU任务的应用程序。 不幸的是,对于与数据库有关的任务,它没有太大帮助。
使用替代方案 。 例如,来自Facebook的HHVM虚拟机。 它在更优化的环境中执行代码。 不幸的是,HHVM与PHP语法不完全兼容。 作为替代方案,可以使用VK或PeachPie的kPHP编译器将代码完全转换为.NET C#。
完全重写为另一种语言。 这是一个根本的选择-完全摆脱请求之间的代码加载。
您可以
将应用程序的状态完全
存储在内存中 ,可以积极地使用该内存进行工作,而无需考虑垂死的工作人员的概念,并且可以在请求之间完全清除应用程序。
为了实现这一点,我们将与初始化点一起使用的入口点移入了应用程序的深处。
转移入口点-妖魔化
这在应用程序中创建了一个无限循环:传入请求-通过框架运行-生成对用户的响应。 这是一个很大的节省-所有引导程序,框架的所有初始化仅执行一次,然后由应用程序处理多个请求。

我们适应应用
有趣的是,我们可以专注于仅优化将
在运行时运行的那部分应用程序:控制器,业务逻辑。 在这种情况下,您可以放弃延迟加载模型。 在初始化时,我们将从一开始就参与引导项目。 初步计算:路由,模板,设置,ORM方案将增加初始化,但将来它们将节省一个特定请求的处理时间。

我不建议在下载工作程序时编译模板,但是例如下载所有配置都是有用的。
比较模型
比较妖魔化的(左)模型和经典模型。

从创建过程到响应返回给用户的那一刻,妖魔化的模型花费了更多的时间。 经典应用程序已针对快速创建,处理和销毁进行了优化。
但是,预热代码后的所有后续请求都快得多。 框架,应用程序,容器已经在内存中,可以接受请求并快速响应。
长寿模型的问题
尽管有很多优点,该模型还是有一些限制。
内存泄漏。 该应用程序在内存中放置了很长时间,如果您使用该库的“曲线”,则错误的依赖项或全局状态-内存将开始泄漏。 在某个时候,将出现致命错误,这将破坏用户的请求。
该问题有两种解决方法。
- 编写准确的代码,使用经过验证的库。
- 积极监督工人。 如果您怀疑内存在进程内部泄漏,请主动将其更改为下限较低的模拟,即简单地更改为尚未设法累积未清除内存的新副本。
数据泄漏 。 例如,如果在传入请求期间我们将系统的当前用户保存在某个全局变量中,而忘记在请求后重设此变量,则系统的下一个用户可能会意外地访问他不应该看到的数据。
该问题在应用程序体系结构级别解决。
- 不要在全局上下文中存储活动用户。 在下一个请求之前,将丢弃并清除所有特定于请求上下文的数据。
- 认真处理会话数据。 PHP中的会话-使用经典方法,这是一个全局对象。 正确包装,以便在后续请求时将其重置。
资源管理 。
- 监视与数据库的连接。 如果应用程序在内存中挂了一个月或两个月,则打开的连接很可能会在此时间内关闭:数据库将被重新安装,重新启动,或者防火墙将重置连接。 在代码级别,请考虑重新连接,或者在每个请求断开连接后,在下一个请求重新引发连接。
- 避免长期文件锁定。 如果您的工作人员将一些信息写入文件,则没有问题。 但是,如果此文件已打开并具有锁,则在释放该锁之前,系统中的其他进程都无法访问该文件。
探索长寿模型
考虑一个长期存在的工作模型-演示应用程序-并探索实现它的方法。
非阻塞方法
我们使用异步PHP-我们将应用程序一次加载到内存中,并在应用程序内部处理传入的HTTP请求。 现在,
应用程序和服务器是一个过程 。 当请求到达时,我们创建一个单独的协程,或者在事件循环中我们给出一个承诺,对其进行处理并将其提供给用户。

该方法不可否认的优势是性能最高。 也可以使用有趣的工具,例如,
直接在应用程序上配置WebSocket 。
但是,该方法大大
增加了开发的复杂性 。 有必要安装ELDO,请记住并非所有数据库驱动程序都受支持,并且PDO库已排除在外。
为了在使用非阻塞方法进行妖魔化的情况下解决问题,可以使用众所周知的工具:
ReactPHP ,
amphp和
Swoole -C扩展形式的有趣开发。 这些工具工作迅速,拥有良好的社区和良好的文档。
封锁方式
我们不在应用程序内部引发协程,而是从外部进行。

我们只是
选择了一些应用程序流程 ,就像PHP-FPM那样。 我们不是以流程状态的形式发送这些请求,而是以协议或消息传递的形式从外部传递它们。
我们编写已知的相同
单线程代码 ,使用所有相同的库和相同的PDO。 使用套接字,HTTP和其他工具的所有艰苦工作都是
在PHP应用程序之外完成
的 。
缺点:我们必须
监视内存,并记住
两个不同进程之间的通信不是免费的 ,但我们需要传输数据。 这将产生少量开销。
为了解决该问题,已经有一个用
PHP编写的
PHP-RM工具 。 在ReactPHP库上,它已
与多个框架集成 。 但是,PHP-PM非常
慢,它在服务器级别泄漏内存,并且在负载下它的增长不如PHP-FRM那样大。
我们编写我们的应用服务器
我们编写
了与PHP-RM相似的
应用程序服务器 ,但功能更多。 我们想要服务器提供什么?
与现有框架结合。 我们希望与市场上几乎所有框架进行灵活集成。 我不想编写仅在特定情况下有效的工具。
服务器和应用程序的不同过程 。 热重启的可能性,因此在本地进行开发时,请按F5键并查看新的更新代码,并能够分别对其进行扩展。
高速稳定 。 尽管如此,我们仍在编写HTTP服务器。
易于扩展 。 我们不仅希望将服务器用作HTTP服务器,而且还希望将其用于队列服务器或gRPC服务器等单个方案。
尽可能
开箱即用 :Windows,Linux,ARM CPU。
能够编写特定于我们的应用程序的非常
快速的多线程扩展 。
如您所知,我们将用Golang编写。
RoadRunner服务器
要创建PHP服务器,您需要解决4个主要问题:
- 在Golang和PHP进程之间建立通信。
- 流程管理:创建,销毁,监视工人。
- 平衡任务-有效地将任务分配给工人。 由于我们正在实施的系统会阻止单个工人执行特定的特定传入任务,因此创建一个可以快速地说出流程已完成工作并准备接受下一个任务的系统非常重要。
- HTTP堆栈-将HTTP请求数据发送给工作程序。 编写用户向其发送请求的输入点是一个简单的任务,该请求将传递给PHP并返回。
流程之间交互的变体
首先,让我们解决Golang和PHP进程之间的通信问题。 我们有几种方法。
嵌入:直接在Golang中嵌入PHP解释器。 这是可能的,但是需要自定义PHP程序集,复杂的配置以及服务器和PHP的通用过程。 例如,在
go-php中 ,PHP解释器已集成到Golang中。
共享内存-共享内存空间的使用, 进程共享该空间 。 这需要艰苦的工作。 交换数据时,您将必须手动同步状态,并且可能发生的错误数量非常大。 共享内存还取决于操作系统。
编写传输协议-Goridge
我们采用了一条简单的路径,几乎在Linux系统上的所有解决方案中都使用了它-我们使用了传输协议。 它是
在标准PIPES和UNIX / TCP SOCKETS之上编写的 。
它具有双向传输数据,检测错误以及标记请求并在其上放置标头的能力。 对我们来说,一个重要的细微差别是能够在PHP和Golang方面实现不依赖的协议的能力-不用纯语言的C扩展。
与任何协议一样,基础是数据包。 在我们的情况下,数据包的固定报头为17个字节。

分配第一个字节以确定数据包的类型。 这可以是指示数据序列化类型的流或标志。 然后两次将数据大小打包为Little Endian和Big Endian。 我们使用这种传统来检测传输错误。 如果我们发现两个不同顺序的打包数据大小不匹配,则很可能发生了数据传输错误。 然后数据被发送。

在该软件包的第三个版本中,我们将摆脱这种遗留问题,引入带有校验和的更为经典的方法,并且还增加了将该协议与异步PHP进程一起使用的功能。
为了在Golang和PHP中实现该协议,我们使用了标准工具。
在Golang上:用于处理标准管道和UNIX / TCP套接字的编码/二进制库以及io和net库。
在PHP中:用于处理二进制数据打包/解压缩以及管道和套接字的扩展流和套接字的熟悉函数。
在实施过程中出现了一个有趣的
副作用 。 我们将其与标准的Golang net / rpc库集成在一起,这使我们可以直接在应用程序中从Golang调用服务代码。
我们编写服务:
用少量的代码,我们从应用程序中调用它:
<?php use Spiral\Goridge; require "vendor/autoload.php"; $rpc = new Goridge\RPC( new Goridge\SocketRelay("127.0.0.1", 6001) ); echo $rpc->call("App.Hi", "Antony");
PHP流程管理器
服务器的下一部分是PHP Worker的管理。

Worker是我们不断从Golang观察到的PHP流程。 我们在STDERR文件中收集其错误日志,通过Goridge传输协议与工作人员进行通信,并收集有关内存消耗,任务执行和阻止的统计信息。
实现很简单-这是os / exec,运行时,同步,原子的标准功能。 要创建工人,我们使用
Worker Factory 。

为什么选择工人工厂? 因为我们要在标准管道和套接字上进行通信。 在这种情况下,初始化过程略有不同。 在创建通过管道进行通信的工作者时,我们可以立即创建它并直接发送数据。 对于套接字,您需要创建一个工作程序,等待它到达系统,进行PID握手,然后才能继续工作。
任务平衡器
服务器的第三部分对于性能而言是最重要的。
为了实现,我们使用标准的Golang功能-
缓冲通道 。 特别是,我们创建了多个工作程序,并将它们作为LIFO堆栈放置在此通道中。

收到用户的任务后,我们将请求发送到LIFO堆栈,并要求发出第一个免费工人。 如果无法在一定时间内分配工作人员,则用户会收到“超时错误”类型的错误。 如果分配了工作程序-它从堆栈中获取,将被阻止,然后它从用户那里接收任务。

处理完任务后,响应将返回给用户,而工作人员站在堆栈的末端。 他准备再次执行下一个任务。

如果发生错误,则用户将收到错误,因为工作人员将被销毁。 我们要求工人池和工人工厂创建一个相同的过程并将其替换在堆栈上。 这样就可以通过类似于PHP-FPM的方式简单地重新创建工作程序,从而使系统即使在发生致命错误的情况下也能正常工作。

结果,事实证明是实施了一个非常快速的小型系统
-200 ns用于工作人员分配 。 即使出现致命错误,它也可以工作。 每个工人在某个时间点仅处理一项任务,这使我们可以使用
经典的阻止方法 。
主动监控
主动监视系统是流程管理器和任务平衡器的单独部分。

这是一个每秒对工作人员进行轮询并监视指标的系统:它查看他们消耗了多少内存,它们所占用的内存量以及它们是否为IDLE。 除了跟踪之外,系统还会监视内存泄漏。 如果工人超出某个限制,我们将看到它并在发生致命泄漏之前将其小心地从系统中移除。
HTTP堆栈
最后的简单部分。
如何实施:- 在Golang端引发一个HTTP点;
- 我们收到一个请求;
- 转换为PSR-7格式;
- 将请求发送给第一个免费工人;
- 将请求解压缩到PSR-7对象中;
- 我们处理;
- 我们产生答案。
为了实现,我们使用了标准的
Golang NET / HTTP库 。 这是一个著名的图书馆,具有许多扩展。 能够同时通过HTTPS和HTTP / 2协议工作。
在PHP方面,我们使用了PSR-7标准
。 它是一个具有许多扩展和中间件的
独立框架 。 PSR-7
在设计上是
一成不变的 ,与寿命长的应用程序的概念非常吻合,并且避免了全局查询错误。
Golang和PSR-7中的两个结构都相似,这大大节省了将请求从一种语言映射到另一种语言的时间。
要启动服务器,需要
最小绑定 :
http: address: 0.0.0.0:8080 workers: command: "php psr-worker.php" pool: numWorkers: 4
此外,从1.3.0版开始,可以省略配置的最后一部分。
下载服务器二进制文件,将其放入Docker容器或项目文件夹中。 另外,全局地,我们编写一个小的配置文件,该文件描述了我们将要收听的Pod,哪个工作程序是入口点以及需要多少个。
在PHP方面,我们编写了一个主循环,该循环接收PSR-7请求,对其进行处理,然后将响应或错误返回给服务器。
while ($req = $psr7->acceptRequest()) { try { $resp = new \Zend\Diactoros\Response(); $resp->getBody()->write("hello world"); $psr7->respond($resp); } catch (\Throwable $e) { $psr7->getWorker()->error((string)$e); } }
组装方式 为了实现服务器,我们选择了带有组件方法的体系结构。 这样就可以根据项目需要组装服务器,并根据应用程序的需求添加或删除单个组件。
func main() { rr.Container.Register(env.ID, &env.Service{}) rr.Container.Register(rpc.ID, &rpc.Service{}) rr.Container.Register(http.ID, &http.Service{}) rr.Container.Register(static.ID, &static.Service{}) rr.Container.Register(limit.ID, &limit.Service{}
用例
考虑使用服务器和修改结构的选项。 首先,请考虑经典管道-服务器可以处理请求。
模块化
服务器接收到HTTP点的请求,并将其通过一组用Golang编写的中间件传递。 传入的请求将转换为工作人员可以理解的任务。 服务器将任务交给工作人员并将其返回。

同时,工作人员使用Goridge协议与服务器通信,监视其状态并向其传输数据。
Golang上的中间件:授权
这是第一件事。 在我们的应用程序中,我们编写了Middleware
通过JWT令牌授权用户 。 对于任何其他类型的授权,中间件都以相同的方式编写。 一个非常平庸而简单的实现是编写Rate-Limiter或Circuit-Breaker。
授权很快 。 如果请求无效,则不要将其发送到PHP应用程序,也不要在处理无用的任务时浪费资源。
监控方式
第二个用例。 我们可以将监视系统直接集成到Golang中间件中。 例如Prometheus,收集有关响应点速度,错误数量的统计信息。

您还可以
将监视与特定于应用程序的指标结合使用 (在1.4.5中作为标准配置提供)。 例如,我们可以将请求数量发送到数据库,或者将已处理的特定请求数量发送到Golang服务器,然后发送给Prometheus。
分布式跟踪和记录
我们与流程管理器一起编写中间件。 特别是,我们可以连接到用于监视日志的实时系统,并将
所有日志收集到一个中央数据库中 ,这在编写分布式应用程序时非常有用。

我们还可以
标记请求 ,给它们指定一个特定的ID,然后将此ID传递给它们之间的所有下游服务或通信系统。 结果,我们可以构建一个
分布式跟踪,并查看应用程序日志的运行方式。
记录您的查询历史记录
这是一个小模块,记录所有传入的请求并将其存储在外部数据库中。 该模块允许您在项目中提出重播请求,并实现自动测试系统,负载测试系统,或仅检查API的操作。

我们如何实现该模块?
我们处理Golang的部分请求 。 我们用Golang编写中间件,并且可以将部分请求发送给也用Golang编写的Handler。 如果应用程序中的某些点在性能方面令人担忧,我们将其重写为Golang并将堆栈从一种语言拖到另一种语言。
我们正在编写一个WebSocket服务器 。 实施WebSocket服务器或推送通知服务器正成为一项琐碎的任务。
- 服务器级别的Golang服务。
- 为了交流,我们使用Goridge。
- PHP中的瘦服务层。
- 我们实现了通知服务器。
我们收到一个请求,并引发一个WebSocket连接。 如果应用程序需要向用户发送某种通知,它会通过RPC协议向WebSocket服务器启动此消息。
管理您的PHP环境。 创建工作人员池时,RoadRunner可以完全控制环境变量的状态,并允许您随意更改它们。 如果要编写大型分布式应用程序,则可以使用单个配置数据源并将其作为系统连接以配置环境。 如果我们提供一组服务,那么所有这些服务都将敲定一个系统,进行配置然后运行。 这可以大大简化部署,并摆脱.env文件。

有趣的是,worker内部可用的env变量在系统内不是全局的。 这稍微提高了容器的安全性。
Golang库在PHP中的集成
我们在
RoadRunner的官方网站上使用了此选项。 这是服务器内部几乎完整的数据库
与全文搜索BleveSearch的集成 。

我们为文档页面建立索引:将它们放置在Bolt DB中,之后执行全文搜索,而没有像MySQL这样的真实数据库,也没有像Elasticsearch这样的搜索集群。 结果是一个小型项目,其中某些功能使用PHP,但搜索使用Golang。
实施Lambda函数
您可以走得更远,
完全摆脱HTTP层。 在这种情况下,实现Lambda函数是一项简单的任务。

为了实现,我们将Lambda函数使用
AWS标准
运行时 。 我们编写一个小的绑定,完全切断HTTP服务器,然后将二进制格式的数据发送给工作人员。 我们还可以访问环境设置,这使我们可以编写直接从Amazon管理面板配置的功能。
工作者在整个过程中都在内存中,初始请求后的Lambda函数在内存中保留15分钟。 目前,该代码无法加载并快速响应。 在综合测试中,
每一个传入请求我们最多接收
0.5毫秒 。
适用于PHP的gRPC
更为困难的选择是将HTTP层替换为gRPC层。 该
软件包可在GitHub上获得 。

我们可以将所有传入的Protobuf请求完全代理到下级PHP应用程序,在那里可以对它们进行解包,处理和答复。 我们可以用PHP和Golang编写代码,将功能从一个堆栈转移到另一个堆栈。 该服务支持中间件。 独立应用程序以及与HTTP结合使用都可以工作。
队列服务器
最后也是最有趣的选择是
队列服务器的实现。

在PHP方面,我们要做的就是获取二进制有效负载,将其解压缩,完成工作,然后将成功告知服务器。 在Golang方面,我们完全致力于管理与经纪人的联系。 它可以是RabbitMQ,Amazon SQS或Beanstalk。
在Golang方面,我们实施了工人的“正常
关机” 。 我们可以精美地等待“持久连接”的实现-如果与代理的连接丢失,服务器将使用“退避策略”等待一段时间,它取消了连接,应用程序甚至没有注意到它。
我们可以在PHP和Golang中处理这些请求,并在两侧排队:
- 从PHP通过Goridge协议Goridge RPC;
- 从Golang-与SDK库进行通信。
如果有效负载下降,则不是整个消费者下降,而是只有一个单独的过程。 系统立即将其引发,任务将发送给下一个工作人员。 这使您可以执行不间断的任务。
我们直接在服务器内存中实现了一个代理,并使用了Golang功能。 这使我们能够在选择最终堆栈之前使用队列编写应用程序。 我们在本地提升应用程序,启动它,并且我们有在内存中工作的队列,其行为与在RabbitMQ,Amazon SQS或Beanstalk上的行为相同。
当在这样的混合包中使用两种语言时,值得记住如何将它们分开。
单独的域域
Golang是一种多线程快速语言,适用于编写基础结构逻辑以及用户监视和授权逻辑。
这对于
实现用于访问数据源的
自定义驱动程序也很有用-这些是队列,例如Kafka,Cassandra。
PHP是用于编写业务逻辑的出色语言。
这是用于HTML呈现,ORM和数据库使用的良好系统。
工具比较
几个月前,
在Habré上对 PHP-FPM,PHP-PM,React-PHP,Roadrunner和其他工具进行了比较。 基准测试是在一个带有Symfony 4的项目上进行的。
负载下的RoadRunner显示出良好的结果,并且领先于所有服务器。 与PHP-FPM相比,性能提高了6-8倍。

在同一基准测试中,RoadRunner没有丢失任何一个请求,所有内容都可以100%解决。 不幸的是,React-PHP在负载下丢失了8–9个请求-这是不可接受的。 我们希望服务器不崩溃并稳定运行。

自从RoadRunner在GitHub上公开发布以来,我们已经收到了30,000多个安装。 社区帮助我们编写了一组特定的扩展,改进,并相信该解决方案具有生命权。
如果您想
大大加快应用程序的速度,但是尚未准备好使用异步PHP, RoadRunner就是很好的选择。 这是一个折衷方案,需要一定的努力,但不如完全重写代码库那么重要。
如果您想
更好地控制PHP生命周期 ,
如果没有足够的PHP功能(例如,用于队列系统或Kafka)并且当流行的Golang库解决了您的问题(不是PHP的问题)并且编写需要花费时间(而您却没有)时,请使用RoadRunner。
总结
通过编写此服务器并将其用于生产基础架构中,我们得到了什么。
- 与PHP-FPM相比, 它们将应用程序点的反应速度提高了4倍 。
- 完全摆脱了负载下的502错误 。 在峰值负载下,服务器仅等待一会儿,然后响应,就好像没有负载一样。
- 优化内存泄漏后,工作人员会在内存中挂起长达2个月的时间 。 这有助于编写分布式应用程序,因为服务之间的所有请求都已在套接字级别缓存。
- 我们使用Keep-Alive。 这大大加快了分布式系统之间的通信。
- 在真正的基础架构内部, 我们将所有内容放入Kubernetes的Alpine Docker中 。 现在,该项目的部署和构建系统更加容易。 所需要做的就是为该项目构建自定义的RoadRunner构建,将其放入Docker项目中,填写Docker映像,然后将我们的pod平稳地上传到Kubernetes。
- 根据项目之一对无法访问数据库的各个点的实际时序, 平均响应时间为0.33 ms 。
明年仅面向PHP开发人员的下一次专业会议PHP俄罗斯 。 目前,我们提供以下内容:
- 如果您对Go语言感兴趣,并想了解更多详细信息或听到赞成切换到该语言的争论,请关注GolangConf 。 如果您准备分享您的经验, 请发送摘要 。
- 参加莫斯科的HighLoad ++ ,如果对您而言与高性能相关的所有重要事项,请在9月7日之前提交报告,或预订机票。
- 订阅新闻通讯和电报频道 ,以便比其他人更早收到2020年PHP Russia的邀请。