LEN

文件锁 - 解决高并发数据安全问题
最近比较懒, 这篇文章应该早点写的. 介绍下使用文件锁的场景,公司某部门接口遭黑客强刷, CTO让所有部门查看所有...
扫描右侧二维码阅读全文
07
2017/05

文件锁 - 解决高并发数据安全问题

最近比较懒, 这篇文章应该早点写的. 介绍下使用文件锁的场景,
公司某部门接口遭黑客强刷, CTO让所有部门查看所有对外接口高并发下是否存在脏操作;

大概是上面的意思, 举个栗子:
用户领取奖励,多点几下能够获取多次奖励;这个栗子是真实存在的.

分析下原因, 通常业务逻辑就是:

  1. 用户点击领取奖励 -> 2. 触发领取接口 -> 3. 接口逻辑先验证是否满足条件,一否已领取 -> 4. 满足条件领取奖励

上面是这样的业务, 但如果用户手快 多次请求触发接口,就会发生在 "3" 的位置验证通过都满足条件,用户就能多领奖....

上述场景 接口需要添加一把锁将接口锁起来, 上锁期间其他请求禁止请求,就可以解决这个问题了.

这个问题高并发场景以前也遇到过, 但解决方案是使用mysql 读锁,用户请求阻塞. 效果说实话有效但当时觉得就很怪, 方案很有局限性,
当时接口数据直接读库mysql, 使用 for update 进行读锁, 还需要搭配事务使用.

回归正题 : 文件锁 - 解决高并发数据安全问题
下面是php 文件锁的封装类这个类是从网上随便找的, 简单看了下改了些地方文件锁存放路径 /dev/shm 和添加register_shutdown_function

/dev/shm的容量默认最大为内存的一半大小,使用df -h命令可以看到。但它并不会真正的占用这块内存,如果/dev/shm/下没有任何文件,它占用的内存实际上就是0字节。

通过下面的命令,我们可以看到/dev/shm的文件系统为tmpfs,即为临时文件系统。其他的几个tmpfs的挂载目录,其实质上于/dev/shm是一致的。

register_shutdown_function(array($this, 'unlock'));

register_shutdown_function — 注册一个会在php中止时执行的函数

flock 锁机制

LOCK_SH取得共享锁定(读取的程序)。
LOCK_EX 取得独占锁定(写入的程序。
LOCK_UN 释放锁定(无论共享或独占)。

<?php
/**
 * 用于解决PHP在并发时候的锁控制,不同的锁之间并行执行,类似mysql innodb的行级锁
 */
class FileLock {

    //文件锁存放路径
    private $path='/dev/shm';

    //文件句柄
    private $fp='';

    //锁文件
    private $lockFile='';

    /**
     * 构造函数
     * @param string $name 锁 KEY
     */
    public function __construct($name)
    {
        $this->lockFile=$this->path.md5($name).'.lock';
    }
 
    /**
     * 加锁
     */
    public function lock()
    {
      $this->fp=fopen($this->lockFile, 'a+');
      if($this->fp===false){
        return false;
      }
      register_shutdown_function(array($this, 'unlock'));

      return flock($this->fp, LOCK_EX);//获取独占锁
    }
     
    /**
     * 解锁 (尽量手动解锁)
     */
    public function unlock()
    {
      if($this->fp!==false){
         @flock($this->fp,LOCK_UN);
         clearstatcache();
      }
      @fclose($this->fp);
      @unlink($this->lockFile);
    }
}

通过上面的类就可以通过在服务器的/dev/shm下创建一个文件并且上独占锁,禁止其他请求读写, 在入口出屏蔽请求不阻塞.
添加register_shutdown_function 是在上锁时注册一个php中止时执行解锁.
还有问题就是做负载均衡时如何控制文件锁, 也简单设置负载策略呗, 让同一用户永远访问同一台机器...
感觉有点类似会话共享问题.

文件锁以前听朋友说过,但是在讨论文件写入加锁的问题, 想必文件锁在生产环境下还有更多的应用.

Last modification:May 7th, 2017 at 11:18 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment

2 comments

  1. 哒哒

    文件不会 慢么 io开销大

    1. LEN
      @哒哒

      文件锁解决并发 将文件放在 /dev/shm 下 相当于内存io