利用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'  => 'Predis\Connection\PhpiredisStreamConnection',
            'unix' => 'Predis\Connection\PhpiredisSocketConnection',
        ],
    ]);

 

就是這么簡單!現在我們的Redis安裝會更快!

總結:

在本教程中,我們利用Redis結合Predis庫來提升已部署的app的速度,我們平衡大數據海洋的水滴中可用的RAM來存儲每天一次查詢的結果,然后從緩存中返回這些結果,而不是重新運行一遍查詢。但這確實意味着結果不會總是最新的,但就這邊文章,其實查詢結果沒有被刷新的次數比這種情況多得多。

注:關於更多的有關Redis的知識可以參考redisdoc.com (此網站文檔是 Redis Command Reference 和 Redis Documentation 的中文翻譯版, 閱讀這個文檔可以幫助你了解 Redis 命令的具體使用方法, 並學會如何使用 Redis 的事務、持久化、復制、Sentinel、集群等功能。)
我們雲巴的產品也是使用redis存儲實踐,大家也可以來交流學習~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM