redis实现延时队列

1、怎么使用redis实现延时队列

我们通过redis的有序集合zset来实现简单的延迟队列,将消息数据序列化,作为zset的value,把消息处理时间作为score,每次通过zRangeByScore获取一条消息进行处理。

class DelayQueue
{
protected $prefix = ‘delay_queue:’;
protected $redis = null;
protected $key = ‘’;

public function __construct($queue, $config = [])
{
    $this->key = $this->prefix . $queue;
    $this->redis = new Redis();
    $this->redis->connect($config['host'], $config['port'], $config['timeout']);
    $this->redis->auth($config['auth']);
}

public function delTask($value)
{
    return $this->redis->zRem($this->key, $value);
}

public function getTask()
{
    //获取任务,以0和当前时间为区间,返回一条记录
    return $this->redis->zRangeByScore($this->key, 0, time(), ['limit' => [0, 1]]);
}

public function addTask($name, $time, $data)
{
    //添加任务,以时间作为score,对任务队列按时间从小到大排序
    return $this->redis->zAdd(
        $this->key,
        $time,
        json_encode([
            'task_name' => $name,
            'task_time' => $time,
            'task_params' => $data,
        ], JSON_UNESCAPED_UNICODE)
    );
}

public function run()
{
    //每次只取一条任务
    $task = $this->getTask();
    if (emptyempty($task)) {
        return false;
    }
    $task = $task[0];
    //有并发的可能,这里通过zrem返回值判断谁抢到该任务
    if ($this->delTask($task)) {
        $task = json_decode($task, true);
        //处理任务
        echo '任务:' . $task['task_name'] . ' 运行时间:' . date('Y-m-d H:i:s') . PHP_EOL;
        return true;
    }
    return false;
}

}

$dq = new DelayQueue(‘close_order’, [
‘host’ => ‘127.0.0.1’,
‘port’ => 6379,
‘auth’ => ‘’,
‘timeout’ => 60,
]);
$dq->addTask(‘close_order_111’, time() + 30, [‘order_id’ => ‘111’]);
$dq->addTask(‘close_order_222’, time() + 60, [‘order_id’ => ‘222’]);
$dq->addTask(‘close_order_333’, time() + 90, [‘order_id’ => ‘333’]);

然后,我们写一个php脚本,用来处理队列中的任务。

