`
seamon
  • 浏览: 22515 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
19c4d30c-d52a-3cc5-b233-a4a7d92b5798
rails3项目解析
浏览量:19591
社区版块
存档分类
最新评论

rails3项目解析之3——redis

阅读更多
rails3项目解析之1——系统架构
rails3项目解析之2——rails基础


在国家的正确指引和坚强领导下,在国内经济突飞猛进一片光明的大好形势下,随着互联网的飞速发展,即使是普通互联网应用的用户数量也呈线性上升趋势,更不用说国外那些大型的广受欢迎的诸多“并不存在”的网站们指数级的用户增长。而且网站内的数据关系也随着SNS等应用的兴起发生了很大的变化。传统的关系型数据库已经慢慢地对这些新时代的新特性显得有些力不从心。如何提高单台数据库服务器负载能力,如何更高效更迅速地处理简单类型的数据关系,成了摆在我们面前的亟待解决的问题。

时隔多年又过了把写论文的瘾。下面说点有用的。

当初在设计这个项目的架构时,就准备引入nosql作为主要组成部分。一是从网站的预期流量上,单台mysql要撑起来还真有点费劲,mysql的扩展方案又不是很优雅方便。二是当前凡是有点活力的场所,张口闭口都是nosql,现在搞个项目要是还在跟sql语句死抠较劲,你都不好意思跟人家打招呼。所以经过一番论证和可行性分析,最终我们选择了redis和mongodb来各负其责。这次先简单说说redis。

1、选择理由

喜欢一个人是没有理由的,但选择一个组件,却一定是要有理由的。这关系到日(名词)后有没有扩展空间,在项目中好不好用,大家写起代码来会不会暗地里大骂当初那个选型的人。

redis是一款内存型的key-value数据库,它允许把所有的数据都保留在内存里,保证了数据存取的速度。又有持久化和日志机制,保证了断电时数据的完整性。redis支持hash、list、(sorted) set等数据类型,作为绝大多数的应用来说已经足够。而且redis的更新非常快,开发者们都很敬业努力,这也是选择一个开源组件的很重要的一个方面。

因为这个系列不是专门讲解redis开发的,所以更详细的使用特性和开发手册,请微移莲步至官方网站

2、适用场景

项目中使用redis的场景主要有以下几处:

2.1 rails默认缓存。凡是rails需要使用缓存的地方,比如页面片段缓存等,都会用到指定的默认缓存系统。这个配置起来很简单,只需要一行代码即可,而且也不必关心rails具体在redis上是怎么实现的,自有redis_store来完成这一切。

config.cache_store = :redis_store, $config.redis[:server]


2.2 自定义缓存。主要是以对象缓存的形式,保存在开发中认为有必要进行快速存取的数据。自定义缓存需要自己写一个类,通过redis store调用redis client的命令,来实现数据的存取。比如首页上需要调用的某些资讯数据,就不再每次都从mysql中获取,而是由后台任务定时从mysql中读取或在内容更新时读取并保存至redis缓存中。

其中要注意一点,redis保存的value值,只接受字符串格式,所以如果要通过自定义缓存保存非字符串型的数据,就需要使用Marshal进行序列化和反序列化。

2.3 任务队列。执行异步和定时任务的resque和resque-scheduler组件,使用redis作为任务队列服务器。同样,按照resque的配置说明,一行代码即可搞定。

Resque.redis = Redis.new($config.redis[:server])


3、扩展redis缓存

redis_store只是按照ActiveSupport::Cache的规范实现了诸如read、write、increment、decrement、delete等通用的存取接口,而作为redis一大亮点的hash、set等数据结构则在默认的规范中没有用武之地。而且在项目中,很有可能会有存取hash类型缓存的需求。

作为金融资讯网站,当天的股票行情信息是非常重要的,访问率非常高,而且要求访问速度很快,如果每次访问都要去oracle实时查询,则无法满足速度的要求。因此,当天所有的股票行情数据,我们从oracle中取出之后,都要保存redis的高速缓存中。

国内的股票一共有2000多支,每支股票的行情数据要按照不低于每分钟一次的频率进行实时刷新。如果每支股票的数据都存为一个key-value键值对,那么在进行每分钟更新时,要同时取出2000个键值对,反序列化,对每支股票依次插入最新的行情数据,再依次序列化保存。经过实际测试,循环2000次序列化和反序列化所用时间极长,想在1分钟内完成这个任务是不可能的。

因此这就是一个典型的hash类型缓存存取的需求。我们把这2000支股票数据作为一个hash来进行保存,key是:stocks,field就是每支股票的代码,这样就不需要循环2000次存取数据,而只需一个redis命令就能完成所有2000多支股票数据的保存和读取,满足了在一分钟内实时刷新行情数据的要求。而且如果要读取某一支股票的数据,也只需指定key和field,就可迅速取出数据。

实现方法是扩展redis_store的RedisStore::Cache::Store类。具体代码就很简单了,这也显示出了redis的功能强大和ruby编程的便利。

def hwrite(key, hash)
  @data.hmset(key, *hash.map{|k, v| [k, Marshal.dump(v)]}.flatten(1))
end

def hread(key, field = nil)
  field.nil? ? Hash[*@data.hgetall(key).map{|k, v| [k, Marshal.load(v)]}.flatten(1)] :
               Marshal.load(@data.hget(key, field))
rescue TypeError
end


其中@data是Redis::Factory创建的一个Redis::Store实例,负责调用redis client执行redis命令。

同样,如果在项目中需要list和set等数据类型的缓存,也可按此思路一并处理。

4、redis高可用

因为redis不仅作为缓存使用,而且也是resque执行异步和定时任务的消息队列,因此对于可用性的要求就比较高,一旦挂掉,所有后台任务就会全部停止,严重影响网站的功能和体验。

但是redis原生的cluster解决方案迟迟不出,去年看redis官网的时候,说是直到今年5月份才可能会有rc放出,所以没办法,只能自己做一个山寨的高可用方案勉强支撑一段时间。

PS:今年5月份的时候我再看,却又拖到“不早于夏末”了。原来不只是XXX说话不算数的。

redis双机高可用的基础,是redis的主备复制机制。指定主备角色,是用slaveof命令。

指定本机为master
slaveof NO ONE


指定本机为192.168.1.10的slave
slaveof 192.168.1.10 6379


本来一开始我也想如同mysql的master-master机制那样,分别在配置文件中指定本机为对方的slave,不过后来发现这个方法行不通。如果配置文件中都设置slaveof x.x.x.x,那么这两个redis启动之后不提供服务,客户端无法连接,类似于服务死锁的状态。

经过多次实验发现,如果两个服务按照master-slave的方式启动,然后给master发送slaveof命令,指定其为另一个的slave,则此时双方都为slave,数据可以进行双向同步。基于这个原理,设计了一个redis双机互备的机制。

在自定义的配置文件中,做如下配置:

redis:
  server: redis://192.168.1.1:6379
  cluster:
    master: redis://192.168.1.10:6379
    slave: redis://192.168.1.20:6379


192.168.1.1是keepalived的virtual ip,应用程序只使用这个ip地址来存取redis。

其核心的实现方式如下:

4.1 两台redis服务器,配合keepalived。初始状态,是在master(192.168.1.10)上绑定keepalived的virtual ip 192.168.1.1。
4.2 启动一个监控脚本,每秒钟对两个redis服务进行一次扫描。
4.3 如果两台redis处于正常master-slave状态,则不进行操作。
4.4 如果master挂掉,监控脚本对在线的slave(192.168.1.20)发送slaveof NO ONE命令,设置其为临时的主机temp-master,同时由于原来的master服务器挂掉,virtual ip 192.168.1.1自动转移至temp-master,不影响应用程序对redis的存取。此时应用程序新产生的数据都保存到temp-master(192.168.1.20)上。
4.5 脚本监测到原来的master(192.168.1.10)在挂掉后重新启动加入集群,则向master发送slaveof 192.168.1.20 6379命令,设置其为temp-slave,从temp-master(192.168.1.20)复制在自己挂掉期间丢失的数据。同时virtual ip自动跳回temp-slave(192.168.1.10)向应用程序提供服务。
4.6 延时30秒钟,确保数据复制完毕,对调temp-master和temp-slave的角色,恢复默认的master-slave体系。

我知道延时30秒钟确保数据复制完毕这种方式很不好,但我确实在redis的info命令响应中没有找到指示复制完毕的字段。如果有消息能够明确指出数据复制完毕的状态会更好。

这样,两台redis服务器中的任何一台挂掉,都会由另一台继续提供服务,不会对网站形成可察觉的影响,也不会丢失数据。

5、redis配置

redis的配置也比较灵活强大,使得redis的使用也方便了不少。

5.1 持久化频率。配置save a b,指定在a秒内如果有b次key的改变,就执行硬盘持久化。此频率根据服务器状态进行设定,最好不要太过频繁。

5.2 内存限制。使用maxmemory,限制最大使用内存,如数据超出这个大小,则按照LRU把最不常用的移出redis。这个特性对于使用内存有限的VPS时比较适合,免得内存超出之后造成宕机或天量收费。

5.3 虚拟内存。设置vm-enabled,可指定redis能够使用的最大物理内存,当存储数据大于此内存值时,按照LRU算法把最不常使用的value移出到硬盘的虚拟内存文件中。不过所有的key都是保存在内存中的,这个不可设置。

5.4 二进制日志。当然,redis可以设置5.1所述的save参数,但如果存盘动作太密集,则会占用很多的资源,速度一慢也就失去了内存数据库的主要优点。为此redis设计了日志机制。通过设置appendonly,可以开启日志选项,每一个发送到redis执行的命令,都会被立刻追加到硬盘的日志文件中,如果redis意外宕机,则在重新启动的时候,redis会读取日志里的内容,恢复内存中尚未持久化的数据。

不过因为appendonly是所有数据的累积,所以文件大小增长非常快,在我们的项目中,差不多每一个小时就会增长6个G。虽然appendonly是另开进程操作的,但文件太大也会影响效率,更何况还有塞满硬盘的危险。为此我们使用定时任务,每半个小时向redis发送bgrewriteaof命令,使redis按照当前数据快照重写日志,重写后的日志大小与内存数据大小在同一个数量级上。
分享到:
评论
1 楼 wowpzp 2011-06-29  
继续学习!

相关推荐

    redis-rails:Ruby on Rails的Redis存储

    Ruby on Rails的Redis商店 redis-rails为Ruby on Rails提供了一整套存储(缓存,会话, HTTP缓存)。 有关一般准则,请参见主要的。 关于Rails 5.2的快速说明 Rails 5.2.0用地,因此,如果您只需要将片段缓存存储在...

    ruby on rails与MySql的环境配置——支持rails 2.3.5以上版本

    运行`rails -d mysql abc`创建名为abc的新项目,然后在项目的config目录下修改`database.yml`文件,输入正确的MySQL连接参数。启动Rails服务器(`ruby script/server`),访问`http://localhost:3000`,如果看到关于...

    Rails项目源代码

    这个“Rails项目源代码”是一个使用Rails构建的图片分享网站的完整源代码,它揭示了如何利用Rails的强大功能来创建一个允许用户上传、分享和浏览图片的应用。 1. **Rails框架基础**: Rails的核心理念是DRY(Don't...

    rails 项目起步示例

    本示例"rails项目起步示例"是一个购物系统,非常适合初学者入门学习。 在Rails项目中,我们首先需要了解的是项目的目录结构。一个标准的Rails应用会包含以下关键部分: 1. **app**:应用程序的核心,包括模型...

    The Rails 3 Way(2nd)

    3. **企业级项目**:对于那些正在使用或计划使用Rails 3进行企业级项目开发的团队而言,本书提供的实践经验和技术指导非常有价值。 #### 五、专家推荐与评价 多位业界知名专家对本书给予了高度评价: - Armando ...

    Rails3常用命令行命令

    Rails3还支持安装插件,可以通过以下命令将插件添加到项目中: ```bash rails plugin install https://..../..git ``` 插件会被安装到`vendor/plugins`目录下,提供额外的功能或扩展。 以上就是Rails3的一些常用...

    Redis Cookbook.pdf

    ### Redis Cookbook知识点解析 #### 一、Redis简介与安装 **知识点:** 1. **何时使用Redis** - **问题背景:** 在多种数据库选择中,理解何时选用Redis至关重要。 - **解决方案:** Redis最适合用作缓存系统、...

    ruby on rails 3 tutorial.pdf

    《Ruby on Rails 3 Tutorial》是一本专门为初学者设计的指南,旨在帮助读者快速掌握Ruby on Rails这一强大的Web开发框架。Ruby on Rails(简称Rails)是基于Ruby语言的一个开源框架,它采用MVC(Model-View-...

    redis-server下载

    Redis,全称Remote Dictionary Server,是一款高性能的键值存储系统,常被用于数据库、缓存和消息中间件的角色。...同时,理解并熟练运用`redis-server`的配置与管理,是每个IT专业人员必备的技能之一。

    在Ruby on Rails上使用Redis Store的方法

    对于在Rails上使用Redis Store,首先我们需要在Gemfile文件中添加入口   gem 'redis-rails' gem 'redis-rack-cache' # optional 然后我们就会有如下选择: ## Cache Store # config/environments/production.rb...

    Rails 3 in Action

    《Rails 3 in Action》是2011年由Ryan Bigg撰写的一本关于Ruby on Rails框架的权威指南,专门针对当时最新的Rails 3.1版本进行了深入解析。这本书旨在帮助开发者充分利用Rails 3.1的强大功能,提升Web应用开发的效率...

    centOS Rails3环境搭建

    ### CentOS环境下Rails 3开发环境搭建详解 #### 一、准备工作与环境配置 在开始部署Rails 3开发环境之前,我们需要确保系统上已经安装了一些基本的软件包和工具。这一步骤对于后续的Ruby和Rails安装至关重要。 ##...

    Rails3 使用rake启动后台任务

    在 Rails3 中,rake 不仅用于基本的项目管理,还可以用于启动后台任务,这在处理耗时操作、异步任务或者批量数据处理时非常有用。后台任务可以避免阻塞用户界面,提高应用程序的响应速度。以下是一些关于如何在 ...

    Rails3消息队列系统 Sidekiq

    在Rails3时代,Sidekiq就已经崭露头角,成为开发者们首选的消息队列系统之一。本文将深入探讨Sidekiq的核心概念、工作原理以及如何在Rails3项目中集成和使用。 一、核心概念 1. 消息队列:消息队列是一种设计模式...

    ruby on rails 3

    Ruby on Rails 3 是一个基于Ruby编程语言的开源Web应用程序框架,它遵循MVC(Model-...提供的文档如"Ruby192和Rails3.0.3的新征程.doc"和"rails3入门教程.pdf"等,将有助于深入理解这一框架及其在实际项目中的应用。

    redis cookbook

    对于使用Ruby on Rails的开发者,书中也提供了一章节专门介绍如何将Redis与Rails结合使用,使得Rails应用可以利用Redis强大的数据结构和性能优势。 整本书以实际问题和解决方案的形式展开,每章都是一个独立的单元...

    Ruby on Rails 3 Tutorial

    ### Ruby on Rails 3 教程知识点解析 #### 标题与描述中的核心知识点 - **Ruby on Rails 3**:一种流行的Web开发框架,基于Ruby语言。 - **经典教材**:表明本书是学习Ruby on Rails 3的一个权威且广受好评的资源...

    Ruby-RedisDashboard一个用于监控Redis服务器的Sinatra应用

    3. **配置**:在`config.ru`或Rails项目的配置文件中设置Redis连接参数。 4. **启动应用**:使用`rackup`命令启动Sinatra应用,或者在Rails中通过`rails s`启动。 5. **访问Web界面**:打开浏览器,输入服务器地址和...

Global site tag (gtag.js) - Google Analytics