Redis在Rails中的應用實例

Redis在Rails中的應用實例

Redis是一個非常快速的,原子性的key-value存儲。它允許字符串,集合,排序集合,列表和散列存儲。 Redis把數據持久化在RAM中,很像Memcached但又不全是Memcached的,因爲Redis的週期性寫入磁盤來維持它的持久性。

1. 數據類型

Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合),詳情請看這裏

2. 啓動服務

運行redis-server,啓動redis服務器,得到以下

PENG-MacBook-Pro:~ PENG-mac$ redis-server
31998:C 02 Nov 13:58:45.177 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
31998:M 02 Nov 13:58:45.178 * Increased maximum number of open files to 10032 (it was originally set to 256).
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 3.0.6 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 31998
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

31998:M 02 Nov 13:58:45.179 # Server started, Redis version 3.0.6
31998:M 02 Nov 13:58:45.184 * DB loaded from disk: 0.004 seconds
31998:M 02 Nov 13:58:45.184 * The server is now ready to accept connections on port 6379

以上未指定配置文件,使用默認的配置文件,若要自定義請在後面指定參數redis-server /path/to/redis.conf

然後用redis-cli本地連接到redis服務器

Rails and Redis

在Rails中爲了避免Sql的反覆查詢,可以考慮把一部分數據用Redis儲存(緩存),例如Web服務器中的Session儲存就可以利用redis來緩存,這裏用個簡單的例子來說明Redis的一些基本方法和如何連接rails和redis

1.創建新的rails應用rails new redis-test

2.在Gemfile中加入ruby的redis庫

gem 'redis'

3.運行bundle install安裝依賴庫

4.在Rails中配置與redis的連接:在初始化文件中創建config/initializers/redis.rb,並填入一下:

$redis = Redis.new(:host => 'localhost', :port => 6379)

以上會創建一個新的redis客戶端實例,與localhost:6379連接(默認),這個實例會被儲存在全局變量$redis中,能在其他任何地方直接調用

5.運行rails console進入Rails的控制檯,檢查與redis的連接:

PENG-MacBook-Pro:redis-test PENG-mac$ rails console
Loading development environment (Rails 4.2.5.2)
2.2.4 :001 > $redis
 => #<Redis client v3.2.2 for redis://localhost:6379/0> 
2.2.4 :002 > $redis.set('chunky', 'bacon')
 => "OK" 
2.2.4 :003 > $redis.get('chunky')
 => "bacon" 
2.2.4 :004 > 

6.運行rails generate model user name:string建立一個用戶模型,並指定字段name的類型爲字符串

7.下面考慮用戶之間的關注問題:比如,在微博中用戶之間可以互相關注(follow),那麼就有followers和followings,followings表示我關注的人,followers表示關注我的人。這種功能的實現可以通過傳統的關係數據庫實現:多對多的關聯關係,通過建立額外的關聯表,儲存雙方的id即可,請戳這裏獲得詳細的描述

現在我們通過redis來實現這個,編輯user.rb:

class User < ActiveRecord::Base
  # follow a user
  def follow!(user)
    $redis.multi do
      $redis.sadd(self.redis_key(:following), user.id)
      $redis.sadd(user.redis_key(:followers), self.id)
    end
  end

  # unfollow a user
  def unfollow!(user)
    $redis.multi do
      $redis.srem(self.redis_key(:following), user.id)
      $redis.srem(user.redis_key(:followers), self.id)
    end
  end

  # users that self follows
  def followers
    user_ids = $redis.smembers(self.redis_key(:followers))
    User.where(:id => user_ids)
  end

  # users that follow self
  def following
    user_ids = $redis.smembers(self.redis_key(:following))
    User.where(:id => user_ids)
  end

  # users who follow and are being followed by self
  def friends
    user_ids = $redis.sinter(self.redis_key(:following), self.redis_key(:followers))
    User.where(:id => user_ids)
  end

  # does the user follow self
  def followed_by?(user)
    $redis.sismember(self.redis_key(:followers), user.id)
  end

  # does self follow user
  def following?(user)
    $redis.sismember(self.redis_key(:following), user.id)
  end

  # number of followers
  def followers_count
    $redis.scard(self.redis_key(:followers))
  end

  # number of users being followed
  def following_count
    $redis.scard(self.redis_key(:following))
  end

  # helper method to generate redis keys
  def redis_key(str)
    "user:#{self.id}:#{str}"
  end
end

如何使用?

> %w[Alfred Bob].each{|name| User.create(:name => name)}
=> ['Alfred', 'Bob']
> a, b = User.all
=> [#<User id: 1, name: "Alfred">, #<User id: 2, name: "Bob">] 
> a.follow!(b)
=> [1, 1] 
> a.following?(b)
=> true 
> b.followed_by?(a)
=> true 
> a.following
=> [#<User id: 2, name: "Bob">] 
> b.followers
=> [#<User id: 1, name: "Alfred">]
> a.friends
=> [] 
> b.follow!(a)
=> [1, 1] 
> a.friends
=> [#<User id: 2, name: "Bob">] 
> b.friends
=> [#<User id: 1, name: "Alfred">] 

我們使用了上述redis的集合(set)數據類型,使用了以下方法:

方法 說明 示例
sadd 向集合中添加新的成員(不能重複) SADD myset "Hello"
srem 移除集合中一個或多個成員 SREM myset "Hello"
smembers 返回集合中的所有成員 SMEMBERS myset
sinter 返回給定所有集合的交集 SINTER set1 set2
scard 獲取集合的成員數 SCARD myset
multi 標誌着一個事務塊的開始(多條語句執行)

結束語

上述通過一個實際例子,介紹瞭如何在Rails中使用redis儲存,以及redis的集合的一些操作,可以看出來,用key-value的儲存方式設計起來要比傳統的多對多關係要簡單的多。

當然,當Web服務器中的登錄人數過多時,僅靠內存來儲存session會話信息可能不太夠用(<4k),這時就可以考慮用redis來緩存,因爲redis可以週期性將數據部分儲存在硬盤裏。但是如果直接將sessions會話信息直接儲存在數據庫中,隨着時間的增加,這些冗餘數據會佔據一部分空間,因此需要週期對數據庫進行清理。所以相對來說,使用redis緩存會成爲一個折中的方案。

reference:http://www.justinweiss.com/articles/how-rails-sessions-work/

http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html

發佈了46 篇原創文章 · 獲贊 132 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章