Laravel - Caching Eloquent with Frequent Updates

2020-07-27 05:48发布

Is it possible to use caching on an object that will be frequently modified? For instance, let's say we have a BlogPost object, and there's a num_of_views column (amongst others) that frequently changes. Is it possible to update the num_of_views field, both in cache and in the DB, without destroying the cache object and recreating it? I can do it manually, however I worry about sync issues.

3条回答
再贱就再见
2楼-- · 2020-07-27 06:30

There are several options:

  1. Separate the high-performance metrics from the database record and update the Php Model code to reflect that. In effect, your "model", a model, that delegates its setters and getters to other the BlogSlowData and BlogFastData models (I forgot the name of this pattern).

  2. You change the nature of how you write to your database. So, for instance when you update a record, you pop it into a queue, which is processed quickly. I like using redis for this, the writes are queued into to redis and then another program reads the queue and writes it to the database and to the cache.

  3. Finally, and probably the worst answer. Is you can use Redis's LUA code to write to the updated metrics into database or if you are using mysql you can use the http://dev.mysql.com/doc/refman/5.6/en/innodb-memcached.html memcache libraries to integrate the data directly into your database.

You can also do a combination of 1 & 2, in which you increment the counters in redis, and push a record into a queue, indicating that BlogPost.id = 1234, needs $view incremented by 1.

-daniel

查看更多
太酷不给撩
3楼-- · 2020-07-27 06:41

No, sadly there is not a good way to do it. But let me explain...


But there is actually a good reason for that - the whole reason of caching is to speed up the process of serving somewhat static data. For example, WikiPedia serves you 90% because it has so many users. WikiPedia articles rarely change, the popular one's that is, meaning caching is a great solution to keep some load off the servers.

In your case you would be wanting to modify a cache basically every request, you should never cache a view count by the way, and that would mean the caching functionality is rendered virtually useless. Even with a modification every 2, 3 or even 10 requests caching is still somewhat useless just because it's not the purpose of caching to regenerate every few requests but instead to keep load off the server.

Caching a request actually takes more resources than a regular live serving request would, so you can imagine that caching such variable data would not only be useless but also very problematic concerning your servers.


Another problem is that you propose to change only the num_of_views but keep the rest of object intact, but what you don't account for is that you can't actually do that with Cache. They way cache works is that it compresses whatever data you have into something else - it's a simple key 'post_object_x' and a value, which is usually some sort of encrypted string like base64 or others.

That means that the num_of_views field itself does not actually exist in the cache itself, unless you decrypt it and then modify it and encrypt it again, which is just as quick and resource intensive as destroying and recreating the object. So it's also just not possible from a purely technical standpoint.


I hope you could see why your idea doesn't quite work out and why it's also not the best idea in the world to cache any counters ever unless you have a massive site with billions of impressions - and even then you should only do it for very high request counts specifically and only short amounts of time.

查看更多
倾城 Initia
4楼-- · 2020-07-27 06:44

Yes, it is. I don't know how you are doing cache, but you can replace a cache instance at any time:

public function updatePost($post_id, $num_of_views)
{
    if (Cache::has('POST.'.$post_id))
    {
        $post = Cache::get('POST.'.$post_id);
    }
    else
    {
        $post = Post::find($post_id);
    }

    $post->num_of_views = $num_of_views;

    $post->save();

    Cache::put('POST.'.$post_id, $post);
}
查看更多
登录 后发表回答