简单实现PHP对时间轮算法的方法
什么是时间轮算法?把任务放到它需要被执行的时刻,然后等待时针转到这个时刻,取出该时刻的任务,执行并将任务从该时刻删除(消费)。 解决了什么问题?以商品为例,如何实现商品的过保质期自动失效? 分层时间轮的作用?上述的例子有一个问题就是,我们的这个时间轮必须够大,才能将任务放到指定的年月日时分秒执行。这里就引入了分层时间轮的概念。 用PHP简单模拟一个时间轮来解决的场景
0、业务需求场景(FROM 滴滴)有一个APP实时消息通道系统,对每个用户会维护一个APP到服务器的TCP连接,用来实时收发消息,对这个TCP连接,有这样一个需求:“如果连续30s没有请求包(例如登录,消息,keepalive包),服务端就要将这个用户的状态置为离线”。 1、先写一个30秒一轮的时间轮,其实就是一个0到30的队列来模拟时间的推进。<?PHP
$redis = new Redis();
$redis->connect('localhost', 6379);
//$redis->auth('S'); //如果有密码要进行认证
//写一个定时器,每秒对redis的key进行查询
while (true) {
//1分钟60秒,每30秒一个循环,当作当前的index
$time = date('s')>30?date('s')/2:date('s');
$set_key = $redis->lindex('testlist',(int)$time);
//清空当前key中的slot的值,并将用户u_id设置为离线
if($redis->exists($set_key)){
$uid = $redis->smembers($set_key);
//对uid进行处理
foreach ($uid as $value) {
//将用户设置为离线并记录日志
file_put_contents('offline.txt', $value.'离线了'.PHP_EOL,FILE_APPEND);
//移出当前slot
$redis->srem($set_key,$value);
}
}
sleep(1);
}?>2、写一个模拟用户登录的系统function connect(){
$redis = new Redis();
$redis->connect('localhost', 6379);
// $redis->auth('S');
return $redis;}function init(){
$redis = connect();
//初始化,只执行一次,维护一个初始的list
if(!$redis->exists('testlist')){
for ($i=0; $i <=30; $i++) {
$redis->lpush('testlist','slot-'.$i);
}
}}function login(){
$redis = connect();
//写一个登录系统,用户登录后记录日志,并放到定时器中
$uid = 666666;
//根据hash查找到当前用户uid对应的index
$index = $redis->hget('timeline-index',$uid);
if($index){
//删除当前用户的slot_index,避免过期
$redis->srem($index,$uid);
}
//放到新的index里,并记录当前用户对应的index
$time = date('s')>30?date('s')/2:date('s');
$time = $time>0?$time-1:30;
//从队列获取当前的插槽
$set_key = $redis->lindex('testlist',(int)$time);
//插入插槽并记录index
$redis->sadd($set_key,$uid);
$redis->hset('timeline-index',$uid,$set_key);
file_put_contents('online.txt', $uid.'上线了'.PHP_EOL,FILE_APPEND);}init();login();3、数据结构介绍主要使用了redis的list数据结构做环形队列,redis的set结构做任务存储,redis的hash结构做uid和用户所在set结构所处的index映射。 4、执行流程介绍登录流程:用户每次登录,都会把用户离线任务所在的时间轮查到,然后删除,避免时间轮执行到任务,把用户置为离线状态。然后给用户分配当前秒数的前一秒作为下次过期的时间,这样,下次执行到这个任务又是30秒。最后将index和uid做好映射关系。 (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
