高并发如何避免重复记录用户信息

高并发如何避免重复记录用户信息

用户访问网站记录用户IP,来源网站,访问网站

高并发如何避免重复记录用户IP地址

获取访问者ip地址  $_SERVER['REMOTE_ADDR']     测试使用192.168.1.mt_rand(0,10)代替
获取客户来源网址   $_SERVER["HTTP_REFERER"]    测试使用baidu.com代替
获取访问网址       'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']

创建数据库

#复制执行SQL语句
create database if not exists test;
use test;
drop table if exists site;
create table site(
id int primary key auto_increment,
ip varchar(120) not null,
page varchar(120) not null,
referrer varchar(120) not null
);

创建test.php记录访问者信息

query("select * from site where ip = '$user_ip'");
$site = $pdoStatement->fetch(PDO::FETCH_ASSOC);
if (!$site) {
    $pdo->exec("insert into site values (null, '$user_ip', '$user_page', '$user_referer')");
}

通过apache的ab测压工具模拟请求

ab -n 300 -c 100 http://127.0.0.1/test.php

打开Navicat查看结果

逻辑没问题,并发出问题

使用memcache测试重新测试

修改站点目录下的test.php文件

connect('127.0.0.1', 11211);//

#3.判断该IP未记录则入库
if (!$mem->get($user_ip)) {
    //入库
    $mem->add($user_ip, [$user_ip, $user_pager, $user_referer]);
    //注:因为memcache不方面查看键,所以通过文件查看
    file_put_contents('./'.$user_ip . '__' . time() . microtime(true), 1);
}

同样通过apache的ab测压工具模拟请求

ab -n 300 -c 100 http://127.0.0.1/test.php

对于memcache访问测试量过少,体现不出要测试的效果可以修改代码

connect('127.0.0.1', 11211);

#3.判断该IP未记录则入库
if (!$mem->get($user_ip)) {
   //usleep单位是微秒,1秒 = 1000毫秒 ,1毫秒 = 1000微秒
    usleep(10000);
    //入库
    $mem->add($user_ip, [$user_ip, $user_pager, $user_referer]);
    //注:因为memcache不方面查看键,所以通过文件查看
    file_put_contents('./'.$user_ip . '__' . time() . microtime(true), 1);
}

增加访问延迟 在测试结果

发现出现重复文件 = 重复键

IP入库(memcache优化)

connect('127.0.0.1', 11211);

//【新增】加锁不成功的,进行排队等待(注:第一个用户进来未处理完,后面的用户循环等待)
while ( !$mem->add('lock', 'lock', 0, 0) ){ //如果键存在测后面数据重复等待 知道释放lock
    //进行休息
    //加锁成功返回true 进行循环
    //加锁失败-- 当前没有键 测添加
    usleep(1000); //usleep单位是微秒,1秒 = 1000毫秒 ,1毫秒 = 1000微秒
}

#3.判断该IP未记录则入库
if (!$mem->get($user_ip)) {
   //usleep单位是微秒,1秒 = 1000毫秒 ,1毫秒 = 1000微秒
    usleep(10000);
    //入库
    $mem->add($user_ip, [$user_ip, $user_pager, $user_referer]);
    //注:因为memcache不方面查看键,所以通过文件查看
    file_put_contents('./'.$user_ip . '__' . time() . microtime(true), 1);
}

//【新增】删除锁(注:操作完毕后,释放锁,让后面用户进来)
$mem->delete('lock');

重新测试..

完成代码

connect('127.0.0.1', 11211);

//【新增】加锁不成功的,进行排队等待(注:第一个用户进来未处理完,后面的用户循环等待)
while ( !$mem->add('lock', 'lock', 0, 0) ){
    //进行休息
    usleep(1000); //usleep单位是微秒,1秒 = 1000毫秒 ,1毫秒 = 1000微秒
}

#3.判断该IP未记录则入库
if (!$mem->get($user_ip)) {
    //usleep单位是微秒,1秒 = 1000毫秒 ,1毫秒 = 1000微秒
    //usleep(10000);
    //入库
    $mem->add($user_ip, [$user_ip, $user_pager, $user_referer]);
    //注:因为memcache不方面查看键,所以通过文件查看
    file_put_contents('./'.$user_ip . '__' . time() . microtime(true), 1);
}

//【新增】删除锁(注:操作完毕后,释放锁,让后面用户进来)
$mem->delete('lock');

你可能感兴趣的:(高并发如何避免重复记录用户信息)