Redis实现缓存点赞思路
纵所周知,优酷和抖音这类直播平台都会有点击屏幕就点赞的功能,这类不太重要的数据,交给redis处理是最优的,定时存入MySQL数据库中,就可以实现数据的持久化。
本博基于tp6框架技术,结合think-queue
消息队列,middleware
中间件。
实现redis向mysql点赞的同步。本博使用消息队列:
composer require topthink/think-queue
一、controller层
主要是将前端的数据存到redis之中,用redis的哈希表储存;
redis的哈希表存储键值对:cache()->hset(‘v5_like_num’, ‘user_1’,0);
redis的哈希表获取键值对:cache()->hget(‘v5_like_num’, ‘user_1’);
redis的哈希表步进value值:cache()->hincrby(‘v5_like_num’, ‘user_1’, ‘步进的整数’);
namespace app\v5\controller;
use app\BaseController;
use think\facade\Db;
/**
* redis点赞
*/
class Redis extends BaseController
{
/**
* 显示视图:这里的视图只是为了方便展示
*/
public function index()
{
$data['res'] = Db::table('v5_like_num')->select()->toArray();
$data['redis_like_num'] = cache()->hget('v5_like_num', 'user_1');
// halt($data);
return view('redis/index', $data);
}
/**
* 添加数据到redis接口
*/
public function add()
{
$step = (int)request()->post('step', 0);
//添加redis
cache()->hincrby('v5_like_num', 'user_1', $step);
// dump($step);
// dump(cache()->hget('v5_like_num', 'user_1'));
}
}
视图层参考:view/redis/index
源码:https://github.com/xiaopacairq/tpAdmin/blob/main/app/v5/view/redis/index.php
核心代码如下:
// 点赞攒值,每3秒缓存到redis一次
setInterval(function() {
$.post('/v5/redis/add', {
step,
}, function(res) {
step = 0;
}, '')
}, 3000)
二、数据库层
- Mysql数据库
- Reids数据库
三、Job工作类
- queue的配置选项
config/queue.php
,默认是sync同步执行,可修改为redis缓存
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
return [
'default' => 'redis',
'connections' => [
'sync' => [
'type' => 'sync',
],
'database' => [
'type' => 'database',
'queue' => 'default',
'table' => 'jobs',
'connection' => null,
],
'redis' => [
'type' => 'redis',
'queue' => 'default',
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
'select' => 0,
'timeout' => 0,
'persistent' => false,
],
],
'failed' => [
'type' => 'none',
'table' => 'failed_jobs',
],
];
编写Job工作类,可参考文档:https://packagist.org/packages/topthink/think-queue
具体工作内容:将redis缓存的数据定时5秒存入到mysql中
<?php
namespace app\job;
use think\queue\Job;
use think\facade\Db;
class Job1
{
public function fire(Job $job, $data)
{
$isJob = $this->redisToMysql($data);
if ($isJob) {
$job->delete();
} else {
//通过这个方法可以检查这个任务已经重试了几次了
$attempts = $job->attempts();
if ($attempts == 0 || $attempts == 1) {
// 重新发布这个任务
$job->release(5); //$delay为延迟时间,延迟5S后继续执行
} elseif ($attempts == 2) {
$job->release(5); // 延迟5S后继续执行
}
}
}
public function failed($data)
{
// ...任务达到最大重试次数后,失败了
}
private function redisToMysql($number)
{
//将redis数据存入到mysql数据库当中
$isAdd = Db::table('v5_like_num')
->where('title', '文章1')
->inc('like_num', $number)
->update();
if ($isAdd) {
return true;
} else {
return false;
}
}
}
四、middleware中间件
中间件工作:定时执行队列
Queue::later(5, 'Job1@fire', $number, 'jobdemo');
队列工作时,需要在命令行执行:php think queue:work --queue jobdemo
- 注册中间件
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class,
// 初始化消息中间件
app\v5\middleware\RedisToMysql::class,
];
- 实现中间件
<?php
namespace app\v5\middleware;
use think\facade\Queue;
class RedisToMysql
{
public function handle($request, \Closure $next)
{
$number = (int)cache()->hget('v5_like_num', 'user_1');
//执行队列
$isPushed = Queue::later(5, 'Job1@fire', $number, 'jobdemo');
if ($isPushed) {
cache()->hset('v5_like_num', 'user_1', 0); //队列执行成功,让点赞步进值为0
}
return $next($request);
}
}
执行php think queue:work --queue jobdemo
,只有出现processed状态,才算队列执行成功,一直是processing状态,大概率是Job工作类写错了!
实现结果是:
- 前端点赞,3秒后传入到后端接口
- 后端接口将前端的点赞集合缓存到redis
- 中间件每隔5秒自动将redis的数据缓存到mysql,并清空redis缓存
本博到此结束,thinkphp,以及勤劳的自己!