Redis应用场景
来源:互联网 发布:windows时间服务未运行 编辑:程序博客网 时间:2024/06/06 05:23
1.取最新N个数据的操作
比如典型的取你网站的最新文章,通过下面方式,我们可以将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取使用LPUSH latest.comments<ID>命令,向list集合中插入数据
插入完成后再用LTRIM latest.comments 0 5000命令使其永远只保存最近5000个ID
然后我们在客户端获取某一页评论时可以用下面的逻辑(伪代码)
- <code>FUNCTION get_latest_comments(start,num_items):
- id_list = redis.lrange("latest.comments",start,start+num_items-1)
- IF id_list.length < num_items
- id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
- END
- RETURN id_list
- END</code>
如果你还有不同的筛选维度,比如某个分类的最新N条,那么你可以再建一个按此分类的List,只存ID的话,Redis是非常高效的。
2.排行榜应用,取TOP N操作
这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。3.需要精准设定过期时间的应用
比如你可以把上面说到的sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把 Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。4.计数器应用
Redis的命令都是原子性的,你可以轻松地利用INCR,DECR命令来构建计数器系统。5.Uniq操作,获取某段时间所有数据排重值
这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。6.实时系统,反垃圾系统
通过上面说到的set功能,你可以知道一个终端用户是否进行了某个操作,可以找到其操作的集合并进行分析统计对比等。没有做不到,只有想不到。7.Pub/Sub构建实时消息系统
Redis的Pub/Sub系统可以构建实时的消息系统,比如很多用Pub/Sub构建的实时聊天系统的例子。8.构建队列系统
使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。9.缓存
Redis能够替代memcached,让你的缓存从只能存储数据变得能够更新数据,因此你不再需要每次都重新生成数据了。性能优于Memcached,数据结构更多样化。MySql+Memcached架构的问题
实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题:
» 1.MySQL需要不断进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工作占据大量开发时间。» 2.Memcached与MySQL数据库数据一致性问题。
» 3.Memcached数据命中率低或down机,大量访问直接穿透到DB,MySQL无法支撑。
» 4.跨机房cache同步问题。
总体上各种各样的NoSQL产品主要用于解决以下几种问题
» 1.少量数据存储,高速读写访问。此类产品通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是Redis最主要的适用场景。» 2.海量数据存储,分布式系统支持,数据一致性保证,方便的集群节点添加/删除。
» 3.这方面最具代表性的是dynamo和bigtable 2篇论文所阐述的思路: 前者是一个完全无中心的设计,节点之间通过gossip方式传递集群信息,数据保证最终一致性,后者是一个中心化的方案设计,通过类似一个分布式锁服务来 保证强一致性,数据写入先写内存和redo log,然后定期compat归并到磁盘上,将随机写优化为顺序写,提高写入性能。
» 4.Schema free,auto-sharding等。比如目前常见的一些文档数据库都是支持schema-free的,直接存储json格式数据,并且支持auto-sharding等功能,比如mongodb。
面对这些不同类型的NoSQL产品,我们需要根据我们的业务场景选择最合适的产品。
Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的 持久化有比较大的差别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用 Redis呢?如果简单地比较Redis与Memcached的区别,大多数都会得到以下观点:
» 1. Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。» 2. Redis支持数据的备份,即master-slave模式的数据备份。
» 3. Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
Redis常用数据类型
Redis最为常用的数据类型主要有以下:
- <code>1.String
- 2.Hash
- 3.List
- 4.Set5.Sorted set6.pub/sub
- 7.Transactions</code>
在具体描述这几种数据类型之前,我们先通过一张图了解下Redis内部内存管理中是如何描述这些不同数据类型的:
首先Redis内部使用一个redisObject对象来表示所有的key和value,redisObject最主要的信息如上图所示:
» type代表一个value对象具体是何种数据类型,
» encoding是不同数据类型在redis内部的存储方式,
比 如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际 redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:"123" "456"这样的字符串。
这 里需要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的,该功能会在后面具体描述。通过上 图我们可以发现Redis使用redisObject来表示所有的key/value数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给 Redis不同数据类型提供一个统一的管理接口,实际作者也提供了多种方法帮助我们尽量节省内存使用,我们随后会具体讨论。
各种数据类型应用和实现方式
下面我们先来逐一的分析下这7种数据类型的使用和内部实现方式:String:
String
数据结构是简单的key-value
类型,value
其实不仅是String
,也可以是数字.
常用命令: set
,get
, decr
, incr
, mget
等。
应用场景: String
是最常用的一种数据类型,普通的 key/ value
存储都可以归为此类.即可以完全实现目前Memcached
的功能,并且效率更高。还可以享受 Redis
的定时持久化,操作日志及 Replication
等功能。除了提供与Memcached
一样的 get
、set
、incr
、decr
等操作外,Redis
还提供了下面一些操作:
- 获取字符串长度
- 往字符串append内容
- 设置和获取字符串的某一段内容
- 设置及获取字符串的某一位(bit)
- 批量设置一系列字符串的内容
实现方式: String
在 redis
内部存储默认就是一个字符串,被redisObject
所引用,当遇到 incr
,decr
等操作时会转成数值型进行计算,此时redisObject
的encoding
字段为 int
。
Hash
常用命令: hget
, hset
, hgetall
等。
应用场景: 在 Memcached
中,我们经常将一些结构化的信息打包成 HashMap
, 在客户端序列化后存储为一个字符串的值,比如用户的昵称、年龄、性别、积分等,这时候在需要修改其中某一项时,通常需要将所有值取出反序列化后,修改某一 项的值,再序列化存储回去。这样不仅增大了开销,也不适用于一些可能并发操作的场合(比如两个并发的操作都需要修改积分)。而Redis
的 Hash
结构可以使你像在数据库中 Update
一个属性一样只修改某一项属性值。
我们简单举个实例来描述下 Hash
的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:
用户ID
为查找的key
,存储的value
用户对象包含姓名,年龄,生日等信息,如果用普通的key/value
结构来存储,主要有以下2种存储方式:
第一种方式将用户ID
作为查找key
,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。
第二种方法是这个用户信息对象有多少成员就存成多少个key-value
对儿,用用户ID+对应属性的名称
作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。
那么Redis
提供的Hash
很好的解决了这个问题,Redis
的Hash
实际是内部存储的Value
为一个HashMap
,并提供了直接存取这个Map
成员的接口,如下图:
也就是说,Key
仍然是用户ID
, value
是一个Map
,这个Map
的key
是成员的属性名,value
是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field
), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。
这里同时需要注意,Redis
提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部Map的操作,由于Redis单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。
实现方式:
上面已经说到 Redis Hash
对应 Value
内部实际就是一个 HashMap
, 实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结 构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
List
常用命令: lpush
, rpush
, lpop
,rpop
, lrange
等。
应用场景:
Redis list
的应用场景非常多,也是 Redis
最重要的数据结构之一,比如 twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。
Lists 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用 Lists
结构,我们可以轻松地实现最新消息排行等功能。Lists
的另一个应用就是消息队列, 可以利用Lists
的 PUSH
操作,将任务存在 Lists
中,然后工作线程再用 POP
操作将任务取出进行执行。Redis
还提供了操作 Lists
中某一段的api,你可以直接查询,删除Lists中某一段的元素。
实现方式:
Redis list
的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。
Set
常用命令: sadd
, spop
, smembers
,sunion
等。
应用场景:
Redis set
对外提供的功能与 list
类似是一个列表的功能,特殊之处在于 set
是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set
是一个很好的选择,并且set
提供了判断某个成员是否在一个set集合内的重要接口,这个也是 list
所不能提供的。
Sets 集合的概念就是一堆不重复值的组合。利用 Redis
提供的 Sets
数据结构,可以存储一些集合性的数据,比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供 了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给 客户端还是存集到一个新的集合中。
实现方式:
set
的内部实现是一个 value
永远为 null
的 HashMap
,实际就是通过计算hash
的方式来快速排重的,这也是 set
能提供判断一个成员是否在集合内的原因。
Sorted Set
常用命令: zadd
, zrange
, zrem
,zcard
等
使用场景:
Redis sorted set
的使用场景与 set
类似,区别是 set
不是自动有序的,而sorted set
可以通过用户额外提供一个优先级(score
)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set
数据结构,比如twitter 的public timeline可以以发表时间作为 score 来存储,这样获取时就是自动按时间排好序的。
另外还可以用 Sorted Sets
来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。
实现方式:
Redis sorted set
的内部使用 HashMap
和跳跃表(SkipList
)来保证数据的存储和有序,HashMap
里放的是成员到score
的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap
里存的 score
,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
Pub/Sub
Pub/Sub
从字面上理解就是发布(Publish
)与订阅(Subscribe
),在Redis
中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
Transactions
谁说NoSQL都不支持事务,虽然Redis的Transactions提供的并不是严格的ACID的事务(比如一串用EXEC提交执行的命令,在 执行中服务器宕机,那么会有一部分命令执行了,剩下的没执行),但是这个Transactions还是提供了基本的命令打包执行的功能(在服务器不出问题 的情况下,可以保证一连串的命令是顺序在一起执行的,中间有会有其它客户端命令插进来执行)。Redis还提供了一个Watch功能,你可以对一个key 进行Watch,然后再执行Transactions,在这过程中,如果这个Watched的值进行了修改,那么这个Transactions会发现并拒 绝执行。
php中使用PhpRedis模块操作Redis的实例
Redis官方已经列出了很多的PHP的客户端,这里推荐另外一个非常受欢迎的php客户端–phpredis。
phpredis/phpredis
A PHP extension for Redis — Read More
安装配置的过程就不在这里说了,下面列出应用方法:
- <code>/**
- * 常用的phpredis方法
- */
- $objRedis = new Redis();
- $objRedis->connect('127.0.0.1', 6379);
- /* 1. set: 写入key-value对 */
- $objRedis->set('key1', 'value1');
- $objRedis->set('key2', 'value2');
- /* 2. get: 根据key得到value */
- echo $objRedis->get('key1');
- /* 3. mget: 根据key的队列获取多个value值 */
- $arrKeys = array('key1', 'key2');
- print_r($objRedis->mget($arrKeys));
- /* 4. setex: 同样是写入key-value对,添加了过期时间 */
- $objRedis->setex('key3', 3600, 'value3');
- /* 5. del: 删除key */
- $objRedis->del('key1');
- /* 6. exists: 判断key是否存在,如存在返回true */
- $isExists = $objRedis->exists('key1');
- if($isExists) {echo 'yes';}else{echo 'no';}
- /* 7. close: 关闭连接 */
- $redisClient -> close();</code>
php使用redis的例子
通常redis作为数据库的cache而存在,这里我们可以看到redis是如何跟php+mysql整合的。
- <code><?php
- /* Functions for redis operations starts here */
- $redisObj = new Redis();
- function openRedisConnection( $hostName, $port){
- global $redisObj;
- // Opening a redis connection
- $redisObj->connect( $hostName, $port );
- return $redisObj;
- }
- function setValueWithTtl( $key, $value, $ttl ){
- try{
- global $redisObj;
- // setting the value in redis
- $redisObj->setex( $key, $ttl, $value );
- }catch( Exception $e ){
- echo $e->getMessage();
- }
- }
- function getValueFromKey( $key ){
- try{
- global $redisObj;
- // getting the value from redis
- return $redisObj->get( $key);
- }catch( Exception $e ){
- echo $e->getMessage();
- }
- }
- function deleteValueFromKey( $key ){
- try{
- global $redisObj;
- // deleting the value from redis
- $redisObj->del( $key);
- }catch( Exception $e ){
- echo $e->getMessage();
- }
- }
- /* Functions for converting sql result object to array goes below */
- function convertToArray( $result ){
- $resultArray = array();
- for( $count=0; $row = $result->fetch_assoc(); $count++ ) {
- $resultArray[$count] = $row;
- }
- return $resultArray;
- }
- /* Functions for executing the mySql query goes below */
- function executeQuery( $query ){
- $mysqli = new mysqli( 'localhost', 'username', 'password', 'someDatabase' );
- if( $mysqli->connect_errno ){
- echo "Failed to connect to MySql:"."(".mysqli_connect_error().")".mysqli_connect_errno();
- }
- $result = $mysqli->query( $query );
- // Calling function to convert result to array
- $arrResult = convertToArray( $result );
- return $arrResult;
- }
- $query = 'select * from sometable limit 1';
- // Calling function to execute sql query
- $arrValues = executeQuery( $query );
- // Making json string
- $jsonValue = json_encode($arrValues);
- // Opening a redis connection
- openRedisConnection( 'localhost', 6379 );
- // Inserting the value with ttl = 1 hours
- setValueWithTtl( 'somekey1', $jsonValue, 3600);
- // Fetching value from redis using the key.
- $val = getValueFromKey( 'somekey1' );
- // Output: the json encoded array from redis
- echo $val;
- // Unsetting value from redis
- deleteValueFromKey( $key );
- ?></code>
php Redis应用中的一些开源程序
ErikDubbelboer/phpRedisAdmin
Simple web interface to manage Redis databases. — Read More
http://dubbelboer.com/phpRedisAdmin/
Shumkov/Rediska
Full-featured PHP client for key-value database Redis — Read More
http://rediska.geometria-lab.net
jdp/redisent
a no-nonsense Redis client for PHP — Read More
http://jdp.github.com/redisent/
nrk/predis
Flexible and feature-complete PHP client library for Redis — Read More
https://github.com/nrk/predis/wiki
sash/php-redis
Redis connector for php — Read More
Reference
• Redis应用场景 http://blog.csdn.net/hguisu/article/details/8836819• How to take advantage of Redis just adding it to your stack http://oldblog.antirez.com/post/take-advantage-of-redis-adding-it-to-your-stack.html
• 国内外三个不同领域巨头分享的Redis实战经验及使用场景 http://www.csdn.net/article/1970-01-01/2817107
• php中使用PhpRedis模块操作Redis的实例 http://www.sudops.com/example-of-use-redis-with-phpredis.html
• Redis作者谈Redis应用场景 http://blog.nosqlfan.com/html/2235.html
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- Redis应用场景
- 再谈Redis应用场景
- Redis应用场景
- Redis应用场景
- redis---应用的场景
- Redis应用场景
- 发现了一个非常好的介绍Codeblocks使用的网站
- Android TextView两端完美对齐解决方案
- java导出Excel通用方法
- 【小工具】简单的小钟表
- 研究性学习的MOOR平台--关键是对接了综评以及资料共享
- Redis应用场景
- Intellj IDEA ,设置Project面板展示内容
- linux上部署web项目解压不成功
- css基础学习之文本和颜色属性
- Ubuntu下如何挂载以及卸载U盘?
- LeetCode-141. Linked List Cycle
- Handler发送消息后消息队列的处理
- fastjson JSONObject 怎么设置成有序
- android知识回顾之播放