PHP使用SW-X框架的Redis-UML组件,对用户信息进行缓存读写

会挽雕弓如满月,西北望,射天狼。这篇文章主要讲述PHP使用SW-X框架的Redis-UML组件,对用户信息进行缓存读写相关的知识,希望能为你提供帮助。
前言
官网地址:??SW-X框架-专注高性能便捷开发而生的PHP-SwooleX框架??
希望各大佬举起小手,给小弟一个star:??https://github.com/swoolex/swoolex??


1、Redis-UML介绍
Redis-UML组件,类似于游戏项目中的人物建模,它是一种面向单个数据表创建缓存模型的概念。UML有着类似于mysql-ORM的便捷操作语法支持,同时可自由开关数据更新时的缓存刷新标记,用于读取更新的缓存对象都有哪些,便于将缓存内容回写到数据库中。
2、UML的初衷
由于项目业务需要用到Reids缓存Mysql的更热新数据,进而减少数据库在??update??与??select??时对单个数据表的频繁操作(这样的高频操作往往会将整个Mysql服务器的性能拖垮)。
在以前,我们通常会这样实现:

$Db  =  new  \\x\\Db();
$Redis  =  new  \\x\\Redis();
//  先查询数据库
$user  =  $Db-> name(user)-> where(id,  1)-> find();
//  再更新到redis
$res  =  $Redis-> hmset($key.$user[id],  $user);

//  需要获得该数据缓存的时候,就需要这样拿
$user  =  $Redis-> hgetall($key.$user[id]);

该过程看似没有问题,但却只实现了对update场景的优化,实际上并没有解决select的场景,因为往往在业务过程中,select占据了最频繁的位置。因为一旦将update由缓存代替后,那Mysql查出的数据将不一定是最新的,这时候只能依赖缓存查询,而传统的实现方式又只能实现单条缓存读取,就变成了下面的读取方式:
$Db  =  new  \\x\\Db();
$Redis  =  new  \\x\\Redis();
//  先查数据库
$list  =  $Db-> name(user)-> field(id)-> where(region_code  =  430000)> where(status  =  1  OR  status  =  3)-> select();
//  再循环从Redis中获得
foreach  ($list  as  $k=> $v) 
//  指定需要返回的字段名
$list[$k]  =  $Redis-> hmget($key.$v[id],  [id,  name,  phone]);

而UML组件的出现,就是为了解决这样的业务场景。
$User  =  new  \\box\\uml\\User();
//  查询条件
$where  =  [];
$where[]  =  [region_code,  =,  430000];
$where[]  =  [status,  =,  [1,  3]];
//  直接从查询中获得
$list  =  $User-> where($where)-> field(id,  name,  phone)-> select();
//  你还可以写成
$list  =  $User-> field(id,  name,  phone)
                -> where(status,  430000)
                -> where(region_code,  [1,  3])
                -> limit(1000)
                -> order(id  DESC,  phone  ASC)
                -> select();

3、UML的优缺点
A、优点
1、UML支持类似Mysql-ORM的查询语法,所以它可以很轻易的接替Mysql的大部分日常读写工作。
2、UML是由多种Redis数据结构组合而成的查询组件,其中查询条件可以根据模型进行配置,类似于查询索引的概念,可以很好的控制缓存所占用的内存开销。
3、UML支持开启缓存回写的数据标记,配合定时器组件很容易就能实现Redis  对  Mysql的缓存回写。

B、缺点
1、UML不具备事务性,与Redis的hset一样,当不开启Redis事务时,无法保证数据的并发修改。
2、UML的like模糊匹配时把记录集从缓存中检索出来后,再进行遍历匹配的,所以这块会存在一定的内存开销,使用该查询支持时需要对前置的数据量进行一定的限制,否则很可能会引起大量的内存开销。

4、条件语法的优先级
UML的查询逻辑跟Mysql-ORM的不同,语法存在执行优先级的关系。UML的查询逻辑,共有4种,分别为:??id()??、??geo()??、??where()??、??like()??。
执行优先级为:
当使用id()时,表示后续三种条件均不再使用,只操作主键数据。

当使用geo()时,表示先从Redis-Geo中查询数据,再从返回的数据中通过条件where()、like()再次过滤。

当同时使用where()和like(),再表示根据where()查询出数据,再在php内存中进行like()匹配过滤。

注意:UML中不允许获得整个记录表的信息,因为那样需要keys(*)的操作,组件是不允许的。
5、创建测试模型
由于UML组件是基于Redis连接池实现的,所以需要先到??/config/redis.php??配置文件中,修改Redis对应的连接参数。
该案例,是对标一个??司机-用户信息表??,名称为:??Driver??,存储位置:??\\app\\uml\\Driver.php??:
namespace  app\\uml;
use  x\\redis\\UML;

