PHP雲端儲存Redis的應用情境與Redis實現熱門排行榜功能

來源:互聯網
上載者:User

CRS可作為緩衝使用,在會話緩衝、全頁緩衝、提升資料庫查詢效能等情境都有顯著的優越性;CRS還可作為Key-Value儲存使用,其儲存的資料具備高可靠性,可每日產生冷備和通過流水日誌回檔。在熱門排行榜、計數器應用、即時系統、閱後即焚類需要精準設定到期時間的應用、反垃圾系統等情境下可大大提高效率。

雲端儲存Redis的使用情境,應用情境,產品特點和架構介紹:

使用情境


應用情境


產品特點


架構介紹


PHP運行前必備:

使用用戶端phpredis,下載和參考地址:https://github.com/phpredis/phpredis

【範例程式碼】

<?php
  /**以下參數分別填寫您的redis執行個體內網IP,連接埠號碼,執行個體id和密碼*/
  $host = "192.168.0.2";
  $port = 6379;
  $instanceid = "c532952f-55dc-4c22-a941-63057e560788";
  $pwd = "1234567q";

  $redis = new Redis();
  //串連redis
  if ($redis->connect($host, $port) == false) {
    die($redis->getLastError());
  }
  //鑒權
  if ($redis->auth($instanceid . ":" . $pwd) == false) {
    die($redis->getLastError());
  }
 
  /**接下來可以愉快的開始操作redis執行個體,可以參考:https://github.com/phpredis/phpredis */
 
  //設定key
  if ($redis->set("redis", "piaoyi.org") == false) {
    die($redis->getLastError());
  }
  echo "set key redis OK, value is: piaoyi.org\n";
 
  //擷取key
  $value = $redis->get("redis");
  echo "get key redis is:".$value."\n";
?>

 一個使用redis實現積分熱門排行榜的小例子:

//積分熱門排行榜類
class Ranks {
  const PREFIX = 'rank:';
  protected $redis = null;
  public function __construct( Redis $redis ) {
    $this->redis = $redis;
  }
  public function addScores( $member, $scores, $date="" ) {
    if ( $date=="" ) $key = self::PREFIX . date( 'Ymd' );
    else $key = self::PREFIX . $date;
    return $this->redis->zIncrBy( $key, $scores, $member );
  }
  function getOneDayRankings( $date, $start, $stop ) {
    $key = self::PREFIX . $date;
    return $this->redis->zRevRange( $key, $start, $stop, true );
  }
  protected function getMultiDaysRankings( $dates, $outKey, $start, $stop ) {
    $keys = array_map( function( $date ) {
        return self::PREFIX . $date;
      }, $dates );
    $weights = array_fill( 0, count( $keys ), 1 );
    $this->redis->zUnion( $outKey, $keys, $weights );//合集,相同key會求和累加
    return $this->redis->zRevRange( $outKey, $start, $stop, true );
  }
  public function getYesterdayTop10() {
    $date = date('Ymd' , strtotime('-1 day'));
    return $this->getOneDayRankings( $date, 0, 9 );
  }
  public static function getCurrentMonthDates() {
    $BeginDate=date('Y-m-01', strtotime(date("Y-m-d"))); //當前月第1天
    $curDate=(int)date('d', strtotime(date("Y-m-d")));
    $dates = array();
    for ( $day = 0; $day < $curDate; $day++ ) {
      $dates[] = date('Ymd' , strtotime("$BeginDate +$day day"));
    }
    return $dates;
  }
  public function getCurrentMonthTop10() {
    $dates = self::getCurrentMonthDates();
    return $this->getMultiDaysRankings( $dates, 'rank:current_month', 0, 9 );
  }
}

上面這個類使用:

//執行個體化
$rank = new Ranks( $redis );

$rank->addScores(1, 3, "20151106");
$rank->addScores(2, 2, "20151106");
$rank->addScores(3, 1, "20151106");

$rank->addScores(1, 1, "20151107");
$rank->addScores(2, 3, "20151107");
$rank->addScores(3, 2, "20151107");

print_r($rank->getYesterdayTop10());
print_r($rank->getCurrentMonthTop10());
print_r($rank->getOneDayRankings("20151106",0,-1));
print_r($rank->getOneDayRankings("20151107",0,-1));


一些支援的方法:

Connection

connect, open - Connect to a server
pconnect, popen - Connect to a server (persistent)
auth - Authenticate to the server
select - Change the selected database for the current connection
close - Close the connection
setOption - Set client option
getOption - Get client option
ping - Ping the server
echo - Echo the given string

Keys and Strings

Strings(字串)

