首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  PHP

PHP 代码更新的时候会不会中断用户正在进行的请求及响应

  •  2
     
  •   awanganddong · 79 天前 · 3109 次点击
    这是一个创建于 79 天前的主题,其中的信息可能已经有所发展或是发生改变。

    php 模式是使用的 php-fpm 模式

    比如用户正在请求响应,这时候我更新了代码。会不会对正在请求响应产生影响

    问了我老大,他说不会。 让我了解 web 的工作原理

    这里我就想问下,大家 这个没想明白

    28 回复  |  直到 2019-09-20 14:40:55 +08:00
        1
    imdong   79 天前
    答:不会。

    如果对工作原理懂了,都不会这么问了。

    简单的说,用户 -> Nginx -> php-fpm ( read php file -> run code ) -> Nginx -> 用户

    你更改 php 文件的时候,只要 fpm 执行中,就不会出现问题。

    因为不是边执行边读取,而是读取以后再执行,读取文件是瞬时完成的,修改和读取不会同时(系统保证)
        2
    toyuanx   79 天前
    可以看下这篇文章: https://blog.csdn.net/IT_10/article/details/95387481

    "可以看到一旦 kill 掉 worker 进程后,会重启一个新的 worker 进程。因此客户端请求肯定会得到响应处理。这进一步验证了的上面的结论,master 进程负责监听子进程的状态,子进程挂掉之后,会发信号给 master 进程,然后 master 进程重新启一个新的 worker 进程。"

    正常来说上线的时候对用户是有有影响的,但是如果上线的时间够快,可能影响就比较少
        3
    lincanbin   79 天前 via Android
    你去 Google 搜一下,关键字:php-fpm 平滑重启
        4
    lp7631010   79 天前 via iPhone
    人家问的是更改 php 文件吧 跟 fpm 重启啥的有什么关系呢
        5
    awanganddong   79 天前
    @imdong 你说的最后一句,可以稍微解答我的困惑,但是就是太简略了。

    @toyuanx nginx 的热加载和 php-fpm 的热加载 master-worker 这种模式我也知道。包括多进程间内存是隔离的。


    但是隐约感觉没有一语中的。
        6
    awanganddong   79 天前
    https://t.ti-node.com/thread/6528965533792993280

    这是一个大佬的笔记


    apue 我需要连接下了
        7
    ben1024   79 天前
    每个进程在运行时已经把代码加载到对应的内存中,每个进程使用的内存是独立的,不会相互干扰
        8
    mcfog   79 天前
    是否有影响影响多少用户多少时间取决于你们的部署流程是否正确
    能否观测、监控到这种影响取决于你们的基础设施是否完善

    一个很基本简单的方法论:如果你要修复或者改进一个问题,就必须先确保你能够观测、重现或测量它,否则你做的一切改进都是没有意义的。在建立了观测手段以后,减少更新代码对用户的影响这种属于常规基础的问题,找一些实践跟着做就行,很容易降到 0 或者可以忽略的程度的。

    基于你其实并没有说你们的情况,所以这里即使说了一些实践做法的人也都只是随意说一些常见的可以做的事情而已
        9
    CODEWEA   79 天前   ♥ 5
    答案:会 和 不会取决你如何更新代码。
    你如果是用 svn git 那种覆盖式的更新,大概率是会因为文件依赖而遇到问题。
    为什么会出现问题?
    首先,你的 PHP 项目不可能就一个文件吧,比如你上一个版本 UserService 引入了 MailClass,但是你下一个版本中在 UserService 把 MailClass 删除了,如果你使用覆盖式更新时,如果 MailClass 完成更新删除了,但是 UserService 还没有更新,此时一个请求来了,并不会一次性把你 PHP 项目所有文件载入进去,当文件依赖出问题,你网站直接就 5XX 了

    如何不出问题呢?
    问题的关键就在于你改动 php 项目时,文件的依赖会发生变化,如果项目文件正处于变化时,文件依赖是处于混乱状况的,此时如果一个请求过来,你项目就 5XX 了。

    解决办法:
    1.更新代码时,阻断外部请求,将所有请求重定向到与这个项目无关的维护页面。
    2.nginx 配置 2 个项目,一个为新,一个为旧的,当你新的更新完毕同时内部测试无误后,切换 nginx 的配置文件,切换到新的。

    解决的的核心逻辑是不要在你 php 项目中文件发生变化时运行外部程序请求访问。
        10
    zhangtao   79 天前
    太多人喜欢不懂装懂了
        11
    CODEWEA   79 天前
    你老大说的:不会,应该是理想状态,或者说 php 项目中就一个 php 文件
        12
    jsjscool   79 天前   ♥ 4
    先说答案,会有影响,但是发生的概率极低。

    简单理解 PHP 的执行流程是这样的:

    1. 扫描所有 PHP 文件,并转换成 Token (语言片段)
    2. 解析编译 Token 得到 Opocdes
    3. 执行 Opocdes

    第一步扫描所有 PHP 文件时会将 include,require 等的代码一起加到内存,速度非常快,如果此时更新代码是有可能影响当前请求的。

    如果请求进入到 1 之后的阶段,更新代码是不会对正在进行的请求有影响,因为用户的请求是独立的进程,独立的内存空间,内存里面的代码是请求到达 php-fpm 进程时那一刻的快照。

    如何避免:
    现在发布 PHP 代码都用 CI,CI 的实现方式不是 update 代码,而是每次创建一个新文件夹,全量拷贝代码,再修改软链接。如果使用类似方式发布代码的话就如你老大所说,不会影响用户请求。
        13
    ssynhtn   79 天前 via Android
    不管会不会,和 web 都一毛钱关系没有啊,应该和多个文件的写 /读有关。如果你们是像我待的那种公司一样用 ftp 传 PHP 文件的,ftp 和操作系统又不像数据库那样保证多个文件的上传为事务操作啊?
        14
    wshcdr   79 天前
    会的啊
        15
    CODEWEA   79 天前
    @jsjscool 不是吧? include require 是否真的引入文件还是根据你逻辑来的啊
        16
    zsen   79 天前 via iPhone
    同时考虑一下 php.ini 中的 opcache ?
        17
    crynocry   79 天前
    @imdong 同一个文件可以保证。 可是替换代码是批量替换,会出现有一部分老代码一部分新代码的情况么
        18
    jsjscool   78 天前
    @CODEWEA 我这里描述有误 ,从扫描文件到执行在多文件下是串行的不是并行。
        19
    akira   78 天前
    从原理上讲,单一文件肯定是不会。
    但是
    不管会不会 , 更新发版的时候 截断请求是个好习惯.
        20
    x86   78 天前
    细说的话看你动什么文件了
        21
    lihongming   78 天前 via iPhone
    你要是一个文件一个文件的更新,难免会出现用户访问的文件一部分新一部分旧的问题。要是还改了数据库,那就不可避免会出错。

    所以我们都是把 PHP 等后端系统放在容器或虚拟机里,一更新就是整个系统,然后在前端 nginx 切换一下就行了。
        22
    ladypxy   78 天前 via iPhone
    这么久了居然都没人提到 opcache.revalidate_freq。这就专门针对更新的设置
        23
    awanganddong   78 天前
    现在已经知道对于我提到的问题的解决方案有两种,
    一种是 nginx 进行切换
    一种是 ci 的自动发布
        24
    lihongjie0209   78 天前
    情况有很多, 简单来讲: 不会

    用户正在进行的请求就意味着 php 代码已经被加载的内存中执行了(进程), 这个时候你更新程序, 是不会影响到进程的。


    复杂点讲, 可能会:
    用户正在进行的请求就意味着 php 代码已经被加载的内存中执行了(进程),这个进程然后去加载其他的代码, 而你在更新其他代码, 那么就会可能导致一些问题, 如:

    1. 代码不兼容, 原来是方法 A, 现在改为方法 B, 当然会报错
    2. 代码不完整, 取决于你的更新方式, 当前你的文件数据可能是不完整的, 比如说 1K 的文件当前只传输了 0.5K , 这时候你去读取文件, 就会直接报错。


    这个问题其实和 PHP 没什么关系, 更多是操作系统中进程和文件系统的一些相关知识。
        25
    ETO   78 天前
    @lp7631010 道理一样的。
        26
    laminux29   78 天前
    不管会不会,你这种做法就是不对的。正确的操作应该像 9 楼 [CODEWEA] 说的那样。

    这种事情的本质是事务问题,你想了解详情的话,可以翻翻数据库、分布式系统的书籍,里面会有关于这个问题的阐述。
        27
    awanganddong   78 天前
    @lihongjie0209 对的,实际上公司代码是通过 jenkins 全量覆盖。然后更新过程中,出现不正常,继而引发对这个问题的探讨。

    这个问题,也确实不单单 php 会遇到,包括其他中语言也是一样,可能方式不一样。
        28
    lihongjie0209   78 天前
    @awanganddong #27 如果做不到多节点负载, 一个节点一个节点的更新, 那最好就是先把 Nginx 关闭再更新
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2245 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 25ms · UTC 12:44 · PVG 20:44 · LAX 04:44 · JFK 07:44
    ♥ Do have faith in what you're doing.