class  Driver  extends  UML

        /**
          *  使用的Redis连接池标识
        */
        protected  $driver  =  default;
        /**
          *  使用哪个Redis表存储
        */
        protected  $database  =  12;
        /**
          *  是否开启回写记录
        */
        protected  $timer  =  true;
        /**
          *  主键字段
        */
        protected  $primary  =  id;
        /**
          *  建模必传对象
        */
        protected  $field_rule  =  [
                id,  //  主键值
                driver_sn,  //  编号
                status,  //  状态    1.在线空闲  2.在线工作中    3.离线
                region_id,  //  地区ID
                real_name,  //  真实姓名
                lng,  //  经度
                lat,  //  纬度
                add_time,  //  添加时间
        ];
        /**
          *  普通查询规则
        */
        protected  $query_rule  =  [
                id  =>   [equal],  //  等于查询
                status  =>   [equal],  //  等于查询
                region_id  =>   [equal,  range],  //  等于查询  OR  范围查询
                driver_sn  =>   [equal],  //  等于查询
                real_name  =>   [equal],  //  等于查询
                add_time  =>   [range],  //  日期查询
        ];
        /**
          *  geo配置规则
        */
        protected  $geo_rule  =  [
                longitude  =>   lng,  //  经度
                latitude  =>   lat,  //  纬度
        ];

6、通过HTTP服务,创建测试数据
HTTP服务的,??/app/http/Index.php??控制器,写入以下代码:
namespace  app\\http;
use  x\\controller\\Http;
use  app\\uml\\Driver;

class  Index  extends  Http

        /**
          *  @RequestMapping(route="/test1")
        */
        public  function  index() 
                //  生成随机数据
                $all  =  [];
                $time  =  time();
                //  10W测试
                for  ($i=0;   $i< =100000;   $i++) 
                        $all[]  =  [
                                id  =>   ($i+1),
                                status  =>   rand(1,  3),
                                driver_sn  =>   substr(md5($i),  0,  2).$i,
                                region_id  =>   rand(100,  200),
                                real_name  =>   \\x\\built\\Str::randChinese(),
                                lng  =>   \\x\\common\\Money::randomFloat(113.100000,  116.999999,  6),
                                lat  =>   \\x\\common\\Money::randomFloat(23.100000,  25.999999,  6),
                                add_time  =>   $time+$i,
                        ];
               
                $Driver  =  new  Driver();
                $num  =  $Driver-> insertAll($all,  5000);
                return  $this-> fetch($num);
       

重启服务,浏览器访问??http://IP:端口/test1??,运行脚本。


【PHP使用SW-X框架的Redis-UML组件,对用户信息进行缓存读写】 建议:上面的脚本我是用??3核+8G??的机器一起跑完的【大概需要个30秒,不要惊慌】,如果配置更差的同学记得自己修改测试量,或者分批运行,不要逞强。
7、UML语法测试
HTTP服务的,??/app/http/Index.php??控制器,改为以下代码:
namespace  app\\http;
use  x\\controller\\Http;
use  app\\uml\\Driver;

class  Index  extends  Http

        /**
          *  @RequestMapping(route="/test2")
        */
        public  function  index() 
                $html  =  ;

                //  统计内存
                $StartMemory  =  memory_get_usage();
                //  统计耗时
                $StartTime  =  microtime(true);

                $Driver  =  new  Driver();
                //  查询ID等于3的数据
                $info  =  $Driver-> id(3)-> find();
                $html  .=  场景一:.dd($info);
                //  将其修改为工作中
                $res  =  $Driver-> id(3)-> update([
                        status  =>   2
                ]);
                $html  .=  场景二:.dd($res);
                //  查询在线,并且地区在150的司机
                $list  =  $Driver-> where(status,  [1,  2])-> where(region_id,  150)-> select();  
                $html  .=  场景三:.dd(count($list));
                //  查询在线,并且地区在150,同时要是姓林的司机
                $list  =  $Driver-> where(status,  [1,  2])-> where(region_id,  150)-> like(real_name,  林,  %s)-> select();  
                $html  .=  场景四:.dd(count($list));
                //  查询在线,并且在geo半径5公里内,地区在100  -  120  之间的司机
                $list  =  $Driver-> geo(113.402618,  23.149329,  5)-> where(status,  [1,  2])-> where(region_id,  range,  [100,  120])-> select();
                $html  .=  场景五:.dd(count($list));

                $StopTime  =  microtime(true);
                $TimeSpent=$StopTime-$StartTime;
                $html  .=  dd(上述总耗时:.number_format($TimeSpent*1000,  4).毫秒);
                $StopMemory  =  memory_get_usage();
                $Memory  =  $StopMemory-$StartMemory;
                $html  .=  dd(上述总耗内存:.$this-> formatSize($Memory));

           

    推荐阅读