123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- <?php
- /**
- * Created by PhpStorm.
- * User: wangfanchang
- * Date: 18/4/24
- * Time: 上午11:06
- */
- namespace app\admin\command;
- use app\common\library\Redis;
- use app\common\model\User;
- use app\main\constants\CacheConstants;
- use think\console\Command;
- use think\console\Input;
- use think\console\input\Option;
- use think\console\Output;
- use think\Config;
- use app\common\model\Book;
- use think\Db;
- use think\Log;
- use think\Request;
- class RedisToMysql extends Command
- {
- protected function configure()
- {
- $this
- ->setName('redisToMysql')
- ->addOption('type', 't', Option::VALUE_OPTIONAL, '要处理的缓存类型,all:默认全部处理,bn:书籍阅读数,ubc:用户行为标签, quv:自定义二维码UV统计', 'all')
- ->setDescription('将redis缓存中的数据存入mysql数据库');
- }
- protected function execute(Input $input, Output $output)
- {
- Request::instance()->module('admin'); //cli模式下无法获取到当前的项目模块,手动指定一下
- $type = $input->getOption('type');
- switch ($type) {
- case 'all':
- $this->customQrCodeUvCollect($input, $output);
- $output->writeln("Type: all 全部处理");
- $this->bn($input, $output);
- // //0408 去掉用户喜好字段维护
- //$this->ubc($input, $output);
- break;
- case 'bn':
- $output->writeln("Type: bn 书籍阅读数");
- $this->bn($input, $output);
- break;
- case 'ubc':
- // //0408 去掉用户喜好字段维护
- // $output->writeln("Type: ubc 用户行为标签");
- // $this->ubc($input, $output);
- $output->writeln("Type: ubc 用户行为标签停止维护");
- break;
- case 'quv':
- $output->writeln("Type: quv 自定义二维码UV");
- $this->customQrCodeUvCollect($input, $output);
- break;
- default:
- $output->writeln("Type: {$type} 无法识别的类型");
- }
- $output->writeln("处理完毕!");
- }
- /**
- * 处理自定义二维码 UV 统计
- * @param Input $input
- * @param Output $output
- */
- private function customQrCodeUvCollect(Input $input, Output $output)
- {
- try {
- $output->writeln("处理自定义二维码UV统计---开始");
- Log::info("处理自定义二维码UV统计---开始");
- $redis = Redis::instance();
- Db::table('custom_qrcode')->chunk(100, function ($result) use ($redis) {
- foreach ($result as $val) {
- if ($uv = $redis->pfCount("QR_UV:{$val['admin_id']}:{$val['index']}")) {
- $is_update = model('CustomQrcode')->where('id', $val['id'])->update(['uv' => $uv]);
- if ($is_update !== false) {
- Log::info("处理自定义二维码UV统计: id:{$val['id']} set uv:{$uv} success");
- } else {
- Log::error("处理自定义二维码UV统计: id:{$val['id']} set uv:{$uv} fail");
- }
- }
- }
- sleep(5);
- });
- $output->info("处理自定义二维码UV统计---完成");
- Log::info("处理自定义二维码UV统计---完成");
- } catch (\Exception $e) {
- $output->writeln('处理自定义二维码UV统计---失败' . $e->getMessage());
- Log::error('处理自定义二维码UV统计---失败' . $e->getMessage());
- }
- }
- /**
- * 链接redis
- */
- private function connect($idx)
- {
- $redis = null;
- $config = Config::get('redis');
- $list = explode(';', $config['list']); //共n个redis
- foreach ($list as $item) {
- $con = explode('=', $item); // 0 编号 1 配置
- if (count($con) >= 2) {
- if ($con[0] == $idx) {
- $c = explode(':', $con[1]); //配置 0IP 1端口 2密码 3库编号
- if (count($c) >= 2) {
- $redis = new \Redis();
- if ($config['pconnect']) {
- $redis->pconnect($c[0], $c[1], $config['timeout']);
- } else {
- $redis->connect($c[0], $c[1], $config['timeout']);
- }
- if (count($c) >= 3 && $c[2]) {
- $redis->auth($c[2]);
- }
- if (count($c) >= 4 && is_numeric($c[3])) {
- $redis->select($c[3]);
- }
- }
- return $redis;
- }
- }
- }
- return $redis;
- }
- /**
- * 根据key获取redis编号
- * @param $key
- */
- private function getRedis($key)
- {
- $default = Config::get('redis.default', 0); //默认redis编号
- $rules = Config::get('redis.rules');
- $list = explode(';', $rules);
- foreach ($list as $item) {
- $con = explode('=', $item); // 0 编号 1 配置
- if (count($con) >= 2) {
- $c = explode(',', $con[1]); //规则
- foreach ($c as $it) {
- if ($it) {
- if (strpos($key, $it) === 0) { //查找到,且必须为第一个0
- $default = $con[0];
- break 2;
- }
- }
- }
- }
- }
- return $this->connect($default);
- }
- /**
- * 处理书籍阅读数
- */
- private function bn(Input $input, Output $output)
- {
- $output->writeln("处理书籍阅读数---开始");
- Log::info("处理书籍阅读数---开始");
- $key = 'B-N';
- $redis = $this->getRedis($key);
- if ($redis) {
- $hash = $redis->hGetAll($key);
- $model = new Book();
- $i = 0;
- foreach ($hash as $book => $num) {
- $data = [
- 'read_num' => ['exp', "`read_num`+{$num}"]
- ];
- $model->update($data, ['id' => $book]);
- $redis->hDel($key, $book);
- $redis->del('B:' . $book);
- $redis->del(CacheConstants::BOOK_USER_READ_COUNT . $book);
- $i++;
- if ($i % 1000 === 0) { //每处理1000个hash name 延时1秒
- $output->writeln("处理书籍阅读数---处理1000个,延时1秒");
- Log::info("处理书籍阅读数---处理1000个,延时1秒");
- sleep(1);
- }
- }
- } else {
- $output->writeln("处理书籍阅读数---实例化redis错误!");
- Log::error("处理书籍阅读数---实例化redis错误!");
- }
- $output->writeln("处理书籍阅读数---完毕");
- Log::info("处理书籍阅读数---完毕");
- }
- /**
- * 用户行为标签
- */
- private function ubc(Input $input, Output $output)
- {
- $output->writeln("处理用户行为标签---开始");
- Log::info("处理用户行为标签---开始");
- Redis::instance();
- $key = 'U-BC:';
- $modKeyRules = Config::get('redis.modkeyrules');
- $aModKeyRules = explode(',', $modKeyRules);
- if (in_array($key, $aModKeyRules)) {
- //获取所有取模模式的redis服务器信息
- $strModKeyList = Config::get('redis.modkeylist');
- $aModKeyItem = explode(';', $strModKeyList);
- $aModKeyServerNum = [];
- array_walk($aModKeyItem, function ($v) use (&$aModKeyServerNum) {
- $aItem = explode('=', $v);
- $aModKeyServerNum[] = $aItem[0];
- });
- array_walk($aModKeyServerNum, function ($v) use ($output) {
- $redis = Redis::getRedisConnect($v);
- if (empty($redis)) {
- $output->writeln("处理用户行为标签---实例化redis错误!redisIndex:$v");
- Log::info("处理用户行为标签---实例化redis错误!redisIndex:$v");
- } else {
- $this->processUserTag($redis, $output);
- }
- });
- } else {
- $redisIndex = Redis::getRedisIndex($key);
- $redis = Redis::getRedisConnect($redisIndex);
- if (empty($redis)) {
- $output->writeln("处理用户行为标签---实例化redis错误!redisKey:$key");
- Log::info("处理用户行为标签---实例化redis错误!redisKey:$key");
- } else {
- $this->processUserTag($redis, $output);
- }
- }
- $output->writeln("处理用户行为标签---完毕");
- Log::info("处理用户行为标签---完毕");
- }
- /**
- * @param \Redis $redis
- * @param Output $output
- */
- private function processUserTag($redis, Output $output)
- {
- $pattern = 'U-BC:*';
- $cursor = null;
- $i = 0;
- while ($cursor !== 0) {
- $keys = $redis->scan($cursor, $pattern, 500);
- if (is_array($keys) && count($keys)) {
- foreach ($keys as $value) {
- $ids = $redis->get($value);
- $id = preg_replace('/\D/s', '', $value);
- if ($ids && $id && is_numeric($id)) {
- $model = new User();
- $model->setConnect($id)->update(['book_category_ids' => $ids], ['id' => $id]);
- unset($model);
- }
- $redis->del($value); //删除key
- $i++;
- if ($i % 1000 === 0) { //每处理1000个key 延时1秒
- $output->writeln("处理用户行为标签---处理1000个,延时1秒");
- Log::info("处理用户行为标签---处理1000个,延时1秒");
- sleep(1);
- }
- }
- }
- }
- }
- }
|