赞
踩
Redis的的是完全开源免费的,遵守BSD协议,是一个高性能基于内存的键值(key-value)数据库。是当前最热门的的的NoSql数据库之一,也被人们称为数据结构服务器。
Redis是一个key-value兼职对数据库。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。
由于内存的读写速度远快于硬盘,因此Redis的的的在性能上对比其他基于硬盘存储的数据库有非常明显的优势。
项目中使用Redis的的的,主要是从两个角度去考虑:性能、并发。
(1)存储方式
Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。
Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。支持数据的备份,即master-slave模式的数据备份。
(2)数据支持类型
Memcache对数据类型支持相对简单。
Redis有较复杂的数据类型。
(3)使用底层模型不同
它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。
Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
(4)value大小
redis最大可以达到1GB,而memcache只有1MB。
Redis数据类型 | 容量 / 个数 |
---|---|
String | 一个String类型的value最大可以存储512M |
List / Set /Hash /Sorted Set | 元素个数最多为2^32-1个,也就是4294967295个 |
RDB:RDB 持久化机制,是对 redis 中的数据执行周期性的持久化。
AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在 redis 重启的时候,可以通过重新按顺序执行 AOF 日志中的写入指令来重新构建整个数据集。
RDB 会生成多个数据文件,每个数据文件都代表了某一个时刻中 redis 的完整数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,以预定好的备份策略来定期备份 redis 中的数据。
RDB 对 redis 对外提供的读写服务,影响非常小,可以让 redis 保持高性能,因为 redis 主进程只需要 fork 一个子进程,让子进程执行磁盘 IO 操作来进行 RDB 持久化即可。
相对于 AOF 持久化机制来说,直接基于 RDB 数据文件来重启和恢复 redis 进程,更加快速。
如果想要在 redis 故障时,尽可能少的丢失数据,那么 RDB 没有 AOF 好。一般来说,RDB 数据快照文件,都是每隔 5 分钟,或者更长时间生成一次,这个时候就得接受一旦 redis 进程宕机,那么会丢失最后一次的 5 分钟的数据。
RDB 每次在 fork 子进程来执行 RDB 快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。
(1)过期删除策略
redis数据库键的过期时间都保存在过期字典中,根据系统时间和存活时间判断是否过期。
(2)redis有三种不同的删除策略
(3)优缺点
(4)算法
策略由expireIfNeeded函数实现,所有读写命令在执行之前都会调用该函数进行检查。
删除策略由activeExpireCycle算法决定关键点,遍历数据库,如果时间到,则终止;遍历数据库接着上次的进度,直到所有数据库遍历完,再接着遍历;遍历库时候,随机取出一定数量的随机键。
(5)RDB和AOF时过期键的处理
RDB生成时,过期键会被过滤。RDB载入时,以主服务器运行,则过滤过期键。以从服务器运行,则忽略过期键,不做处理。
AOF生成时,如果过期键还没被删除,则忽略,当被删除以后,会追加记录一条DEL命令。AOF载入时,过期键会被过滤。
Redis可以看作是一个内存数据库,可以通过Maxmemory指令配置Redis的数据集使用指定量的内存。设置maxmemory为0,则表示无限制(这是64位系统的默认行为,而32位系统使用3GB内存极限)。当内存使用达到maxmemory极限时,需要使用某种淘汰算法来决定清理掉哪些数据,以保证新数据的存入。
FIFO:First In First Out,先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。
LRU:Least Recently Used,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。
LFU:Least Frequently Used,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
#达到内存上限后的处理策略,即过期淘汰策略,共有6种
# volatile-lru 只对设置了过期时间的key进行LRU(最近少使用)算法,默认此策略
# allkeys-lru 对所有的key进行LRU算法
# volatile-random 对即将过期的key随机删除
# allkeys-random 对所有key随机删除
# volatile-ttl 删除即将过期的
# noeviction 永不过期,抛出错误
Redis为了达到最快的读写速度,将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。
如果不将数据放到内存中,磁盘I/O速度会严重影响redis性能。如果设置了最大使用内存,则数据量达到内存限制值之后,将不能继续插入新值,可启用淘汰策略。
Redis的复制功能分为同步(sync )和命令传播( command propagate )两个操作:
当客户端向从服务器发送SLAVEOF命令,要求从服务器复制主服务器时,从服务器首先需要执行同步操作,也即是,将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
从服务器对主服务器的同步操作需要通过向主服务器发送SYNC命令来完成,以下是SYNC命令的执行步骤:
在同步操作执行完毕之后,主从服务器两者的数据库将达到一致状态,但这种一致并不是一层不变的,每当主服务器执行客服端发送的写命令时,主服务器的数据库就有可能会被修改,并导致主从服务器状态不再一致。
为了让主从服务器再次回到一致状态,主服务器需要对从服务器执行命令传播操作:主服务器会将自己执行的写命令,也即是造成主从服务器不一致的那条写命令,发送给从服务器执,行,当从服务器执行了相同的写命令之后,主从服务器将再次回到一致状态。
在Redis 2.8以前,从服务器对主服务器的复制可以分为以下两种情况:
对于初次复制来说,旧版复制功能能够很好地完成任务,但对于断线后重复制来说,旧版复制功能虽然也能让主从服务器重新回到一致状态,但效率却非常低,从服务器需要让主服务器将所有执行的写命令的RDB文件,从新发送给从服务器。但主从服务器断开的时间可能很短,主服务器在断线期间执行的写命令可能很少,而执行少量写命令所产生的数据量通常比整个数据库的数据量要少得多,在这种情况下,为了让从服务器补足一小部分缺失的数据,却要让主从服务器重新执行一次SYNC命令,这种做法无疑是非常低效的。
为了解决旧版复制功能在处理断线重复制情况时的低效问题,,Redis从2.8版本开始,使用PSYNC命令代替SYNC命令来执行复制时的同步操作。
PSYNC命令具有完整重同步( full resynchronization)和部分重同步( partial resynchronization)两种模式,
其中完整重同步用于处理初次复制情况:完整重同步的执行步骤和SYNC命令的执行步骤基本一样,它们都是通过让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步。
而部分重同步则用于处理断线后重复制情况:当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
PSYNC命令的部分重同步模式解决了旧版复制功能在处理断线后重复制时出现的低效情况。
部分重同步功能由以下三个部分构成:
pipeline,中文意为管线,意义等同于流水线。 pipeline的概念抽象出来为:将一件需要重复做的事情切割成各个不同的阶段,每一个阶段由独立的单元负责。所有待执行的对象依次进入作业队列,可以复用时间片段节省时间提高效率。
redis客户端执行一条命令分4个过程:
发送命令-〉命令排队-〉命令执行-〉返回结果
这个过程称为Round trip time(简称RTT, 往返时间),mget mset有效节约了RTT,但大部分命令(如hgetall,并没有mhgetall)不支持批量操作,需要消耗N次RTT ,这个时候需要pipeline来解决这个问题。
Redis本身是基于Request/Response协议(停等机制)的,正常情况下,客户端发送一个命令,等待Redis返回结果,Redis接收到命令,处理后响应。在这种情况下,如果同时需要执行大量的命令,那就是等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁调用系统IO,发送网络请求。为了提升效率,这时候pipeline出现了,它允许客户端可以一次发送多条命令,而不等待上一条命令执行的结果,这和网络的Nagel算法有点像(TCP_NODELAY选项)。pipeline不仅减少了RTT,同时也减少了IO调用次数(IO调用涉及到用户态到内核态之间的切换)。
原生批命令(mset, mget)是原子性(原子性概念:一个事务是一个不可分割的最小工作单位,要么都成功要么都失败。原子操作是指你的一个业务逻辑必须是不可拆分的. 处理一件事情要么都成功,要么都失败,原子不可拆分),pipeline是非原子性,需要服务端与客户端共同完成。
使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成。
参考之前集群文章内容:一起学习Redis集群.
Redis Sentinal(主从复制集群)着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。
Redisson、Jedis、lettuce等。
名称 | 介绍 | 优点 | 缺点 |
---|---|---|---|
Jedis | 是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持。调用是比较底层的API,操作与原生操作基本一致。 | 提供了比较全面的数据类型及Redis操作。 | 使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行。单线程不是线程安全的。 |
Lettuce | 高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。 | 多线程,线程安全的,性能更好。 | 缺乏分布式高级特性。 |
Redisson | Redisson实现了分布式和可扩展的Java数据结构,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列。和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。 | 功能较简单,致力于分布式相关特性。 | 数据类型支持不足,消耗性能,若非必需要使用分布式特性建议使用lettuce。 |
参照17题
设置密码有两种方式,一是在redis.conf配置文件中设置# requirepass foobared;另一种是用指令config set requirepass psw设置。
验证密码即进入Redis之前需要使用指令auth psw进行验证之后才能进行操作。
Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。
Redis Cluster 采用虚拟哈希槽分区,所有的键根据哈希函数映射到 0 ~ 16383 整数槽内,每个key通过CRC16校验后对16384取模来决定放置哪个槽(Slot),每一个节点负责维护一部分槽以及槽所映射的键值数据。
计算公式:slot = CRC16(key) & 16383。
这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。使用哈希槽的好处就在于可以方便的添加或移除节点。
用了哈希槽的概念,而没有用一致性哈希算法,不都是哈希么?这样做的原因是为什么呢?
Redis Cluster是自己做的crc16的简单hash算法,没有用一致性hash。Redis的作者认为它的crc16(key) mod 16384的效果已经不错了,虽然没有一致性hash灵活,但实现很简单,节点增删时处理起来也很方便。
如上所述,在消息头中,最占空间的是 myslots[CLUSTER_SLOTS/8]。 当槽位为65536时,这块的大小是: 65536÷8÷1024=8kb因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。
Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。
例如8个节点,16384÷8÷1024=2kb。
综上所述,作者决定取16384个槽,不多不少,刚刚好!
现象名称 | 情况 | 特点 | 解决方式 |
---|---|---|---|
缓存穿透 | 巨大并发访问某一个缓存和数据库中都没有的数据,导致数据库服务器压力超负荷或宕机 | 空数据点穿透 | (1)布隆过滤器;(2)缓存空数据 |
缓存击穿 | 巨大并发访问某一个缓存刚到期的数据,导致数据库服务器压力超负荷或宕机 | 缓存到期点穿透 | (1)设置热点数据永不过期;(2)加互斥锁 |
缓存雪崩 | 巨大并发访问多个缓存刚到期的数据,导致数据库服务器压力超负荷或宕机 | 缓存到期面穿透 | (1)缓存高可用,增设几台备用集群;(2)限流降级,使用队列或者加锁控制数量;(3)数据预热 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。