append - Append a value to a key
bitcount - Count set bits in a string
bitop - Perform bitwise operations between strings
decr, decrBy - Decrement the value of a key
get - Get the value of a key
getBit - Returns the bit value at offset in the string value stored at key
getRange - Get a substring of the string stored at a key
getSet - Set the string value of a key and return its old value
incr, incrBy - Increment the value of a key
incrByFloat - Increment the float value of a key by the given amount
mGet, getMultiple - Get the values of all the given keys
mSet, mSetNX - Set multiple keys to multiple values
set - Set the string value of a key
setBit - Sets or clears the bit at offset in the string value stored at key
setex, psetex - Set the value and expiration of a key
setnx - Set the value of a key, only if the key does not exist
setRange - Overwrite part of a string at key starting at the specified offset
strlen - Get the length of the value stored in a key

Keys(鍵)

del, delete - Delete a key
dump - Return a serialized version of the value stored at the specified key.
exists - Determine if a key exists
expire, setTimeout, pexpire - Set a key's time to live in seconds
expireAt, pexpireAt - Set the expiration for a key as a UNIX timestamp
keys, getKeys - Find all keys matching the given pattern
scan - Scan for keys in the keyspace (Redis >= 2.8.0)
migrate - Atomically transfer a key from a Redis instance to another one
move - Move a key to another database
object - Inspect the internals of Redis objects
persist - Remove the expiration from a key
randomKey - Return a random key from the keyspace
rename, renameKey - Rename a key
renameNx - Rename a key, only if the new key does not exist
type - Determine the type stored at key
sort - Sort the elements in a list, set or sorted set
ttl, pttl - Get the time to live for a key
restore - Create a key using the provided serialized value, previously obtained with dump.


Hashes(雜湊表)

hDel - Delete one or more hash fields
hExists - Determine if a hash field exists
hGet - Get the value of a hash field
hGetAll - Get all the fields and values in a hash
hIncrBy - Increment the integer value of a hash field by the given number
hIncrByFloat - Increment the float value of a hash field by the given amount
hKeys - Get all the fields in a hash
hLen - Get the number of fields in a hash
hMGet - Get the values of all the given hash fields
hMSet - Set multiple hash fields to multiple values
hSet - Set the string value of a hash field
hSetNx - Set the value of a hash field, only if the field does not exist
hVals - Get all the values in a hash
hScan - Scan a hash key for members


Lists(列表)

blPop, brPop - Remove and get the first/last element in a list
brpoplpush - Pop a value from a list, push it to another list and return it
lIndex, lGet - Get an element from a list by its index
lInsert - Insert an element before or after another element in a list
lLen, lSize - Get the length/size of a list
lPop - Remove and get the first element in a list
lPush - Prepend one or multiple values to a list
lPushx - Prepend a value to a list, only if the list exists
lRange, lGetRange - Get a range of elements from a list
lRem, lRemove - Remove elements from a list
lSet - Set the value of an element in a list by its index
lTrim, listTrim - Trim a list to the specified range
rPop - Remove and get the last element in a list
rpoplpush - Remove the last element in a list, append it to another list and return it (redis >= 1.1)
rPush - Append one or multiple values to a list
rPushx - Append a value to a list, only if the list exists


Sets(集合)

sAdd - Add one or more members to a set
sCard, sSize - Get the number of members in a set
sDiff - Subtract multiple sets
sDiffStore - Subtract multiple sets and store the resulting set in a key
sInter - Intersect multiple sets
sInterStore - Intersect multiple sets and store the resulting set in a key
sIsMember, sContains - Determine if a given value is a member of a set
sMembers, sGetMembers - Get all the members in a set
sMove - Move a member from one set to another
sPop - Remove and return a random member from a set
sRandMember - Get one or multiple random members from a set
sRem, sRemove - Remove one or more members from a set
sUnion - Add multiple sets
sUnionStore - Add multiple sets and store the resulting set in a key
sScan - Scan a set for members


Sorted sets(有序集合)

zAdd - Add one or more members to a sorted set or update its score if it already exists
zCard, zSize - Get the number of members in a sorted set
zCount - Count the members in a sorted set with scores within the given values
zIncrBy - Increment the score of a member in a sorted set
zInter - Intersect multiple sorted sets and store the resulting sorted set in a new key
zRange - Return a range of members in a sorted set, by index
zRangeByScore, zRevRangeByScore - Return a range of members in a sorted set, by score
zRangeByLex - Return a lexigraphical range from members that share the same score
zRank, zRevRank - Determine the index of a member in a sorted set
zRem, zDelete - Remove one or more members from a sorted set
zRemRangeByRank, zDeleteRangeByRank - Remove all members in a sorted set within the given indexes
zRemRangeByScore, zDeleteRangeByScore - Remove all members in a sorted set within the given scores
zRevRange - Return a range of members in a sorted set, by index, with scores ordered from high to low
zScore - Get the score associated with the given member in a sorted set
zUnion - Add multiple sorted sets and store the resulting sorted set in a new key
zScan - Scan a sorted set for members


Transactions(事務)

