Redis是什么:
Redis是C语言开发的一个开源的(遵从BSD协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。它是一种NoSQL(not-only sql,泛指非关系型数据库)的数据库。
1.性能优秀,数据在内存中,读写速度非常快,支持并发10W QPS;
2.单进程单线程,是线程安全的,采用IO多路复用机制;
3.丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等;
4.支持数据持久化。可以将内存中数据保存在磁盘中,重启时加载;
5.主从复制,哨兵,高可用;
6.可以用作分布式锁;
7.可以作为消息中间件使用,支持发布订阅
传统MySQL+ Memcached架构遇到的问题
实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题:
MySQL需要不断进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工作占据大量开发时间。
Memcached与MySQL数据库数据一致性问题。
Memcached数据命中率低或down机,大量访问直接穿透到DB,MySQL无法支撑。
跨机房cache同步问题。
少量数据存储,高速读写访问。此类产品通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是Redis最主要的适用场景。
Redis适用场景,如何正确的使用
前面已经分析过,Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用Redis呢?
Redis与Memcached的比较
网络IO模型
Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述字pipe 传递给worker线程,进行读写IO, 网络层使用libevent封装的事件库,多线程模型可以发挥多核作用,但是引入了cache coherency和锁的问题,比如,Memcached最常用的stats 命令,实际Memcached所有操作都要对这个全局变量加锁,进行计数等工作,带来了性能损耗。
(Memcached网络IO模型)
Redis使用单线程的IO复用模型,自己封装了一个简单的AeEvent事件处理框架,主要实现了epoll、kqueue和select,对于单纯只有IO操作来说,单线程可以将速度优势发挥到最大,但是Redis也提供了一些简单的计算功能,比如排序、聚合等,对于这些操作,单线程模型实际会严重影响整体吞吐量,CPU计算过程中,整个IO调度都是被阻塞住的。
Redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
内存管理方面
Memcached使用预分配的内存池的方式,使用slab和大小不同的chunk来管理内存,Item根据大小选择合适的chunk存储,内存池的方式可以省去申请/释放内存的开销,并且能减小内存碎片产生,但这种方式也会带来一定程度上的空间浪费,并且在内存仍然有很大空间时,新的数据也可能会被剔除,原因可以参考Timyang的文章:http://timyang.net/data/Memcached-lru-evictions/
Redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,会在一定程度上存在内存碎片,Redis跟据存储命令参数,会把带过期时间的数据单独存放在一起,并把它们称为临时数据,非临时数据是永远不会被剔除的,即便物理内存不够,导致swap也不会剔除任何非临时数据(但会尝试剔除部分临时数据),这点上Redis更适合作为存储而不是cache。
数据一致性问题
Memcached提供了cas命令,可以保证多个并发访问操作同一份数据的一致性问题。 Redis没有提供cas 命令,并不能保证这点,不过Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断。
存储方式及其它方面
Memcached基本只支持简单的key-value存储,不支持枚举,
不支持持久化和复制等功能
Redis除key/value之外,还支持list,set,sorted set,hash等众多数据结构,提供了KEYS
进行枚举操作,但不能在线上使用,如果需要枚举线上数据,Redis提供了工具可以直接扫描其dump文件,枚举出所有数据,
Redis还同时提供了持久化和复制等功能。
value的大小:redis可以达到1GB,而memcache只有1MB。
关于不同语言的客户端支持
在不同语言的客户端方面,Memcached和Redis都有丰富的第三方客户端可供选择,不过因为Memcached发展的时间更久一些,目前看在客户端支持方面,Memcached的很多客户端更加成熟稳定,而Redis由于其协议本身就比Memcached复杂,加上作者不断增加新的功能等,对应第三方客户端跟进速度可能会赶不上,有时可能需要自己在第三方客户端基础上做些修改才能更好的使用。
根据以上比较不难看出,当我们不希望数据被踢出,或者需要除key/value之外的更多数据类型时,或者需要落地功能时,使用Redis比使用Memcached更合适。
关于Redis的一些周边功能
Redis除了作为存储之外还提供了一些其它方面的功能,比如聚合计算、pubsub、scripting等,对于此类功能需要了解其实现原理,清楚地了解到它的局限性后,才能正确的使用,比如pubsub功能,这个实际是没有任何持久化支持的,消费方连接闪断或重连之间过来的消息是会全部丢失的,又比如聚合计算和scripting等功能受Redis单线程模型所限,是不可能达到很高的吞吐量的,需要谨慎使用。
总结:
Redis使用最佳方式是全部数据in-memory。
Redis更多场景是作为Memcached的替代者来使用。
当需要除key/value之外的更多数据类型支持时,使用Redis更合适。
当存储的数据不能被剔除时,使用Redis更合适。
1.整体模型:单进程单线程事件驱动模式。
Redis在主处理流程中,采用了单进程接受各种client请求并返回结果,整体处理流程采用事件驱动的方式进行。通过其IO复用的方式监听aeEventLoop事件,在事件处理的过程中,这种模式对处理函数的要求:进行一次事件处理需要尽可能地快。因此会有以下几种处理方法:
1.对于非长时间处理事件,直接处理。如set命令;
2.对于需要长时间处理的事件,分步处理,直至完成。如rehash过程,在单次事件处理过程中,每次只移动一个桶。
3.对于阻塞函数,如从磁盘读取vm数据等,采用异步的模式。从磁盘load数据,是一个较为耗时的操作,如处理函数中直接读取数据,将会阻塞整体的单线程处理其他的client请求。
多线程开发的复杂性是我们所清楚的。采用单进程单线程的模式,可以避免很多复杂性,另外事务性操作,无须额外加锁,大大降低了开发难度。
2.IO复用
Redis的IO复用层,可以看作是一个tiny libevent,其实现只有四个文件,ae.c, ae_select.c, ae_kqueue.c,ae_epoll.c。一目了然,ae是事件监听总的interface,select、kqueque、epoll是三种可选的IO复用方式。小而够用,简洁高效,充分体现了redis的设计理念。Redis Default:select,C10K max。
3.事件监听
在单线程事件驱动模型中,往往会遇到两种任务,定时处理任务及事件触发任务,于是会有如下问题:事件触发任务在无任务时,会处于阻塞状态;定时任务要求定时处理,于是往往会有如下两种处理方式:
1. 如果定时任务时间间隔为t,一般设IO复用层的超时时间为t/10,这样可以保证定时任务得到及时处理,在调用所有cron任务时,会做间隔时间判断。
2. 计算当前事件与最近的定时任务开始时间的间隔,设置IO复用超时时间为该事件。这样定时任务也能得到及时处理。
注意:以上定时任务的处理时间,都为估约时间,非精确时间。前一种方式每轮计算量少,当容易引起空转,后一种计算量大,但减少了空转次数。Redis采用的是后一种方式。
这里也许有人会问:为什么不采用sigaction、setitimer等设置精确时钟,以后再也不用为cron事件做额外处理。原因如下:
定时时钟,往往会让进程陷入内核态,内核软中断往往会打破用户态一个函数的完整性,因此会破坏相关的状态转移;另外加入软中断的程序,将可能为程序带来不可避免地复杂性。
4.数据结构
整个redis中,没有任何专门的内存池结构。所有内存分配,Redis全是size+malloc的zmalloc分配,其常见的小对象,在intset,ziplist等数据结构地以数组方式申请,并不断用realloc的方式resize,间接地体现了内存池的思想,但却没有实现一个内存池管理模块。
Redis有八种淘汰策略:
volitile-lru:从已设置过期时间的KV集中优先对最近最少使用(less recently used)的数据淘汰
volitile-ttl:从已设置过期时间的KV集中优先对剩余时间短(time to live)的数据淘汰
volitile-random:从已设置过期时间的KV集中随机选择数据淘汰
allkeys-lru:从所有KV集中优先对最近最少使用(less recently used)的数据淘汰
allkeys-random:从所有KV集中随机选择淘汰
noeviction:不淘汰策略,若超过最大内存,返回错误消息
volatile-lfu:从已设置过期时间的KV集中,通过统计访问频率,将访问频率最少,即最不经常使用的KV淘汰
allkeys-lfu:从所有KV集中,通过统计访问频率,将访问频率最少,即最不经常使用的KV淘汰
Redis持久化
redis为了保证效率,数据缓存在了内存中,但是会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件中,以保证数据的持久化。Redis的持久化策略有两种:
RDB:快照形式是直接把内存中的数据保存到一个dump的文件中,定时保存,保存策略。
AOF:把所有的对Redis的服务器进行修改的命令都存到一个文件里,命令的集合。Redis默认是快照RDB的持久化方式。
当Redis重启的时候,它会优先使用AOF文件来还原数据集,因为AOF文件保存的数据集通常比RDB文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存。
默认Redis是会以快照"RDB"的形式将数据持久化到磁盘的一个二进制文件dump.rdb。工作原理简单说一下:当Redis需要做持久化时,Redis会fork一个子进程,子进程将数据写到磁盘上一个临时RDB文件中。当子进程完成写临时文件后,将原来的RDB替换掉,这样的好处是可以copy-on-write。
RDB的优点是:这种文件非常适合用于备份:比如,你可以在最近的24小时内,每小时备份一次,并且在每个月的每一天也备份一个RDB文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB非常适合灾难恢复。
RDB的缺点是:如果你需要尽量避免在服务器故障时丢失数据,那么RDB不合适你。
使用AOF做持久化,每一个写命令都通过write函数追加到appendonly.aof中,配置方式如下:
appendfsync yes
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
AOF可以做到全程持久化,只需要在配置中开启 appendonly yes。这样redis每执行一个修改数据的命令,都会把它添加到AOF文件中,当redis重启时,将会读取AOF文件进行重放,恢复到redis关闭前的最后时刻。
AOF的优点是:会让redis变得非常耐久。可以设置不同的fsync策略,aof的默认策略是每秒钟fsync一次,在这种配置下,就算发生故障停机,也最多丢失一秒钟的数据。
AOF的缺点是:对于相同的数据集来说,AOF的文件体积通常要大于RDB文件的体积。根据所使用的fsync策略,AOF的速度可能会慢于RDB。
如果你非常关心你的数据,但仍然可以承受数分钟内的数据丢失,那么可以额只使用RDB持久。AOF将Redis执行的每一条命令追加到磁盘中,处理巨大的写入会降低Redis的性能。
数据库备份和灾难恢复:定时生成RDB快照非常便于进行数据库备份,并且RDB恢复数据集的速度也要比AOF恢复的速度快。当然了,redis支持同时开启RDB和AOF,系统重启后,redis会优先使用AOF来恢复数据,这样丢失的数据会最少。
AOF重写:
AOF采用文件追加方式,这会导致AOF文件越来越大,为此,Redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阀值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令bgrewriteaof。
AOF重写的基本原理:
1)在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的AOF文件,并将其包含的指令进行分析压缩并写入一个临时文件中。
2)与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
3)当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将
内存中缓存的写指令追加到新的AOF文件中。
4)当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中。
Redis主从复制
1.从节点执行slaveof[masterIP][masterPort],保存主节点信息
2.从节点中的定时任务发现主节点信息,建立和主节点的socket连接
3.从节点发送Ping信号,主节点返回Pong,两边能互相通信
4.连接建立后,主节点将所有数据发送给从节点(数据同步)
5.主节点把当前的数据同步给从节点后,便完成了复制的建立过程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。
复制的基本原理:
1)slave启动时,会向master发送sync命令,2.8版本后发送psync,以实现增量复制。
2)主数据库接到sync请求后,会在后台保存快照,也就是实现RDB持久化,并将保存快照期间接收到的命令缓存起来。
3)快照完成后,主数据库会将快照文件和所有缓存的命令发送给从数据库。
4)从数据库接收后,会载入快照文件并执行缓存的命令,从而完成复制的初始化。
5)在数据库使用阶段,主数据库会自动把每次收到的写命令同步到从数据库。
主从复制会存在以下问题:
1.一旦主节点宕机,从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。
2.主节点的写能力受到单机的限制。
3.主节点的存储能力受到单机的限制。
4.原生复制的弊端在早期的版本中也会比较突出,比如:redis复制中断后,从节点会发起psync。此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时,可能会造成毫秒或秒级的卡顿。
解决方案:Redis Sentinel(哨兵)
Redis Sentinel(哨兵):
Redis Sentinel(哨兵)主要功能包括主节点存活检测、主从运行情况检测、自动故障转移、主从切换。Redis Sentinel最小配置是一主一从。
Redis的Sentinel(哨兵)系统可以用来管理多个Redis服务器,该系统可以执行以下四个任务:
1.监控:不断检查主服务器和从服务器是否正常运行。
2.通知:当被监控的某个redis服务器出现问题,Sentinel通过API脚本向管理员或者其他应用程序发出通知。
3.自动故障转移:当主节点不能正常工作时,Sentinel会开始一次自动的故障转移操作,它会将与失效主节点是主从关系的其中一个从节点升级为新的主节点,并且将其他的从节点指向新的主节点,这样人工干预就可以免了。
4.配置提供者:在Redis Sentinel模式下,客户端应用在初始化时连接的是Sentinel节点集合,从中获取主节点的信息。
Redis Sentinel(哨兵)工作原理:
1、每个Sentinel节点都需要定期执行以下任务:每个Sentinel以每秒一次的频率,向它所知的主服务器、从服务器以及其他的Sentinel实例发送一个PING命令。
2.如果一个实例距离最后一次有效回复PING命令的时间超过down-after-milliseconds所指定的值,那么这个实例会被Sentinel标记为主观下线。
3.如果一个主服务器被标记为主观下线,那么正在监视这个服务器的所有Sentinel节点,要以每秒一次的频率确认主服务器的确进入了主观下线状态。
4.如果一个主服务器被标记为主观下线,并且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线。
5.一般情况下,每个Sentinel会以每10秒一次的频率向它已知的所有主服务器和从服务器发送INFO命令,当一个主服务器被标记为客观下线时,Sentinel向下线主服务器的所有从服务器发送INFO命令的频率,会从10秒一次改为每秒一次。
6.Sentinel和其他Sentinel协商客观下线的主节点的状态,如果处于SDOWN状态,则投票自动选出新的主节点,将剩余从节点指向新的主节点进行数据复制。
7.当没有足够数量的Sentinel同意主服务器下线时,主服务器的客观下线状态就会被移除。当主服务器重新向Sentinel的PING命令返回有效回复时,主服务器的主观下线状态就会被移除。
Redis 适合的场景:
(1)会话缓存(Session Cache)
最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。
(2)全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进。
Magento提供一个插件来使用Redis作为全页缓存后端。
(3)队列
Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。
(4)排行榜/计数器
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
(5)发布/订阅
最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统。
- 大小: 61.1 KB
分享到:
相关推荐
**Redis简介** Redis,全名Remote Dictionary Server,是一款开源、高性能、支持网络、基于键值对的数据存储系统。...无论是在Windows还是其他操作系统上,正确安装和使用Redis及其客户端是开发过程中的重要一环。
以下将详细介绍Redis、Redis Workbench及其在Windows环境中的应用。 **Redis基础知识** Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,它可以作为数据库、缓存和消息中间件。Redis...
2. **查看键值对**:在Web界面中,用户可以直观地看到各个键及其对应的值,包括字符串、哈希、列表、集合和有序集合等多种数据结构。 3. **搜索和过滤**:提供搜索功能,帮助用户快速定位特定键或值。 4. **编辑和...
综上所述,Redis的学习涵盖了从基本概念到高级特性的全面内容,对于理解和掌握NoSQL数据库及其在现代Web应用中的作用至关重要。通过深入学习和实践,开发者能够充分利用Redis的优势,优化应用程序的性能和可扩展性。
### Redis 数据类型及其应用场景 1. **字符串(String)**:最基础的数据类型,常用于存储单个值,如网站计数器。 2. **哈希(Hash)**:用于存储键值对,适合表示对象,如用户信息。 3. **列表(List)**:有序的...
本文将详细介绍这款被称为“Redis最好用的桌面连接工具”的Redis Desktop Manager及其安装过程。 Redis Desktop Manager是一款跨平台的图形化界面工具,它支持Windows、Mac OS X以及Linux操作系统,使得开发者和...
在实际应用中,了解Redis的数据结构特性及其在缓存、消息队列、计数器等方面的应用,是提高系统性能的关键。同时,定期检查和优化Redis的内存使用,监控其性能指标,也是运维过程中不可忽视的环节。 总之,Redis在...
在本文中,我们将深入探讨 Redis 集群及其相关的接口,特别是针对 `redis-3.0.0.gem` 文件的知识点。 首先,`redis-3.0.0.gem` 是一个 Ruby 的Gem包,它包含了与 Redis 集群交互所需的客户端库。Ruby 是一种流行的...
- **位置**: Redis在缓存系统中的定位。 - **作用**: 解释Redis如何与其他系统交互以及其核心功能。 - **第2章:redis事件驱动详解** - **概述**: Redis采用事件驱动模型来处理网络请求。 - **结构**: 介绍事件...
2. **数据浏览**:通过键值对视图,用户可以直观查看Redis中的键及其对应的值,包括字符串、哈希、列表、集合和有序集合等多种数据结构。此外,还可能支持搜索功能,以便快速定位特定键。 3. **数据操作**:客户端...
以下是关于Redis集群及其在Linux下部署的详细知识点: 1. **Redis集群原理**: - Redis集群通过分片(Sharding)将数据分散到多个节点上,每个节点负责一部分数据,实现数据的水平扩展。 - 集群中的每个节点都有...
以下是一些关于Redis的面试题及其答案,帮助你深入理解Redis的核心特性和使用技巧。 **面试题1:Redis的主要数据类型有哪些?** 答:Redis支持五种基本数据类型: 1. 字符串(String):可以存储字符串、数字等。 ...
理解 Redis 的工作原理,特别是其分布式特性和故障恢复机制,有助于快速定位和解决问题。此外,保持 Redis 版本的更新,定期进行性能优化和安全性检查,也是防止类似问题发生的有效手段。在日常运维中,应建立完善的...
以下是一些主要的Redis命令及其应用场景: 1. **字符串(Strings)**: - `SET key value`:设置键值。 - `GET key`:获取键的值。 - `INCR key`:将整数值增加1。 - `EXPIRE key seconds`:为键设置过期时间。 2...
1. **数据浏览与编辑**:Redis Desktop Manager允许用户直接在界面上查看Redis服务器中的键(keys)及其对应的值(values)。它可以显示不同类型的数据,如字符串、哈希、列表、集合和有序集合,并支持直接编辑和...
数据浏览功能则让使用者可以直观地查看Redis中的键(keys)及其对应的值(values)。不同的数据类型,如字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)和有序集合(sorted sets),在界面上都有...