zoukankan      html  css  js  c++  java
  • 利用Redis cache优化app查询速度实践

    注意:本篇文章译自speeding up existing app with a redis cache,如需要转载请注明出处。

    发现问题

    在应用解决方法之前,我们需要对我们面对的问题有一个清晰的认识。
    App所遇到的问题是,当执行一个查询时,它会跑到Diffbot’s API 然后查询数据集。子集被返回并展示出来。根据Diffbot服务器的繁忙程度,可能需要花5秒左右的时间去完成这一过程。如果扩展计算机的能力这种情形无疑会改进,如果一个查询执行一次就被记住并且重复使用24小时,通常可以把这个过程看成刷新这个集合,并且这个方式会非常的高效。

    你可能会怀疑“缓存一个查询有什么好处呢?”大多数人应该都不会只查询一个东西或者同样的事物。

    呃...事实上,不仅调查表明人们经常查询一个事情或相同的事,他们通常也会去搜索多产作家(或自己)。考虑到事实上应用这一缓存方式并没有增加纸面上的成本(其实是通过减少服务器压力而减少成本),把这个加进来是一个容易的盈利点,即使它使用频率并没有我们希望那样高。但我们也没有任何理由不使用它----因为它可以给我们带来利益。

    既然问题已经界定清楚,让我们先处理先决条件。

    配置环境

    首先,我们需要在开发和生产环境下安装Redis(需要注意的是,如果你把Homestead用于本地开发,Redis就已经安装好了,目前使用的是v3.0.1版本)

    我们可以通过操作系统的包管理器来做这件事:

    sudo apt-get install redis-server

    这是最简单也是最为推荐的方法,但我们也可以从头来安装并且手动配置。根据他们网上的说明,我们可以如此配置:

    sudo apt-get install gcc make build-essential tcl
    wget http://download.redis.io/releases/redis-3.0.2.tar.gz
    tar xzf redis-3.0.2.tar.gz
    cd redis-3.0.2
    make
    make test
    sudo make install

    如果你运行make遇到错误提示jemalloc.h那么运行make distclean然后在运行makemake test命令是选择性运行的,但是很有帮助。

    注意:如果你看到这里,而3.0.2已经不是最新的版本,那么根据你的最新版本号去调节命令。

    为了防止一些常见的警告(至少在Ubuntu上),我们还需要预防性的运行以下命令:

    sudo sh -c 'echo "vm.overcommit_memory=1" >> /etc/sysctl.conf'
    sudo sh -c 'echo "net.core.somaxconn=65535" >> /etc/sysctl.conf'
    sudo sh -c 'echo "never" > /sys/kernel/mm/transparent_hugepage/enabled'

    我们也要确保最后的命令在exit 0上被添加到了/etc/rc.local,因此能保证在每个重启的服务器上能重新发送。最后我们可以用sudo reboot重启服务器并且运行有sudo redis-server的Redis检查是否一切正常。

    最后,我们要确保在服务器重启后Redis会启动,所以我们要跟着官方的说明去完成配置。

    Predis

    我们之前说了一些关于Predis的基础知识,我们将要将其用到本文的例子中:

    composer require predis/predis

    进一步的,假设我们已经了解之前叙述的关于Predis的知识。

    和之前发表的关于Predis相比,虽然是有一些不同(比如过渡到命名空间),但我们需要的API几乎是一样的。

    实施
    要在我们app里运用Redis,我们需要遵循以下的程序:

    • 查看当前的缓存中是否有查询结果
    • 如果是,抓取他们
    • 如果没有,把他们拿来,储存,将他们发送到app的其他部分

    因此,实施非常的简单:在“form submitted”下检查(寻找“search”参数),我们实例化Predis客户端,计算search查询的MD5 hash值,然后检查查询结果是否已经被缓存。如果失败,就在重复前面的流程。

    $result = ...
    $info = ...

    我们将查询结果序列化并直接保存到cache里。然后我们在模块外立即抓取他们,app的流程就和往常一样继续。而index.php改变的部分如下:

    // Check if the search form was submitted
    if (isset($queryParams['search'])) {
    
        $redis = new Client();
        $hash = md5($_SERVER['QUERY_STRING']);
        if (!$redis->get($hash . '-results')) {
    
            $diffbot = new Diffbot(DIFFBOT_TOKEN);
    
            // Building the search string
            $searchHelper = new SearchHelper();
            $string = (isset($queryParams['q']) && !empty($queryParams['q']))
                ? $queryParams['q']
                : $searchHelper->stringFromParams($queryParams);
    
            // Basics
            $search = $diffbot
                ->search($string)
                ->setCol('sp_search')
                ->setStart(($queryParams['page'] - 1) * $resultsPerPage)
                ->setNum($resultsPerPage);
    
            $redis->set($hash . '-results', serialize($search->call()));
            $redis->expire($hash . '-results', 86400);
            $redis->set($hash . '-info', serialize($search->call(true)));
            $redis->expire($hash . '-info', 86400);
        }
    
        $results = unserialize($redis->get($hash . '-results'));
        $info = unserialize($redis->get($hash . '-info'));

    进过测试,我们可以看到它的魅力所在—如果我们刷新页面,或执行另一个查询,就会立即执行一次查询,然后会回到之前的那个。最后我们添加,提交,推动部署一下内容:

    git add -A
    git commit -m "Added Redis cache [deploy:production]"
    git push origin master

    就是这么简单,我们的最新版的app已经上线,而且使用的Redis。

    注意:如果你想知道我们是如何用一条命令从开发模式转到生产部署,你可以看这里

    微调
    为了进一步的提升性能,Predis推荐安装phpiredis,这是个PHP的扩展,目的是“降低序列化和解析Redis协议的成本”。可以看作我们完全控制了服务器,有什么理由不试试呢?

    cd ~
    git clone https://github.com/redis/hiredis
    cd hiredis
    make
    sudo make install
    cd ~
    git clone https://github.com/nrk/phpiredis
    cd phpiredis
    phpize && ./configure --enable-phpiredis
    make
    sudo make install
    
    sudo touch /etc/php5/mods-available/phpiredis.ini
    sudo sh -c 'echo "extension=phpiredis.so" > /etc/php5/mods-available/phpiredis.ini'
    sudo php5enmod phpiredis
    sudo service php5-fpm restart

    以上是安装的前提,并且启用了扩展。现在我们要做的就是利用phpiredis链接去配置Predis客户端。因此我们需要更换:

    $redis = new Client();

    $redis = new Client('tcp://127.0.0.1', [
            'connections' => [
                'tcp'  => 'PredisConnectionPhpiredisStreamConnection',
                'unix' => 'PredisConnectionPhpiredisSocketConnection',
            ],
        ]);

    就是这么简单!现在我们的Redis安装会更快!

    总结:

    在本教程中,我们利用Redis结合Predis库来提升已部署的app的速度,我们平衡大数据海洋的水滴中可用的RAM来存储每天一次查询的结果,然后从缓存中返回这些结果,而不是重新运行一遍查询。但这确实意味着结果不会总是最新的,但就这边文章,其实查询结果没有被刷新的次数比这种情况多得多。

    注:关于更多的有关Redis的知识可以参考redisdoc.com (此网站文档是 Redis Command Reference 和 Redis Documentation 的中文翻译版, 阅读这个文档可以帮助你了解 Redis 命令的具体使用方法, 并学会如何使用 Redis 的事务、持久化、复制、Sentinel、集群等功能。)
    我们云巴的产品也是使用redis存储实践,大家也可以来交流学习~

  • 相关阅读:
    二分图 洛谷P2055 [ZJOI2009]假期的宿舍
    并查集 洛谷P1640 [SCOI2010]连续攻击游戏
    贪心 洛谷P2870 Best Cow Line, Gold
    贪心 NOIP2013 积木大赛
    快速幂 NOIP2013 转圈游戏
    倍增LCA NOIP2013 货车运输
    树形DP 洛谷P2014 选课
    KMP UVA1328 Period
    动态规划入门 BZOJ 1270 雷涛的小猫
    KMP POJ 2752Seek the Name, Seek the Fame
  • 原文地址:https://www.cnblogs.com/yunba/p/4797562.html
Copyright © 2011-2022 走看看