<?php set_time_limit(0); $dq = new DelayQueue('close_order', [ 'host' => '127.0.0.1', 'port' => 6379, 'auth' => '', 'timeout' => 60, ]); while (true) { $dq->run(); usleep(100000); } 2、为什么缓存比mysql并发好 一、 Redis 的数据操作方式不同于 MySQL 在数据操作方式的角度来看,Redis 以内存为存储介质,数据的读写速度快于传统的关系型数据库 MySQL。在实际应用中,Redis 只需要将数据一次性写入内存中,之后对数据的读取及修改则可以在内存中高效地执行,避免了磁盘寻道时间等硬盘操作时间带来的延迟,从而实现了高速访问、高效处理等功能。 相比之下,MySQL 的磁盘操作量较大,在进行数据读取、修改等操作时,需要查询硬盘中的数据,然后再将其加载至内存中进行处理。由于磁盘读写速度相对较慢,这样的操作就会导致 MySQL 的响应速度变慢,而 Redis 的操作则具有更快的响应时间。 二、 Redis 支持数据分片方式的分布式缓存 在分布式架构的场景下,Redis 通过数据分片的方式对数据进行分布式处理,从而使多个 Redis 节点可以分摊数据操作,提高了系统的整体稳定性及可靠性,也使得 Redis 在大规模应用方面甚至可以替代 MySQL。 在实际生产环境中,如果以 MySQL 作为数据存储,其通常由主从服务器双机部署来保证数据的高可用性,但随着数据量增大,主从复制的性能瓶颈以及单机并发量的限制将会变得更加明显,也会导致整体的响应速度降低,而 Redis 则不会出现这种情况,因为其支持数据分片方式的分布式缓存,充分发挥了其高并发处理性能。 三、 Redis 支持更多的数据类型 在数据类型的角度来看,Redis 支持数据类型更加丰富,并且每一种数据类型都可以进行丰富的操作。在实际使用中,开发者可以灵活地调用 Redis 中的数据类型,以实现不同的业务需求,从而提高程序的处理性能。 例如,Redis 不仅仅支持字符串、列表、散列表、集合、有序集合等传统的数据类型,还支持地理位置类型,Bitmap 数据类型等等,而这些数据类型提供了更多的操作功能,充分发挥了 Redis 的优势,帮助企业实现高速缓存、数据计算等多种功能。 3、php有哪些运行方式,为什么能在nginx上运行 命令行方式运行PHP 在命令行运行PHP是最简单的方式之一。它适用于那些不需要与Web服务器、浏览器或其他Web应用程序进行交互的应用程序。只需打开终端,输入"php"命令即可。例如: 1 php -r 'echo "Hello, world!";' 这将输出"Hello, world!"。此外,您还可以在运行时指定PHP文件。例如: 1 php my_program.php 命令行方式运行PHP非常方便,但它不能与Web服务器交互,因此它不适用于需要动态生成Web页面的应用程序。 模块方式运行PHP Apache服务器是目前最流行的Web服务器之一,如果您想要将PHP与Apache搭配使用,您需要安装PHP模块。安装成功后,PHP脚本可以与Web浏览器一起使用。Apache服务器会自动将请求发送给PHP模块进行处理。模块方式运行PHP的优点是,它非常快速且易于部署;缺点是,它无法对于每一个PHP文件进行独立的设置,因此可能不够灵活。 CGI方式运行PHP 在CGI模式下,PHP脚本由Web服务器调用并执行。当浏览器发送PHP请求时,Web服务器会调用PHP解释器解析PHP文件,并在处理请求后将其发送回浏览器。CGI方式运行PHP的优点是可靠性高及可维护性强,因为每个PHP文件都可以单独配置;缺点是CGI比其他方法更慢,因为每个请求都需要启动和关闭PHP进程。同时,在处理大量请求时,CGI也可能会占用太多的服务器资源。 FastCGI方式运行PHP FastCGI与CGI非常相似,但它可以重用解释器进程,从而更快地处理请求。FastCGI是一种可扩展性较高的CGI方式,支持多个进程同时运行。在FastCGI下,解释器进程(PHP-FPM)作为单独的服务运行,Web服务器与之通信并将其处理结果返回给浏览器。FastCGI模式下运行PHP的优点是速度较快,同时可以通过更改进程配置文件调整进程数量,来适应并发请求处理的需求。但是需要注意,如果配置不当,它可能会占用更多的系统资源。 4、php在语言层面可以做到异步吗 使用多线程 使用多线程是一种常见的异步编程方式。可以通过PHP的PTHREAD扩展库实现多线程,这个扩展提供了一些类和接口,可以使用PHP语言来创建线程和执行多线程程序。 由于多线程程序存在一些问题,比如线程间共享数据、数据同步和死锁等,因此使用多线程需要特别小心。 使用无阻塞式I/O 无阻塞式I/O是另一种常见的异步编程方式。当程序需要执行一个I/O操作时,程序不会等待I/O操作完成,而是继续执行下一个任务。当I/O操作完成后,程序再回来处理这个I/O操作的结果。在PHP中,可以使用非阻塞式I/O实现异步编程。 使用事件驱动编程 PHP提供了一些扩展库,例如libevent,可以实现事件驱动编程。事件驱动编程的主要思想是,程序可以同时监听多个事件,当事件发生时,程序会调用相应的回调函数。 使用事件驱动编程可以让程序变得高效、可扩展,并且易于维护。 使用协程 协程是一种用户态轻量级线程,可以在程序中实现高效的并发操作。协程使用的原理是在程序中主动让出CPU的执行权,让其他任务先执行。在PHP中,可以使用swoole扩展实现协程。 5、php怎么是处理高并发的。 使用异步框架:通过使用异步处理方式,可以有效地降低 PHP 处理请求的响应时间,避免因为 IO 操作而导致的等待阻塞。常用的异步框架有ReactPHP和Swoole等。 使用缓存:使用缓存可以减少每个请求都需要访问数据库或文件系统的次数,有效地提高响应速度。可以使用Redis、Memcached等缓存工具来解决高并发请求的问题。 分布式架构:对于访问量非常大的应用,可以采用分布式架构来提高系统的响应性能,通过将请求分配到多个服务器上进行并行处理来提高并发能力。 负载均衡:通过使用负载均衡器,可以将请求均衡地分配到不同的服务器上进行处理,保证每个服务器的负载均衡,从而提高系统的可靠性、可扩展性和并发能力。 数据库优化:使用主从库、索引、分区等技术来提高数据库的读写性能,减少数据库的访问压力,从而提高系统的响应速度。 6、具体说下文件的上传过程,php以什么方式接收文件的,是怎么存在服务器的。 表单提交: 需要将请求的method设置为post请求。 需要设置编码类型为enctype=multipart/form-data,form表单用了enctype="multipart/form-data"类型后,所有的值都将以二进制的形式进行传递的,都将以这个游戏规则进行。 服务器接收文件:   $_FILES多维数组,用于存储各种与上传有关的信息 PHP文件上传处理函数,用于成功上传文件后的后续处理 is_uploaded_file()函数 判断指定的文件是否是通过HTTP上传的 move_upload_file()函数 文件上传成功后,会率先存储在服务器的临时目录当中去,这个函数可以让我们将上传在临时路径的文件移到指定的位置。 <? header('Content-type:text/html;charset=utf-8'); date_default_timezone_set('Asia/Shanghai');//设置东部时区 if(isset($_POST["submit"])) { //判断用户是否点击了开始上传按钮 if(is_uploaded_file($_FILES["uploadFile"]["tmp_name"])){//判断该文件是否是通过HTTP的POST方法上传的 //上传成功 $arr = pathinfo($_FILES["uploadFile"]["name"]); //获取文件名信息 $newFileName = date('YmdGis').rand(1000,9999); //以时间作为文件的命名,随机数避免同一时间的冲突 if(move_uploaded_file($_FILES["uploadFile"]["tmp_name"],"upload/{$newFileName}.{$arr['extension']}")){ //将暂时存储的的上传文件移到新位置,并且拼接上源文件的文件名和拓展名 echo "上传成功!"; }else { echo "移到文件失败!"; } }else { exit("上传失败!"); } //var_dump($_FILES);//相当于console输出某个对象信息 } ?> 上传文件 7、魔术方法__call是做什么的,是怎么实现自动加载的,除了__autoload还有什么。