multi, exec, discard - Enter and exit transactional mode
watch, unwatch - Watches a key for modifications by another client.


Server(伺服器端命令)

bgrewriteaof - Asynchronously rewrite the append-only file
bgsave - Asynchronously save the dataset to disk (in background)
config - Get or Set the Redis server configuration parameters
dbSize - Return the number of keys in selected database
flushAll - Remove all keys from all databases
flushDB - Remove all keys from the current database
info - Get information and statistics about the server
lastSave - Get the timestamp of the last disk save
resetStat - Reset the stats returned by info method.
save - Synchronously save the dataset to disk (wait to complete)
slaveof - Make the server a slave of another instance, or promote it to master
time - Return the current server time
slowlog - Access the Redis slowlog entries




使用 Redis 實現熱門排行榜功能



熱門排行榜功能是一個很普遍的需求。使用 Redis 中有序集合的特性來實現熱門排行榜是又好又快的選擇。

一般熱門排行榜都是有實效性的,比如“使用者積分榜”。如果沒有實效性一直按照總榜來排,可能榜首總是幾個老使用者,對於新使用者來說,那真是太令人沮喪了。

首先,來個“今日積分榜”吧,定序是今日使用者新增積分從多到少。

那麼使用者增加積分時,都操作一下記錄當天積分增加的有序集合。
假設今天是 2015 年 04 月 01 日,UID 為 1 的使用者因為某個操作,增加了 5 個積分。
Redis 命令如下:

ZINCRBY rank:20150401 5 1

假設還有其他幾個使用者也增加了積分:

ZINCRBY rank:20150401 1 2
ZINCRBY rank:20150401 10 3

看看現在有序集合 rank:20150401 中的資料(withscores 參數可以附帶擷取元素的 score):

ZRANGE rank:20150401 0 -1 withscores

1) "2"
2) "1"
3) "1"
4) "5"
5) "3"
6) "10"

按照分數從高到低,擷取 top10:

ZREVRANGE rank:20150401 0 9 withscores

1) "3"
2) "10"
3) "1"
4) "5"
5) "2"
6) "1"

因為只有三個元素,所以就查詢出了這些資料。

如果每天記錄當天的積分熱門排行榜,那麼其他花樣百出的榜單也就簡單了。
比如“昨日積分榜”:

ZREVRANGE rank:20150331 0 9 withscores

利用並集實現多天的積分總和,實現“上周積分榜”:

ZUNIONSTORE rank:last_week 7 rank:20150323 rank:20150324 rank:20150325 rank:20150326 rank:20150327 rank:20150328 rank:20150329 WEIGHTS 1 1 1 1 1 1 1

這樣就將 7 天的積分記錄合并到有序集合 rank:last_week 中了。權重因子 WEIGHTS 如果不給,預設就是 1。為了不隱藏細節,特意寫出。
那麼查詢上周積分榜 Top10 的資訊就是:

ZREVRANGE rank:last_week  0 9 withscores

“月度榜”、“季度榜”、“年度榜”等等就以此類推。

下面給出一個 PHP 版的簡單實現。使用 Redis 依賴於 PHP 擴充 PhpRedis,代碼還依賴於 Carbon 庫,用於處理時間。代碼量很少,所以就不敲注釋了。

<?php

namespace Blog\Redis;

use \Redis;
use Carbon\Carbon;


class Ranks {

    const PREFIX = 'rank:';

    protected $redis = null;


    public function __construct(Redis $redis) {
        $this->redis = $redis;
    }


    public function addScores($member, $scores) {
        $key = self::PREFIX . date('Ymd');
        return $this->redis->zIncrBy($key, $scores, $member);
    }


    protected function getOneDayRankings($date, $start, $stop) {
        $key = self::PREFIX . $date;
        return $this->redis->zRevRange($key, $start, $stop, true);
    }


    protected function getMultiDaysRankings($dates, $outKey, $start, $stop) {
        $keys = array_map(function($date) {
            return self::PREFIX . $date;
        }, $dates);

        $weights = array_fill(0, count($keys), 1);
        $this->redis->zUnion($outKey, $keys, $weights);
        return $this->redis->zRevRange($outKey, $start, $stop, true);
    }


    public function getYesterdayTop10() {
        $date = Carbon::now()->subDays(1)->format('Ymd');
        return $this->getOneDayRankings($date, 0, 9);
    }


    public static function getCurrentMonthDates() {
        $dt = Carbon::now();
        $days = $dt->daysInMonth;

        $dates = array();
        for ($day = 1; $day <= $days; $day++) {
            $dt->day = $day;
            $dates[] = $dt->format('Ymd');
        }
        return $dates;
    }


    public function getCurrentMonthTop10() {
        $dates = self::getCurrentMonthDates();
        return $this->getMultiDaysRankings($dates, 'rank:current_month', 0, 9);
    }

}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.