一文让你读懂redis,瞬间解决业务诸多问题!

作者: dreamfly 分类: 转载 发布时间: 2018-07-24 10:34

转载自:http://baijiahao.baidu.com/s?id=1595171891425116073


在百花齐放的NoSQL年代,我们究竟需要什么样的NoSQL呢?大概在几年之前,大多数系统都会用的Memcached+MySQL的架构,使用Memcached来作为热点数据缓存,可以说大致统治了这个时代的数据库热点缓存。但是随着互联网业务的速度发展,越来越多的Memcached系统出现这样那样的问题。集中体现为:

1.MySQL需要不断拆库拆表扩容,Memcached也需不断跟着扩容,集群的管理和维护越来越重,问题也日益明显。

2.Memcached与MySQL数据库数据一致性问题,cache同步问题。

3.Memcached如果宕机,大量访问直接穿透到DB,MySQL被拖垮。

但是总结NoSQL的典型应用场景,主要是能够少量数据存储,高速读写访问。最好提供数据落地的功能,保证宕机有新的能够马上阻挡热点流量,而这正是Redis最主要的适用场景。

那么很多开发人员就会有疑问,似乎Redis像一个加强版的Memcached,那么应该使用Memcached,还是Redis呢?

redis与memcached区别

(1)性能方面:他们的性能都已经足够高。无论你使用哪一个,每秒处理请求的次数都不会成为瓶颈。memcached使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结构来做key-value存储,然后压缩处理,使用率也非常高。

(2)数据持久化:如果你对数据持久化和数据同步有所要求,那么选择Redis,因为这两个特性Memcached都不具备。所以升级或者重启系统后缓存数据不会丢失。

(3)数据类型: Redis相比Memcached来说,拥有更多的数据结构(string,hash,set,list,sorted set)和并支持更丰富的数据操作。通常在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。在Redis中,这些复杂的操作通常和一般的GET/SET一样高效。所以,如果你需要缓存能够支持更复杂的结构和操作,redis是最合适的。

(4)网络IO模型方面:Memcached是多线程,分为监听线程、worker线程,引入全局锁,也带来了性能损耗。Redis使用单线程的IO复用模型,将速度优势发挥到最大,各有千秋。

(5)内存管理方面:Memcached使用预分配的内存池的方式,带来一定程度的空间浪费 并且在内存仍然有很大空间时,新的数据也可能会被剔除,而Redis使用现场申请内存的方式来存储数据,不会剔除任何非临时数据。

(6)数据的一致性方面:Memcached提供了cas命令来保证。而Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断。

以上不仅是与memcached的区别,也是redis的特性。

之所以我们生产环境中,大量使用。除了拥有以上优于memcached的特性以外,更多的是有丰富的数据类型,帮助我们解决实际问题,也有集群方案解决单点宕机,击穿DB的风险。也有持久化解决启动之后需要初始化缓存的尴尬。

redis数据类型

下面介绍redis的数据类型,了解数据类型,你就明白,什么业务用,怎么用。一目了然,再不为业务高并发,慢SQL,变态需求而烦恼了。你想要的redis都有。

(1)String:数据结构是简单的key-value类型。

常用命令: set,get,decr,incr,mget 等。

应用场景:String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类。即可以完全实现目前 Memcached 的功能,并且也非常高效。还可以享受Redis的定时持久化,操作日志及 Replication等功能。

(2)Hash

常用命令:hget,hset,hgetall 等。

应用场景:在Memcached中,我们经常将一些结构化的信息打包成HashMap,在客户端序列化后存储为一个字符串,比如用户的昵称、年龄、性别、积分等,这时候在需要修改其中某一项时,通常需要将所有值取出反序列化后,修改某一项的值,再序列化存储回去。这样不仅增大了开销,也不适用于一些可能并发操作的场合(比如两个并发的操作都需要修改积分)。而Redis的Hash结构可以像在数据库中Update一个字段的值一样。只修改到值,而不必取出全部数据内容。

Memcached在Hash的应用场景下,我们要存储一个用户信息对象数据,包含用户ID,姓名,年龄,生日等信息,主要有以下2种存储方式:

No.1将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。

No.2这个用户信息对象有多少成员就存成多少个key-value对,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是大量重复用户ID这样的数据,内存浪费还是非常严重的。

然而Redis提供的Hash很好的解决了这个问题,Redis的Hash内部存储的value为一个HashMap,并且可以直接操作这个Map成员方法。

也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,类似字段,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的field, 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题,很好的解决了问题。

(3)List

常用命令:lpush,rpush,lpop,rpop,lrange等。

应用场景:

Redis 中list的数据结构实现是双向链表,所以可以非常便捷的应用于消息队列(生产者 / 消费者模型)。消息的生产者只需要通过lpush将消息放入 list,消费者便可以通过rpop取出该消息,并且可以保证消息的有序性。由于 Redis 拥有持久化功能,也不需要担心由于服务器故障导致消息丢失。

(4)Set

常用命令:sadd,spop,smembers,sunion 等。

应用场景:

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,set还可以判断某个成员是否在一个set集合内的重要方法。还有一个微博用的关注关系,例如:用户 A,将它的关注和粉丝的用户 id 都存放在两个 set 中:

A:follow:存放 A 所有关注的用户 id

A:followed:存放 A 所有粉丝的用户 id

根据A:follow和A:followed的交集得到与 A 互相关注的用户。

(5)Sorted Set

常用命令:zadd,zrange,zrem,zcard等

使用场景:

Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构。常见sorted set和一个计算热度的算法便可以轻松打造一个热度排行榜,zrevrangebyscore可以得到以分数倒序排列的序列,zrank可以得到一个成员在该排行榜的位置(是分数正序排列时的位置,如果要获取倒序排列时的位置需要用zcard-zrank)。

两大特性用途

(1)Pub/Sub

发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如:群聊功能。

(2)Transactions

提供了基本的命令打包执行的功能,比如微博关注之后,除了添加一个关注ID(1315402)之后,还需要让被关注(19028474)的粉丝数量+1.这就可以进行打包进行:

> MULTI

OK

> sadd(19028474, 1315402)

QUEUED

> INCR 19028474

QUEUED

> EXEC

1) (integer) 1

2) (integer) 1

命令是顺序在一起执行的,中间不会有其实命令插进来执行。

其他常见的redis应用

(1)计数器

数据统计的需求非常普遍,通过redis原子操作计数。例如,点赞数、收藏数、分享数等。

(2)排行榜

排行榜按照得分进行排序,例如,展示最近、最热、点击率最高、活跃度最高等各种类型的top list。

(3)好友列表

例如,用户点赞列表、用户收藏列表、用户关注列表等。

(4)缓存

缓存热点数据,这也是redis最典型的应用之一,根据实际情况,缓存用户信息,缓存session等。

(5)存储时间戳

当用户发完微博后,都通过lpush将它存放在一个 key 为LATEST_WEIBO的list中,之后便可以通过lrange取出当前最新的微博,随着时间的变化,新的内容也在不断变化,保证每次用户刷新出来的都是最新最热的。

(6)判断行为

判断用户行为也是非常普遍,可以知道一个用户是否进行了某个操作。例如,用户是否点赞、用户是否收藏、用户是否分享等,来决定下次打开后,相关按钮是否置灰。

亲爱的程序员,了然于心了吗? 是不是瞬间解决了你业务中的诸多问题?

点赞+关注,更多专业内容与你分享

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!