问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Redis - 功能特点、应用场景、单线程模型详解(附:与Memcache对比)

创作时间:
作者:
@小白创作中心

Redis - 功能特点、应用场景、单线程模型详解(附:与Memcache对比)

引用
1
来源
1.
https://www.hangge.com/blog/cache/detail_3441.html

Redis是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、向键值对(Key-Value)数据类型的NoSQL数据库,可以满足对海量数据的快速读写需求,并提供多种语言的API。

一、基本介绍

1,什么是 Redis

Redis是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、向键值对(Key-Value)数据类型的NoSQL数据库,可以满足对海量数据的快速读写需求,并提供多种语言的API。

2,Redis 的起源

  • Redis是意大利人antirez发明的,起初是为了解决网站的负载问题。作者当初运营了一个访客信息网站,存储访客的浏览记录,通过列表的形式进行维护。
  • 当时网站的数据存储使用的是MySQL,随着用户越来越多,需要维护的列表数量也越来越多,要执行的入栈和出栈操作也越来越多。使用MySQL执行入栈和出栈操作是需要硬盘读写操作的,所以程序的性能严重受制于硬盘的I/O。
  • 作者希望在不改变硬件的基础上,通过提升列表的性能来解决负载问题。于是决定自己写一个具有列表结构的内存数据库原型,最重要的是将数据存储于内存而不是磁盘,这样程序的性能就不会受制于磁盘I/O。
  • 当时发现这样确实解决了问题,所以作者使用C语言重写了这个内存数据库原型,并增加了持久化等功能。这样Redis就诞生了。

3,Redis 的特点

  • 高性能:官方提供的数据,Redis读的速度是110000次/s,写的速度是81000次/s。
  • 原子性:Redis支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
  • 持久存储:支持RDB和AOF这两种方式的持久化,可以把内存中的数据持久化到磁盘中。
  • 支持主从复制:主机会自动将数据同步到从机,可以进行读写分离,以实现负载均衡及高可用。
  • 支持集群:从3.0版本开始支持。
  • 数据结构丰富:支持string类型的value外还支持hash、set、zset、list等数据结构。

4,一个 Redis 实例最多能存放多少 key?

答案是没有限制。因为Redis本身是不会限制存储多少key的,但是Redis是基于内存的,它的存储极限是系统中的可用内存值,如果内存存满了,那就无法再存储key了。

5,Redis 的应用场景

(1)做缓存

  • 这是Redis使用最多的场景,它不仅够替代Memcached。而且相比于memcached,Redis还提供了丰富的数据结构,并且提供RDB和AOF等持久化机制。
  • 使用Redis,不需要每次都重新生成数据,而且它的缓存速度和查询速度比较快,使用也比较方便。比如,实现数据查询、缓存新闻消息内容、缓存商品内容或购物车等。

(2)做计数器应用

  • Redis的命令具有原子性,它提供了INCR、DECR、GETSET、INCRBY等相关命令来构建计数器系统。
  • 可以使用Redis来记录一个热门帖子的转发数、评论数。通过Redis的原子递增,可以实现在任何时候封锁一个IP地址等。

(3)实现消息队列系统

  • Redis运行稳定,速度快,支持模式匹配,也可以实现消息订阅发布。
  • Redis还有阻塞队列的命令,能够让一个程序在执行时被另一个程序添加到队列中。比如,实现秒杀、抢购等。

(4)做实时系统、消息系统

  • 可以利用Redis的set功能做实时系统,来查看某个用户是否进行了某项操作,对其行为进行统计对比。
  • 也可以利用Redis的Pub/Sub构建消息系统,如在线聊天系统。

(5)实现排行榜应用

  • 排行榜的实现利用了Redis的有序集合。比如,对上百万个用户的排名,采用其他数据库来实现是非常困难的,而利用Redis的ZADD、ZREVRANGE、ZRANK等命令可以轻松实现排名并获取排名的用户。

(6)做数据过期处理

  • 我们可以将sortedset的score值设置成过期时间的时间戳,然后通过过期时间排序,找出过期的数据进行删除。
  • 可以采用过期属性来确认一个关键字在什么时候应该被删除。也可以利用UNIX时间作为关键字,将列表按时间排序。对currenttime和timeto_live进行检索,查询出过期的数据,进而删除。

(7)做大型社交网络

  • 任何架构的系统或网站都可以与Redis很好地结合,同样,采用Redis可以很好地与社交网络相结合,如新浪微博、Twitter等。
  • 比如,我们在使用QQ时,进行实时聊天就需要Redis的支持;又如,我们在浏览微博时,实现信息的刷新、浏览查看等也需要Redis的支持。

(8)分布式集群架构中的session分离

  • 采用分布式集群部署,可以满足一个Web应用系统被大规模访问的需要。而要实现分布式集群部署,就要解决session统一的问题。通常可以采用Redis来实现session共享机制,以达到session统一的目的。

