Maison >développement back-end >tutoriel php >如何在高并发下,http请求返回绝对的当前请求是第几个请求?
比如,我第一次访问请求返回json:{"n": 1}
我第100次访问请求返回json:{"n": 100}
传统的写数据库,再查数据库返回,在并发大时好像不能保证,我应该怎么办?这应该是最简化了的问题了
比如,我第一次访问请求返回json:{"n": 1}
我第100次访问请求返回json:{"n": 100}
传统的写数据库,再查数据库返回,在并发大时好像不能保证,我应该怎么办?这应该是最简化了的问题了
最简单的方法就是建个自增id主键的mysql表,然后每来一次请求就插一条记录,再读出这条记录,读出的id就是你要的值。
然后就可以根据id值来轻松处理高并发的场景了,比如【秒杀】就可用id小于300且能被6整除的规则认为秒杀成功;【抽奖】可以用能被100整除(百分之一概率)作为中奖等等。
如果自己实现也无非就是单线程死循环处理socket请求维护一个全局变量,不如用现成的mysql方便可靠。
如果是java
的话,一个全局的AtomicLong
可以满足你的需求吧,getAndIncrement
原子操作,再加上volatile
修饰,如果是其他语言,大同小异吧
使用redis中的setnx(id),单线程保证每次加1,而且还是内存数据库,速度超级快。
读操作:使用缓存
写操作:使用队列异步写入
纯粹Java的话,可以把计数器对象做成单例,通过filter
拦截所有请求计算器加1(需要同步)。不知道你说的数据库是什么意思,{n : 100}
,n
是数据库拿的?
其实你要做的是一个常驻内存的队列,按请求先后做排队处理.
单机上可以试试Linux内存文件系统(tmpfs)上/dev/shm读写SQLite.
读文件不需要经过网络,也不需要自己实现内存常驻,锁,自增以及唯一约束.
<code><?php header('Content-Type: text/plain; charset=utf-8'); // sudo mkdir -m 777 /dev/shm/app $file = '/dev/shm/app/data.db3'; $ddl = " BEGIN; CREATE TABLE IF NOT EXISTS queue ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER ); CREATE UNIQUE INDEX IF NOT EXISTS queue_user_id_idx ON queue(user_id); COMMIT; "; if(!file_exists($file)) { //多核下多进程并发时可能都会进入到这个判断分支,所以DDL中要用IF NOT EXISTS $db = new PDO('sqlite:'.$file); $db->exec($ddl); // pdo_sqlite 的 query 和 prepare 不支持一次执行多条SQL语句 } else { $db = new PDO('sqlite:'.$file); } $stmt = $db->prepare('INSERT INTO queue(user_id) VALUES(?)'); $stmt->execute(array(time())); //time()换成你的用户ID echo $stmt->rowCount()."\n"; //查询中受影响(改动)的行数,插入失败时为0 echo $db->lastInsertId(); //插入的自增ID,插入失败时为0 // php -S 127.0.0.1:8080 -t /home/eechen/www >/dev/null 2>&1 & // ab -c100 -n1000 http://127.0.0.1:8080/</code>
最简单的是用redis的zset进行自增,效率高,简单,单机的话也可以考虑使用atomiclong(宕机重启后失效)