Redis是单进程单线程的,Redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。程序员
多线程处理会涉及到锁,并且多线程处理会设计到线程切换而消耗CPU。由于CPU不会Redis的瓶颈,Redis的瓶颈最有多是机器内存或者网络带宽。单线程没法发挥多核CPU性能,不过能够经过在单机开启Redis实例来解决。web
EXPIRE
和PERSIST
命令。redis
内存。算法
Redis为了达到最快的读写速度将数据都读到内存中,并经过异步的方式将数据写入磁盘。数据库
因此redis具备快速和数据持久化的特征。若是不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。后端
在内存愈来愈便宜的今天,redis将会愈来愈受欢迎。 若是设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。缓存
Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每一个key经过CRC16校验后对16384取模来决定放置哪一个槽,集群的每一个节点负责一部分hash槽。安全
一次请求/响应服务器能实现处理新的请求即便旧的请求还未被响应。这样就能够将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。性能优化
这就是管道(pipelining),是一种几十年来普遍使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。服务器
事务是一个单独的隔离操做:事务中的全部命令都会序列化、按顺序地执行。事务在执行的过程当中,不会被其余客户端发送来的命令请求所打断。
事务是一个原子操做:事务中的命令要么所有被执行,要么所有都不执行。
MULTI
、EXEC
、DISCARD
、WATCH
Redis的内存回收主要围绕如下两个方面:
Redis过时策略一般有如下三种:
定时过时 每一个设置过时时间的key都须要建立一个定时器,到过时时间就会当即清除。该策略能够当即清除过时的数据,对内存很友好;可是会占用大量的CPU资源去处理过时的数据,从而影响缓存的响应时间和吞吐量。
惰性过时 只有当访问一个key时,才会判断该key是否已过时,过时则清除。该策略能够最大化地节省CPU资源,却对内存很是不友好。极端状况可能出现大量的过时key没有再次被访问,从而不会被清除,占用大量内存。
按期过时 每隔必定的时间,会扫描必定数量的数据库的expires字典中必定数量的key,并清除其中已过时的key。该策略是前二者的一个折中方案。经过调整定时扫描的时间间隔和每次扫描的限定耗时,能够在不一样状况下使得CPU和内存资源达到最优的平衡效果。
Redis中同时使用了惰性过时和按期过时两种过时策略。
在Redis中,容许用户设置最大使用内存大小server.maxmemory
,当Redis内存数据集大小上升到必定大小的时候,就会执行数据淘汰策略
RDB持久化 原理是将Redis在内存中的数据记录定时dump到磁盘上的RDB文件。 指定的时间间隔内将内存中的数据集快照写入磁盘,实际操做过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换以前的文件,用二进制压缩存储。
AOF(append only file)持久化 原理是将Redis的操做日志以追加的方式写入文件。 以日志的形式记录服务器所处理的每个写、删除操做,查询操做不会记录,以文本的方式记录,能够打开文件看到详细的操做记录。当服务器重启的时候会从新执行这些命令来恢复原始的数据。AOF命令以Reids协议追加保存每次写的操做到文件末尾。Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。
RDB持久化
AOF持久化 与RDB持久化相对应,AOF的优势在于支持秒级持久化、兼容性好,缺点是文件大,恢复速度慢,对性能影响大
在介绍持久化策略以前,首先要明白不管是RDB仍是AOF,持久化的开启都是要付出性能方面的代价的。对比RDB持久化,一方面是bdsave在进行fork操做时Redis主进程会阻塞,另外一方面,子进程向硬盘写数据也会带来IO压力;对于AOF持久化,向硬盘写数据的频率大大提升(everysec策略下为秒级),IO压力更大,设置可能形成AOF追加阻塞文件。此外,AOF文件的重写与RDB的basave相似,会有fork时的阻塞和子进程的IO压力问题。相对来讲,因为AOF向硬盘中写数据的频率更高,所以对Redis主进程性能的影响会更大。
在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不一样状况,会有各类各样的持久化策略;如彻底不使用任何持久化,使用RDB或AOF一种,或同事开启RDB和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一块儿考虑,由于主从复制与持久化一样具备数据备份的功能,并且主机master和从机slave能够独立的选择持久化方案。
分区可让Redis管理更大的内存,Redis将可使用全部机器的内存。若是没有分区,你最多只能使用一台机器的内存。分区使Redis的计算能力经过简单地增长计算机获得成倍提高,Redis的网络带宽也会随着计算机和网卡的增长而成倍增加。
为了是在部分节点失败或者大部分节点没法通讯的状况下集群仍然可用,因此集群是用了主从复制模型,每一个节点都会有N-1个复制品
Redis并不能保证数据强一致性,这意味着在实际中集群在特定的条件下可能会丢失写操做
异步复制。
尽量使用散列表(hashes),散列表(是说列表里面存储的数少)使用的内存很是小,因此你应该尽量的将你的数据模型抽象到一个散列表里面,好比你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户全部信息存储到一张散列表中。
单机版
特色:简单
存在问题:
主从复制
Redis的复制(replication)功能容许用户根据一个Redis服务器来建立任意多个该服务器的复制品,其中被复制的服务器为主服务器(master),而经过复制建立出来的服务器复制品则为从服务器(slave)。主要主从服务器之间的网络链接正常,主从服务器二者会具备相同的数据,主服务器就会一直将发生在本身身上的数据更新同步给从服务器,从而一直保证主从服务器的数据相同。
问题:
哨兵
Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运做正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 能够经过 API 向管理员或者其余应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工做时, Sentinel 会开始一次自动故障迁移操做。
特色:
缺点:
集群(proxy型)
Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器; Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议。
特色:
缺点:
集群(直连型)
从redis 3.0以后版本支持redis-cluster集群,Redis-Cluster采用无中心结构,每一个节点保存数据和整个集群状态,每一个节点都和其余全部节点链接。
特色:
缺点:
先拿setnx来争抢锁,抢到以后,再用expire给锁加一个过时时间防止锁忘记了释放。 若是在setnx以后执行expire以前进程意外crash或者要重启维护了,那会怎么样? set指令有很是复杂的参数,这个应该是能够同时把setnx和expire合成一条指令来用的!
般使用 list 结构做为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep一会再重试。
缺点:
缓存穿透
通常的缓存系统,都是按照key去缓存查询,若是不存在对应的value,就应该去后端系统查找(好比DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统形成很大的压力。这就叫作缓存穿透。
如何避免?
对查询结果为空的状况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了以后清理缓存。
对必定不存在的key进行过滤。能够把全部的可能存在的key放到一个大的Bitmap中,查询时经过该bitmap过滤。
缓存雪崩 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力,致使系统崩溃。
如何避免?
这里的并发指的是多个redis的client同时set key引发的并发问题。其实redis自身就是单线程操做,多个client并发操做,按照先到先执行的原则,先到的先执行,其他的阻塞。固然,另外的解决方案是把redis.set操做放在队列中使其串行化,必须的一个一个执行。
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。
这样就能够避免在用户请求的时候,先查询数据库,而后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
解决思路:
目的就是在系统上线前,将数据加载到缓存中。
能够在同一个服务器部署多个Redis的实例,并把他们看成不一样的服务器来使用,在某些时候,不管如何一个服务器是不够的, 因此,若是你想使用多个CPU,你能够考虑一下分片(shard)。
针对运行实例,有许多配置选项能够经过 CONFIG SET 命令进行修改,而无需执行任何形式的重启。 从 Redis 2.2 开始,能够从 AOF 切换到 RDB 的快照持久性或其余方式而不须要重启 Redis。检索 CONFIG GET *
命令获取更多信息。 但偶尔从新启动是必须的,如为升级 Redis 程序到新的版本,或者当你须要修改某些目前 CONFIG 命令还不支持的配置参数的时候。
若是达到设置的上限,Redis的写命令会返回错误信息(可是读命令还能够正常返回。)或者你能够将Redis当缓存来使用配置淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。
既然Redis是如此的轻量(单实例只使用1M内存),为防止之后的扩容,最好的办法就是一开始就启动较多实例。即使你只有一台服务器,你也能够一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来讲这操做起来可能比较麻烦,可是从长久来看作这点牺牲是值得的。这样的话,当你的数据不断增加,须要更多的Redis服务器时,你须要作的就是仅仅将Redis实例从一台服务迁移到另一台服务器而已(而不用考虑从新分区的问题)。一旦你添加了另外一台服务器,你须要将你一半的Redis实例从第一台机器迁移到第二台机器。
Redis有着更为复杂的数据结构而且提供对他们的原子性操做,这是一个不一样于其余数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。Redis运行在内存中可是能够持久化到磁盘,因此在对不一样数据集进行高速读写时须要权衡内存,应为数据量不能大于硬件内存。在内存数据库方面的另外一个优势是, 相比在磁盘上相同的复杂的数据结构,在内存中操做起来很是简单,这样Redis能够作不少内部复杂性很强的事情。 同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,由于他们并不须要进行随机访问。
好文推荐: