简体   繁体   English

Memcached密钥生成从参数到函数

[英]Memcached Key Generation From arguments to a function

This question is similar to a question asked about java , but i'm doing this in php so i don't think it qualifies as a duplicate. 这个问题类似于一个关于java的问题 ,但我在php中这样做,所以我不认为它有资格作为重复。

I would like a way to generate a deterministic key when this function is called. 我想要一种在调用此函数时生成确定性键的方法。 the function should operate like a read through cache. 该函数应该像读取缓存一样运行。 if the key exists, retrieve the data. 如果密钥存在,则检索数据。 if not, call the function store the data, then return it. 如果没有,调用函数存储数据,然后返回它。

here's what i have and it works, but im not sure if its safe and if its deterministic enough or even unique enough, since i have absolutely 0 understanding on these topics. 这是我拥有的,它的工作原理,但我不确定它是否安全,如果它的确定性足够甚至足够独特,因为我对这些主题完全没有理解。

// $call = function being called $args = arguments to that function
// $force = force cache to bypassed, then updated
public function cachedCall($call,$args = [],$force = false)
{
    $cache = \App\App::getInstance()->cache;
    $key = md5($call) . md5(serialize($args));
    $res = $cache->get($key);
    if($res === -1 || $force){
        $res = call_user_func_array([$this,$call],$args);
        if(!empty($res) && $res !== false && $res !== 0 && !is_null($res)){
            $cache->set($key,$res,0); //never set empty data in the cache.
        }
    }
    return $res;
}

My question only pertains to the third line, where the key is calculated. 我的问题只涉及计算密钥的第三行。 you can see that it is calculated by the called function and the arguments to be supplied to that function. 你可以看到它是由被调用的函数和要提供给该函数的参数计算的。 I have had collisions in some instances. 我在某些情况下发生了碰撞。 I'm looking for ways to improve this so its more useful and the hashes are consistent but not likely to collide.The third argument can be ignored as its simply a way to force the cache to be bypassed. 我正在寻找改进它的方法,因此它更有用,哈希是一致的但不太可能发生冲突。第三个参数可以忽略,因为它只是一种强制缓存被绕过的方法。

Examples of how this function is called: 如何调用此函数的示例:

$data = $db->cachedCall('getUserByEmail',[$this->email],true);

$data = $db->cachedCall('getCell',['SELECT id FROM foobar WHERE foo=:bar',[':bar'=>55]]);

If possible, i would like to guarantee the keys have a consistent length at the same time. 如果可能的话,我想保证密钥同时具有一致的长度。

This is because the key could be the same in different instances, for example when calling to the method cachedCall have the same arguments. 这是因为密钥在不同的实例中可能是相同的,例如,当调用方法cachedCall具有相同的参数时。 As I image you should share the same memcached server for each instance, and then that is the reason why you have cache collisions. 在我映像时,你应该为每个实例共享相同的memcached服务器,然后这就是你有缓存冲突的原因。

Demostration 笔画演示

As I read, the variable $call will have a limited values shared with any of the other parts of the code, because will contain a name of a method of the class that contains the method cachedCall , that means it is very easy that two different calls shares this value . 正如我所读到的,变量$ call将具有与代码的任何其他部分共享的有限值,因为它将包含包含方法cachedCall的类的方法的名称 ,这意味着它很容易两个不同呼叫共享此值

Furthermore, you can call to this method with an empty array of arguments . 此外,您可以使用空数组参数调用此方法。

So, is very easy to have the same method call in two different instances: 因此,在两个不同的实例中调用相同的方法非常容易:

cachedCall('methodX', array()); <- From instance A
cachedCall('methodX', array()); <- From instance B

This will store this content in the same memcached key 这会将此内容存储在同一个memcached密钥中

Solution

Inside the method, take in account in someway the instance name . 在方法内部,以某种方式考虑实例名称 For example, you could use the current url as part of the key, or the domain name (depending on your case): 例如,您可以使用当前URL作为密钥的一部分或域名(取决于您的情况):

$key = md5($call) . md5(serialize($args)) . md5($_SERVER['HTTP_HOST']);
$key = md5($call) . md5(serialize($args)) . md5($_SERVER['REQUEST_URI']);

Above you can see two examples of how you can change the memcached key depending on your instance. 您可以在上面看到两个如何根据您的实例更改memcached密钥的示例。

If your arguments are guaranteed to be unique per query and you're getting collisions then I think there may be a bug in your code. 如果您的参数保证每个查询都是唯一的,并且您遇到了冲突,那么我认为您的代码中可能存在错误。

The likelihood of collisions using MD5 is remote... 使用MD5发生碰撞的可能性很小......

How many random elements before MD5 produces collisions? MD5产生碰撞之前有多少随机元素?

If you're seeing collisions something's wrong. 如果你看到碰撞出了问题。 PHP serializing an array will serialize it ordered so md5(serialize($array_here) should be safe. I had a problem where I didn't box the argument from the calling function when trying to pass a single array. If your args are in an array before calling then you have no issue. PHP序列化一个数组会序列化它的顺序,所以md5(serialize($array_here)应该是安全的。 I有一个问题,我试图传递单个数组时没有从调用函数中插入参数。如果你的args在一个在调用之前的数组然后你没有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM