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

如何限制 PHP 每秒只执行一次?

  •  
  •   yitalin · 2022-07-16 07:14:43 +08:00 · 4317 次点击
    这是一个创建于 869 天前的主题,其中的信息可能已经有所发展或是发生改变。
    a.php 实际上每秒有 10 个 ip 同时访问,如何实现每秒只执行一个 ip 的请求,同一秒剩余 9 个的请求实际上代码是不执行的?
    想了半天找不到解题思路
    28 条回复    2022-07-18 13:28:52 +08:00
    em70
        1
    em70  
       2022-07-16 07:38:50 +08:00
    修改 nginx 配置文件,把最大并发 IP 设为 1

    limit_conn perip 1
    ersic
        2
    ersic  
       2022-07-16 07:41:09 +08:00 via Android   ❤️ 2
    换个思路,让每个执行都持续一秒。
    dangyuluo
        3
    dangyuluo  
       2022-07-16 07:59:51 +08:00
    加锁和队列?
    xiangyuecn
        4
    xiangyuecn  
       2022-07-16 08:05:28 +08:00
    @em70 #1 @ersic #2 严禁掩耳盗铃🐶 😂
    realpg
        5
    realpg  
       2022-07-16 08:21:25 +08:00
    这还用思路?

    首先,多个请求,他们得有一个协商的地方,就是得有个公共的地方能存储状态
    数据库,redis,memcache,或者 shmem
    然后按秒做标志,考虑好锁存机制
    或者利用关系数据库的一些特性去做,比如利用 mysql 的 unique 索引实现天然锁
    zjsxwc
        6
    zjsxwc  
       2022-07-16 08:35:35 +08:00 via Android
    用 mode 为 x 的 fopen 方式打开文件名为秒级时间戳的文件,
    这样再某一秒中只有第一个 fopen 能成功,

    https://www.php.net/manual/zh/function.fopen.php
    realpg
        7
    realpg  
       2022-07-16 08:42:32 +08:00
    @zjsxwc #6
    然后第一个打开成功,30ms 后 PHP 执行退出了,下一个又打开了?
    imdong
        8
    imdong  
       2022-07-16 08:52:28 +08:00 via iPhone   ❤️ 1
    伪代码:
    if(!Redis::set(time())) return;
    zjsxwc
        9
    zjsxwc  
       2022-07-16 08:57:16 +08:00 via Android
    @realpg
    执行完 sleep 1 秒,
    嘿嘿
    treblex
        10
    treblex  
       2022-07-16 09:11:18 +08:00 via iPhone
    存一个时间戳,没过期之前都返回缓存结果,过期执行实际代码更新缓存
    ersic
        11
    ersic  
       2022-07-16 10:58:38 +08:00
    redis 存一个 1s 过期的 key ,存在就不执行,不存在就执行,执行完继续存这个 key 。
    k9982874
        12
    k9982874  
       2022-07-16 11:32:56 +08:00 via Android
    起消息队列,消费者一秒只处理一个
    vacker
        13
    vacker  
       2022-07-16 11:45:13 +08:00
    php 的话可以用 laravel 的原子锁

    use Illuminate\Support\Facades\Cache;

    $lock = Cache::lock('foo', 1);

    if ($lock->get()) {
    // 锁定 1 秒...
    }
    GGGG430
        14
    GGGG430  
       2022-07-16 11:53:44 +08:00
    public static function lock($key, $ttl)
    {
    return apcu_add($key, 1, $ttl);
    }
    misaka19000
        15
    misaka19000  
       2022-07-16 11:55:09 +08:00
    漏桶算法

    想要简单点可以直接用 apisix 网关管理
    wonderfulcxm
        16
    wonderfulcxm  
       2022-07-16 12:13:07 +08:00 via iPhone
    那不在这一秒执行的其他请求怎么处理,是直接返回 503 还是进入队列等待下一秒?
    cpstar
        17
    cpstar  
       2022-07-16 13:20:37 +08:00
    我觉得 LZ 没想清楚的事情是,不是一秒钟内执行一个,而是每一秒钟怎么调配给不同的请求,是时间分配给请求,而不是请求来抢占时间。
    keepeye
        18
    keepeye  
       2022-07-16 13:38:16 +08:00
    redis setnx ,过期时间设为 1 秒 setnx 返回 1 的那个执行,其他的不执行
    sutra
        19
    sutra  
       2022-07-16 15:33:29 +08:00
    搜“限流”,有算法,也有解决方案。
    pengtdyd
        20
    pengtdyd  
       2022-07-16 17:08:32 +08:00
    rxjs 可以做到,不过嘛这玩意学起来很难
    cszchen
        21
    cszchen  
       2022-07-16 22:53:44 +08:00 via iPhone
    是期望“每秒”只有一个请求,还是同一个时间点只有一个请求。区别很大,解决的思路很简单。
    装个 redis ,获取原子锁,没有群的要等
    liyunlong5
        22
    liyunlong5  
       2022-07-17 16:36:06 +08:00 via Android   ❤️ 1
    @em70 这个只是限制一个连接,真正限制请求要加上 limit req 1r/s
    janus77
        23
    janus77  
       2022-07-17 19:35:50 +08:00
    加一层缓存就行了呗,一秒内的请求都走缓存
    hoopan
        24
    hoopan  
       2022-07-18 09:21:05 +08:00
    php 进程池只开一个呢,为啥会有这种奇怪的需求,原始需求是啥?如果是防止并发出错,可以加锁。
    junwind
        25
    junwind  
       2022-07-18 09:39:56 +08:00
    第一个 ip 访问进来写一个 session ,第一个进来,如果有这个值就 return ,没试过,不知道能否实现你的要求
    xuelu520
        26
    xuelu520  
       2022-07-18 11:36:08 +08:00
    加锁就行了
    wolfie
        27
    wolfie  
       2022-07-18 11:47:17 +08:00
    java 思路
    请求扔队列,根据 ip 分组。
    所有请求共用互斥锁,定义个守护线程循环 wait 、notify.
    tianyou666shen
        28
    tianyou666shen  
       2022-07-18 13:28:52 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2579 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 10:54 · PVG 18:54 · LAX 02:54 · JFK 05:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.