(9)分布式锁实现

  • 在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用Redis自带的SETNX命令实现分布式锁,除此之外,还可以使用官方提供的RedLock分布式锁实现。

(10)位操作

  • reids位操作也叫位数组操作、bitmap,它提供了SETBIT、GETBIT、BITCOUNT、BITTOP四个命令用于操作二进制位数组。每个位可以存储0或1,因此Redis的位操作非常灵活,可以用于多种应用场景。
  • 通过在Redis中使用位操作,可以实现一个非常节省内存的布隆过滤器,用于判断某个元素是否存在于集合中。
  • 使用Redis的位操作来实现计数器,其中每个位代表一个计数值。这在一些场景下可以用于统计用户的活跃状态、点击次数等。
  • 在某些场景下,可以使用位操作来构建位图索引,用于快速检索某些属性的相关数据。例如,可以用位图来表示用户的活跃状态,每个位表示一个小时,从而可以迅速了解用户的活跃时间。

6,Redis 线程模型

(1)Redis6.0之前,Redis是一个完全的单线程服务。即Redis在处理客户端的请求时,包括读socket、解析、执行、写socket等都由一个顺序串行的主线程处理。作者之所以这么设计,主要是为了保证Redis的快速和高效。如果涉及多线程,则需要使用锁机制来解决并发问题,这样执行效率反而会打折扣。

(2)Redis6.0之后改多线程,但要注意多线程并非是完全摒弃单线程,redis还是使用单线程模型来处理客户端的请求,只是使用多线程来处理数据的读写和协议解析,执行命令还是使用单线程。这样做的目的是因为redis的性能瓶颈在于网络IO而非CPU,使用多线程能提升IO读写的效率,从而整体提高redis的性能。

提示:使用Redis时,几乎不存在CPU成为瓶颈的情况,Redis主要受限于内存和网络。例如在一个普通的Linux系统上,Redis通过使用pipelining每秒可以处理100万个请求,所以如果应用程序主要使用O(N)或O(log(N)) 的命令,它几乎不会占用太多CPU。

附一:Redis 和 Memcached 的对比

1,二者之间的共同点与区别

(1)Redis与Memcached共同点:

  • 都是基于内存的数据库,一般都用来当做缓存使用。
  • 都有过期策略。
  • 两者的性能都非常高。

(2)Redis与Memcached区别:

  • Redis支持的数据类型更丰富(String、Hash、List、Set、ZSet),而Memcached只支持最简单的key-value数据类型;
  • Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memcached没有持久化功能,数据全部存在内存之中,Memcached重启或者挂掉后,数据就没了;
  • Redis原生支持集群模式,Memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;
  • Redis支持发布订阅模型、Lua脚本、事务等功能,而Memcached不支持;

2,为什么 Memcache 使用多线程,而 Redis 使用单线程模式?

(1)Redis使用单线程模式的理由有很多。首先有两个显著的优点:

  • 不会引入上下文切换的开销,也没有多线程访问资源的竞争问题。
  • 其次Redis是一个内存数据库,操作很快,所以它的性能瓶颈只可能出现在网络IO和内存大小上,是不是多线程影响不大。
  • 最后,单线程模式比较好理解,调试起来也容易。

(2)Memcache采用了多线程设计,那么带来的后果就是会有线程上下文切换的开支,并且多线程模式下需要引入锁来保护共享资源。优点则是Memcache会比Redis更充分地利用多核CPU的性能。

(3)当然,这就是一个设计者的偏好问题,没有说哪种设计一定更好。网上发布了Redis和Memcache的性能对比。基本上就是有些时候Redis好一点,有些时候Memcache好一点。

附二:Redis 为什么引入多线程?

(1)Redis在6.0引入多线程的原因只有一个,那就是性能。当Redis启用了多线程之后,里面的主线程就要负责接收事件、创建连接、执行命令。Redis的IO线程就负责读写数据。

注意:默认情况下,多线程模式是被禁用了的,需要显式地开启。

(2)整个请求的处理过程如下:

  • 当客户端发出请求的时候,主线程会收到一个可读的事件,于是它把对应的客户端丢到可读的客户端列表。
  • 一个IO线程会被安排读写这个客户端发过来的命令,并且解析好。
  • 紧接着主线程会执行IO线程解析好的命令,并且把响应放回到可写客户端列表里面。
  • IO线程负责写回响应。整个过程就结束了。

(3)所以整个Redis在多线程模式下,可以看作是单线程Reactor、单线程Acceptor和多线程Handler的Reactor模式。只不过Redis的主线程同时扮演了Reactor中分发事件的角色,也扮演了接收请求的角色。同时多线程Handler在Redis里面仅仅是读写数据,命令的执行还是依赖于主线程来进行的。

提示:虽然说现在Redis的IO改成多线程之后能够有效利用多核性能,但是大部分情况下都是不推荐使用多线程模式的。道理很简单,Redis在单线程模式下的性能就足以满足绝大多数使用场景了,那么用不用多线程已经无所谓了。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号