高并发如何避免重复记录用户信息
用户访问网站记录用户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记录访问者信息
<?php
#1.组装用户信息
$user_ip = '192.168.1.'.mt_rand(0, 10);
$user_page = 'http://baidu.com';
$user_referer = 'http://baidu.com';
#2.连接数据库
$pdo = new PDO('mysql:dbname=test', 'root', 'root');
#3.判断该IP未记录则入库
$pdoStatement = $pdo->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文件
<?php
#1.组装用户信息
$user_ip = '192.168.1.'.mt_rand(0, 10);
$user_page = 'http://baidu.com';
$user_referer = 'http://baidu.com';
#2.连接数据库
$mem = new Memcache;
$mem->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访问测试量过少,体现不出要测试的效果可以修改代码
<?php
#1.组装用户信息
$user_ip = '192.168.1.'.mt_rand(0, 10);
$user_page = 'http://baidu.com';
$user_referer = 'http://baidu.com';
#2.连接数据库
$mem = new Memcache;
$mem->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优化)
<?php
#1.组装用户信息
$user_ip = '192.168.1.'.mt_rand(0, 10);
$user_page = 'http://baidu.com';
$user_referer = 'http://baidu.com';
#2.连接数据库
$mem = new Memcache;
$mem->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');
重新测试..
完成代码
<?php
#1.组装用户信息
$user_ip = '192.168.1.'.mt_rand(0, 10);
$user_page = 'http://baidu.com';
$user_referer = 'http://baidu.com';
#2.连接数据库
$mem = new Memcache;
$mem->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');