


A Cache callback and automatic triggering technology based on PHP_PHP tutorial
Jul 13, 2016 am 10:12 AMA Cache callback and automatic triggering technology based on PHP
Background
When using Memcache or Redis in PHP, we usually encapsulate Memcache and Redis and write a Cache class separately as a proxy for Memcache or Redis, and Generally singleton mode. In the business code, when using the Cache class, the basic sample code of the operation is as follows
// cache 的 key $key = 'this is key'; $expire = 60;// 超時時間 // cache 的實(shí)例 $cache = Wk_Cache::instance(); $data = $cache->fetch($key); // 判斷data if(empty($data)){ // 如果為空,調(diào)用db方法 $db = new Wk_DB(); $data = $db->getXXX(); $cache->store($key, $data, $expire); } // 處理$data相關(guān)數(shù)據(jù) return $data;
The basic process is
Step 1 , first assemble the query key and query the value in Cache. If it exists, continue processing and enter the third step; if it does not exist, enter the second step
The second step is to query the relevant data in the DB according to the request. If the data exists, put the data into the Cache
The third step is to process the data returned in the cache or db
Problem
The above process will basically appear in every call to the Cache. Query the cache first. If not, call the DB or third-party interface to obtain the data, store it in the cache again, and continue data processing. Since multiple calls are a problem, this query method should be encapsulated into a lower-level method. Instead of repeating such logic every time, in addition to encapsulation issues, there are other issues. Let’s list them together
First: from a design perspective, repeated code requires lower-level logic encapsulation.
Second: The assembly of the key is cumbersome and cumbersome. In actual situations, various parameters may be assembled. During maintenance, you dare not modify it.
Third: The set expire timeout will be scattered in various logical codes, making it difficult to calculate the Cache cache time in the end.
Fourth: Since the cache->store method needs to be executed after calling the db, if there are other logical processes after the db, it is possible to forget to put the data into the cache, resulting in data loss.
Fifth: In a high-concurrency system, when the cache fails, a large number of requests will directly penetrate to the rear, causing the pressure on the DB or third-party interface to rise sharply, slowing down the response, and further affecting the stability of the system. This phenomenon for "Dogpile".
Among the above problems, the simplest ones are 2 and 3. For the problem of scattered expire timeouts, we can solve it through a unified configuration file. For example, we can create such a configuration file.
“test"=>array( // namespace,方便分組 "keys"=> array( “good”=>array( // 定義的key,此key非最終入cache的key,入key需要和params組裝成唯一的key "timeout"=>600, // 此處定義超時時間 "params"=>array("epid"=>1,"num"=>1), // 通過這種方法,描述需要傳遞參數(shù),用于組裝最終入cache的key "desc"=>"描述" ), "top_test"=>array( // 定義的key,此key非最終入cache的key,入key需要和params組裝成唯一的key "timeout"=>60, // 此處定義超時時間 "ttl"=>10, // 自動觸發(fā)時間 "params"=>array('site_id'=>1,'boutique'=>1,'offset'=>1,'rows'=> 1,'uid'=>1,'tag_id'=>1,'type'=>1), // 通過這種方法,描述需要傳遞參數(shù),用于組裝最終入cache的key "desc"=>"描述", "author"=>"ugg", ), ) )
As shown above, through an algorithm, we can assemble site_top_feeds and params into a unique warehousing key. The assembled key , something like this site_top_feeds_site_id=12&boutique=1&offset=0&rows=20&uid=&tag_id=0&type=2 In this way, we prevent workers from assembling the key themselves, thereby eliminating the second problem. At the same time, in this configuration file, we also set a timeout , when calling the store, we can read directly from the configuration file, thus avoiding the third problem. After the above modifications, our cache method has also been appropriately adjusted. The calling example is as follows.
$siteid = 121; $seminal = 1; $tag_id = 12; $tag_id = 22; $data = fetch(‘site_top_feeds’,array('site_id'=>$siteid,'boutique'=>$seminal, 'offset'=>"0", 'rows' => "20", 'uid' =>null,’tag_id’=>$tag_id,’type'=>$type),'feed'); if(empty($data)){ // db相關(guān)操作 $db = new Wk_DB(); $data = $db->getTopFeeds($site_id,$seminal,0,20,null,$tag_id,$type); // $data數(shù)據(jù)其他處理邏輯 這里 …… $cache->store(‘site_top_feeds’,$data,array(‘site_id'=>$siteid,'boutique'=>$seminal, 'offset'=>"0", 'rows' => "20", 'uid' =>null,’tag_id’=>$tag_id,’type'=>$type),'feed'); }
Through the above solution, I did not see that the timeout timeout is gone and the key assembly is gone. For outer calls, It's transparent. But we can know the timeout of site_top_feeds through the configuration file, and what the assembled key looks like through the encapsulated algorithm.
This method does not solve the first and fourth problems, encapsulation; in order to achieve encapsulation, the first thing to do is the callback function. As a school-based language, PHP does not have a complete concept of function pointers. , of course, you don’t actually need a pointer to execute a function. PHP supports callback functions in two ways: call_user_func and call_user_func_array.
However, I made two examples and found that the execution efficiency of the above method is much different than the native method
native:0.0097959041595459s call_user_func:0.028249025344849s call_user_func_array:0.046605110168457s
The example code is as follows:
$s = microtime(true); for($i=0; $i< 10000 ; ++$i){ $a = new a(); $data = $a->aaa($array, $array, $array); $data = a::bbb($array, $array, $array); } $e = microtime(true); echo "native:".($e-$s)."s\n"; $s = microtime(true); for($i=0; $i< 10000 ; ++$i){ $a = new a(); $data = call_user_func(array($a,'aaa'),$array,$array,$array); $data = call_user_func(array('a','bbb'),$array,$array,$array); } $e = microtime(true); echo "call_user_func:".($e-$s)."s\n"; $s = microtime(true); for($i=0; $i< 10000 ; ++$i){ $a = new a(); $data = call_user_func_array(array($a,'aaa'),array(&$array,&$array,&$array)); $data = call_user_func_array(array('a','bbb'),array(&$array,&$array,&$array)); } $e = microtime(true); echo “call_user_func_array:".($e-$s)."s\n";
In PHP, if you know an object and a method, it is actually very simple to call the method. For example, in the example above
$a = new a(); $data = $a->aaa($array, $array, $array); $obj = $a; $func = ‘a(chǎn)aa’; $params = array($array,$array,$array); $obj->$func($params[0],$params[1],$params[2]); // 通過這種方式可以直接執(zhí)行
What is the execution performance of this method? In this way, after our comparative testing, we found that
native:0.0092940330505371s call_user_func:0.028635025024414s call_user_func_array:0.048038959503174s my_callback:0.11308288574219s
added a large number of method strategies to verify that the performance loss was relatively low, and the time consumption was only about 1.25 times that of the native method, much less than more than 3 times that of call_user_func, and that of call_user_func_array More than 5 times, the specific encapsulated code
switch(count($params)){ case 0: $result = $obj->{$func}();break; case 1: $result = $obj->{$func}($params[0]);break; case 2: $result = $obj->{$func}($params[0],$params[1]);break; case 3: $result = $obj->{$func}($params[0],$params[1],$params[2]);break; case 4: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3]);break; case 5: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3],$params[4]);break; case 6: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3],$params[4],$params[5]);break; case 7: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3],$params[4],$params[5],$params[6]);break; default: $result = call_user_func_array(array($obj, $func), $params); break; }
Before using this method, I considered using create_function to create anonymous functions and execute function callbacks. After testing, create_function can only create Global functions cannot create class functions and object functions, so I gave up.
After completing the above preparations, you can use the callback mechanism and call the business code again
…. // 相關(guān)變量賦值 $db = new Wk_DB(); $callback['obj'] = $db; $callback['func'] = 'getTopFeeds'; $callback['params'] = array('site_id'=>$siteid,'boutique'=>$seminal, 'offset'=>"0", 'rows' => "20", 'uid' =>null,'tag_id'=>$tag_id,'type'=>$type); $top_feed_list = $cache->smart_fetch('site_top_feeds',$callback,'feed');
使用以上方法實(shí)現(xiàn)對cache調(diào)用的封裝,同時保證性能的高效,從而解決第一和第四個問題。
至此已經(jīng)完成前四個問題,從而實(shí)現(xiàn)Cache的封裝,并有效的避免了上面提到的第二,第三,第四個問題。但是對于第五個問題,dogpile問題,并沒有解決,針對這種問題,最好的方式是在cache即將失效前,有一個進(jìn)程主動觸發(fā)db操作,獲取DB數(shù)據(jù)放入Cache中,而其他進(jìn)程正常從Cache中獲取數(shù)據(jù)(因?yàn)榇藭rcache并未失效);好在有Redis緩存,我們可以使用Redis的兩個特性很好解決這個問題,先介紹下這兩個接口
TTL方法:以秒為單位,返回給定 key 的剩余生存時間 (TTL, time to live),當(dāng) key 不存在時,返回 -2 。當(dāng) key 存在但沒有設(shè)置剩余生存時間時,返回 -1 。否則,以秒為單位,返回 key 的剩余生存時間。很明顯,通過這個方法,我們很容易知道key的還剩下的生存時間,通過這個方法,可以在key過期前做點(diǎn)事情,但是光有這個方法還不行,我們需要確保只有進(jìn)程執(zhí)行,而不是所有的進(jìn)程都做,正好用到下面這個方法。
SETNX方法:將 key 的值設(shè)為 value ,當(dāng)且僅當(dāng) key 不存在。若給定的 key 已經(jīng)存在,則SETNX 不做任何動作。SETNX 是『SET if Not eXists』(如果不存在,則 SET) 的簡寫。返回值:設(shè)置成功,返回 1 。設(shè)置失敗,返回 0 。通過這個方法,模擬分布式加鎖,保證只有一個進(jìn)程做執(zhí)行,而其他的進(jìn)程正常處理。結(jié)合以上Redis方法的特性,解決第五種的問題的,實(shí)例代碼。
… // 變量初始化 $key = “this is key”; $expiration = 600; $recalculate_at = 100; $lock_length = 20; $data = $cache->fetch($key); $ttl = $cache->redis->ttl($key); if($recalculate_at>=$ttl&&$r->setnx("lock:".$key,true)){ $r->expire(“l(fā)ock:”.$key, $lock_length); $db = new Wk_DB(); $data = $db->getXXX(); $cache->store($key, $expiration, $value); }
解決方案
好了,關(guān)鍵核心代碼如下
1:function回調(diào)部分代碼
public static function callback($callback){ // 安全檢查 if(!isset($callback['obj']) || !isset($callback['func']) || !isset($callback['params']) || !is_array($callback['params'])){ throw new Exception("CallBack Array Error"); } // 利用反射,判斷對象和函數(shù)是否存在 $obj = $callback['obj']; $func = $callback['func']; $params = $callback['params']; // 方法判斷 $method = new ReflectionMethod($obj,$func); if(!$method){ throw new Exception("CallBack Obj Not Find func"); } // 方法屬性判斷 if (!($method->isPublic() || $method->isStatic())) { throw new Exception("CallBack Obj func Error"); } // 參數(shù)個數(shù)判斷(不進(jìn)行逐項(xiàng)檢測) $paramsNum = $method->getNumberOfParameters(); if($paramsNum < count($params)){ throw new Exception("CallBack Obj Params Error"); } // 6個參數(shù)以內(nèi),逐個調(diào)用,超過6個,直接調(diào)用call_user_func_array $result = false; // 判斷靜態(tài)類方法 if(!is_object($obj) && $method->isStatic()){ switch(count($params)){ case 0: $result = $obj::{$func}();break; case 1: $result = $obj::{$func}($params[0]);break; case 2: $result = $obj::{$func}($params[0],$params[1]);break; case 3: $result = $obj::{$func}($params[0],$params[1],$params[2]);break; case 4: $result = $obj::{$func}($params[0],$params[1],$params[2],$params[3]);break; case 5: $result = $obj::{$func}($params[0],$params[1],$params[2],$params[3],$params[4]);break; case 6: $result = $obj::{$func}($params[0],$params[1],$params[2],$params[3],$params[4],$params[5]);break; case 7: $result = $obj::{$func}($params[0],$params[1],$params[2],$params[3],$params[4],$params[5],$params[6]);break; default: $result = call_user_func_array(array($obj, $func), $params); break; } }else{ switch(count($params)){ case 0: $result = $obj->{$func}();break; case 1: $result = $obj->{$func}($params[0]);break; case 2: $result = $obj->{$func}($params[0],$params[1]);break; case 3: $result = $obj->{$func}($params[0],$params[1],$params[2]);break; case 4: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3]);break; case 5: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3],$params[4]);break; case 6: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3],$params[4],$params[5]);break; case 7: $result = $obj->{$func}($params[0],$params[1],$params[2],$params[3],$params[4],$params[5],$params[6]);break; default: $result = call_user_func_array(array($obj, $func), $params); break; } }
2:自動觸發(fā)回調(diào)機(jī)制
public function smart_fetch($key,$callback,$namespace="wk") { key = $prefix.$key.$suffix; $result = $this->_redis->get($key); $bttl = false; // ttl狀態(tài)判斷(注意冷啟動) if(!empty($ttl)){ // 獲得過期時間 $rttl = $this->_redis->ttl($key); if($rttl > 0 && $ttl >= $rttl && $this->_redis->setnx("lock".$key,true)){ // 設(shè)置超時時間(超時時間3秒) $this->_redis->expire("lock".$key,3); $bttl = true; } } // 如何返回值不存在,調(diào)用回調(diào)函數(shù),獲取數(shù)值,并保持?jǐn)?shù)據(jù)庫 if($bttl || !$result || (isset($CONFIG['FLUSH']) && !empty($CONFIG['FLUSH']))){ // 重新調(diào)整參數(shù) $callbackparams = array(); foreach($params as $k=>$value){ $callbackparams[] = $value; } $callback['params'] = $callbackparams; $result = Wk_Common::callback($callback); $expire = $key_config["timeout"]; // 存儲數(shù)據(jù) $status = $this->_redis->setex($key, $expire, $result); $result=$this->_redis->get($key); } // 刪除鎖 if($bttl){ $this->_redis->delete("lock".$key); } return $result; }
至此,我們使用腳本語言特性,通過user_call_func_array方法補(bǔ)齊所有函數(shù)回調(diào)機(jī)制,從而實(shí)現(xiàn)對Cache的封裝,通過配置文件定義組裝key的規(guī)則和每個key的超時時間,再通過Redis的ttl和setnx特性,保證只有一個進(jìn)程執(zhí)行DB操作,從而很好避免dogpile問題,實(shí)現(xiàn)cache自動觸發(fā),保證cache持續(xù)存在數(shù)據(jù),并且有效減少DB的訪問次數(shù),提高性能。

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

This paper explores the problem of accurately detecting objects from different viewing angles (such as perspective and bird's-eye view) in autonomous driving, especially how to effectively transform features from perspective (PV) to bird's-eye view (BEV) space. Transformation is implemented via the Visual Transformation (VT) module. Existing methods are broadly divided into two strategies: 2D to 3D and 3D to 2D conversion. 2D-to-3D methods improve dense 2D features by predicting depth probabilities, but the inherent uncertainty of depth predictions, especially in distant regions, may introduce inaccuracies. While 3D to 2D methods usually use 3D queries to sample 2D features and learn the attention weights of the correspondence between 3D and 2D features through a Transformer, which increases the computational and deployment time.

The first pilot and key article mainly introduces several commonly used coordinate systems in autonomous driving technology, and how to complete the correlation and conversion between them, and finally build a unified environment model. The focus here is to understand the conversion from vehicle to camera rigid body (external parameters), camera to image conversion (internal parameters), and image to pixel unit conversion. The conversion from 3D to 2D will have corresponding distortion, translation, etc. Key points: The vehicle coordinate system and the camera body coordinate system need to be rewritten: the plane coordinate system and the pixel coordinate system. Difficulty: image distortion must be considered. Both de-distortion and distortion addition are compensated on the image plane. 2. Introduction There are four vision systems in total. Coordinate system: pixel plane coordinate system (u, v), image coordinate system (x, y), camera coordinate system () and world coordinate system (). There is a relationship between each coordinate system,

StableDiffusion3’s paper is finally here! This model was released two weeks ago and uses the same DiT (DiffusionTransformer) architecture as Sora. It caused quite a stir once it was released. Compared with the previous version, the quality of the images generated by StableDiffusion3 has been significantly improved. It now supports multi-theme prompts, and the text writing effect has also been improved, and garbled characters no longer appear. StabilityAI pointed out that StableDiffusion3 is a series of models with parameter sizes ranging from 800M to 8B. This parameter range means that the model can be run directly on many portable devices, significantly reducing the use of AI

Trajectory prediction plays an important role in autonomous driving. Autonomous driving trajectory prediction refers to predicting the future driving trajectory of the vehicle by analyzing various data during the vehicle's driving process. As the core module of autonomous driving, the quality of trajectory prediction is crucial to downstream planning control. The trajectory prediction task has a rich technology stack and requires familiarity with autonomous driving dynamic/static perception, high-precision maps, lane lines, neural network architecture (CNN&GNN&Transformer) skills, etc. It is very difficult to get started! Many fans hope to get started with trajectory prediction as soon as possible and avoid pitfalls. Today I will take stock of some common problems and introductory learning methods for trajectory prediction! Introductory related knowledge 1. Are the preview papers in order? A: Look at the survey first, p

In September 23, the paper "DeepModelFusion:ASurvey" was published by the National University of Defense Technology, JD.com and Beijing Institute of Technology. Deep model fusion/merging is an emerging technology that combines the parameters or predictions of multiple deep learning models into a single model. It combines the capabilities of different models to compensate for the biases and errors of individual models for better performance. Deep model fusion on large-scale deep learning models (such as LLM and basic models) faces some challenges, including high computational cost, high-dimensional parameter space, interference between different heterogeneous models, etc. This article divides existing deep model fusion methods into four categories: (1) "Pattern connection", which connects solutions in the weight space through a loss-reducing path to obtain a better initial model fusion

Suddenly discovered a 19-year-old paper GSLAM: A General SLAM Framework and Benchmark open source code: https://github.com/zdzhaoyong/GSLAM Go directly to the full text and feel the quality of this work ~ 1 Abstract SLAM technology has achieved many successes recently and attracted many attracted the attention of high-tech companies. However, how to effectively perform benchmarks on speed, robustness, and portability with interfaces to existing or emerging algorithms remains a problem. In this paper, a new SLAM platform called GSLAM is proposed, which not only provides evaluation capabilities but also provides researchers with a useful way to quickly develop their own SLAM systems.

Some of the author’s personal thoughts In the field of autonomous driving, with the development of BEV-based sub-tasks/end-to-end solutions, high-quality multi-view training data and corresponding simulation scene construction have become increasingly important. In response to the pain points of current tasks, "high quality" can be decoupled into three aspects: long-tail scenarios in different dimensions: such as close-range vehicles in obstacle data and precise heading angles during car cutting, as well as lane line data. Scenes such as curves with different curvatures or ramps/mergings/mergings that are difficult to capture. These often rely on large amounts of data collection and complex data mining strategies, which are costly. 3D true value - highly consistent image: Current BEV data acquisition is often affected by errors in sensor installation/calibration, high-precision maps and the reconstruction algorithm itself. this led me to

Written above & The author’s personal understanding is that image-based 3D reconstruction is a challenging task that involves inferring the 3D shape of an object or scene from a set of input images. Learning-based methods have attracted attention for their ability to directly estimate 3D shapes. This review paper focuses on state-of-the-art 3D reconstruction techniques, including generating novel, unseen views. An overview of recent developments in Gaussian splash methods is provided, including input types, model structures, output representations, and training strategies. Unresolved challenges and future directions are also discussed. Given the rapid progress in this field and the numerous opportunities to enhance 3D reconstruction methods, a thorough examination of the algorithm seems crucial. Therefore, this study provides a comprehensive overview of recent advances in Gaussian scattering. (Swipe your thumb up
