首页 > 如何在高并发下,http请求返回绝对的当前请求是第几个请求?

如何在高并发下,http请求返回绝对的当前请求是第几个请求?

比如,我第一次访问请求返回json:
{"n": 1}

我第100次访问请求返回json:
{"n": 100}

传统的写数据库,再查数据库返回,在并发大时好像不能保证,我应该怎么办?这应该是最简化了的问题了



最简单的是用redis的zset进行自增,效率高,简单,单机的话也可以考虑使用atomiclong(宕机重启后失效)


纯粹Java的话,可以把计数器对象做成单例,通过filter拦截所有请求计算器加1(需要同步)。不知道你说的数据库是什么意思,{n : 100},n是数据库拿的?


如果是java的话,一个全局的AtomicLong可以满足你的需求吧,getAndIncrement原子操作,再加上volatile修饰,如果是其他语言,大同小异吧


其实你要做的是一个常驻内存的队列,按请求先后做排队处理.
单机上可以试试Linux内存文件系统(tmpfs)上/dev/shm读写SQLite.
读文件不需要经过网络,也不需要自己实现内存常驻,锁,自增以及唯一约束.

<?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/

最简单的方法就是建个自增id主键的mysql表,然后每来一次请求就插一条记录,再读出这条记录,读出的id就是你要的值。

然后就可以根据id值来轻松处理高并发的场景了,比如【秒杀】就可用id小于300且能被6整除的规则认为秒杀成功;【抽奖】可以用能被100整除(百分之一概率)作为中奖等等。

如果自己实现也无非就是单线程死循环处理socket请求维护一个全局变量,不如用现成的mysql方便可靠。


使用redis中的setnx(id),单线程保证每次加1,而且还是内存数据库,速度超级快。

【热门文章】
【热门文章】