__call是魔术方法中的一个,当程序调用到当前类中未声明或没权限调用的方法时,就会调用__call方法

自动加载,除了__autoload还有spl_autoload_register()

8、redis的list、set、zset有什么区别。

9、数据结构的顺序表和链表有什么区别,从有序的顺序表查找某个元素的最短时间复杂度为多少。

顺序表的特点是逻辑上相邻数据元素,物理存储位置相邻,并且顺序表的存储空间需要预先分配,存储空间是静态分配的。

优点:
顺序表具有按数组下标随机访问的特点。
不用为表示节点间的逻辑关系而增加额外的存储开销
缺点:
在顺序表中做插入、删除操作时,需要遍历数组元素,当数组元素较大时,顺序表效率低。
静态分配,程序执行之前必须明确规定存储规模预先分配足够大的存储空间,估计过大,可能会导致顺序表后部大量闲置;预先分配过小,又会造成溢出。

在链表中逻辑上相邻的数据元素,物理存储位置不一定相邻,它使用指针实现元素之间的逻辑关系。并且链表的存储空间是动态分配的。

优点
插入、删除运算方便。
缺点
链表不是一种随机存储结构,不能随机存取元素。
要占用额外的存储空间存储元素之间的关系,存储密度降低。

顺序表按值查找的时间复杂度是O(n),因为在按值查找时,需要按顺序扫描整个表来查找所需的值。如果表中有n个元素,则需要比较n次才能找到所需的值。

顺序表按位查找的时间复杂度是O(1),因为在按位查找时,可以直接访问表中的某个位置的元素,无需按顺序扫描整个表。所以,无论表中有多少元素,按位查找的时间复杂度都是O(1)。

10、从顺序表查找某个元素,如果查询十万次,有什么方法可以缩短查询时间。

一次性查询所有元素的位置,存一个哈希表。

11、如何解决mysql千万级别的数据表查询缓慢的问题?

https://www.cnblogs.com/wsablog/articles/17769770.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值