redis和memcache的比较

1 、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;

2 、Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘;

3 、memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);

4、memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;

5、memcache是多线程,redis是单线程

6、redis存储的value最大可以达到1GB,而memcache只有1MB

7、过期策略--memcache在set时就指定,Redis可以在设置值之后通过expire单独设定过期时间

8、Memcached主要用于缓存数据,Redis除了用于数据缓存之外,还能用作NoSQL数据库、消息队列等。

redis五种类型

String
hash
list
set
zset

redis各种类型简介

String

string 是 redis 最基本的类型,可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。

string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。

string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

常用命令:get、set、incr、decr、mget

hash

hash是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

常用命令:hget,hset,hgetall 等

list

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

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

set

Redis的Set是string类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。(不允许重复的成员)

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

zset

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

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

redis各种类型的使用场景

Redis持久化是如何工作的?

什么是持久化?

简单来讲就是将数据放到断电后数据不会丢失的设备中,也就是我们通常理解的硬盘上。

数据库在进行写操作时到底做了哪些事?

1、客户端向服务端发送写操作(数据在客户端的内存中)。

2、数据库服务端接收到写请求的数据(数据在服务端的内存中)。

3、服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。

4、操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。

5、磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。

当数据库系统故障时,这时候系统内核还是完好的。那么此时只要我们执行完了第3步,那么数据就是安全的,因为后续操作系统会来完成后面几步,保证数据最终会落到磁盘上。

当系统断电时,这时候上面5项中提到的所有缓存都会失效,并且数据库和操作系统都会停止工作。所以只有当数据在完成第5步后,才能保证在断电后数据不丢失。

什么是数据损坏

所谓数据损坏,就是数据无法恢复,上面我们讲的都是如何保证数据是确实写到磁盘上去,但是写到磁盘上可能并不意味着数据不会损坏。比如我们可能一次写请求会进行两次不同的写操作,当意外发生时,可能会导致一次写操作安全完成,但是另一次还没有进行。如果数据库的数据文件结构组织不合理,可能就会导致数据完全不能恢复的状况出现。

通常也有三种策略来组织数据,以防止数据文件损坏到无法恢复的情况:

如何解决数据损坏问题

1、通过配置数据同步备份的方式,在数据文件损坏后通过数据备份来进行恢复。实际上MongoDB在不开启操作日志,通过配置Replica Sets时就是这种情况。

2、在上面基础上添加一个操作日志,每次操作时记一下操作的行为,这样我们可以通过操作日志来进行数据恢复。因为操作日志是顺序追加的方式写的,所以不会出现操作日志也无法恢复的情况。这也类似于MongoDB开启了操作日志的情况。

3、更保险的做法是数据库不进行旧数据的修改,只是以追加方式去完成写操作,这样数据本身就是一份日志,这样就永远不会出现数据无法恢复的情况了。实际上CouchDB就是此做法的优秀范例。

Redis的第一个持久化策略:RDB快照

Redis支持将当前数据的快照存成一个数据文件的持久化机制。而一个持续写入的数据库如何生成快照呢。Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB文件。

我们可以通过Redis的save指令来配置RDB快照生成的时机,比如你可以配置当10分钟以内有100次写入就生成快照,也可以配置当1小时内有1000次写入就生成快照,也可以多个规则一起实施。这些规则的定义就在Redis的配置文件中,你也可以通过Redis的CONFIG SET命令在Redis运行时设置规则,不需要重启Redis。

Redis的RDB文件不会坏掉,因为其写操作是在一个新进程中进行的,当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件,这样在任何时候出现故障,Redis的RDB文件都总是可用的。

但是,我们可以很明显的看到,RDB有它的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到 Redis停机这段时间的数据全部丢掉了。在某些业务下,这是可以忍受的,我们也推荐这些业务使用RDB的方式进行持久化,因为开启RDB的代价并不高。 但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,RDB就无能为力了,所以Redis引入了另一个重要的持久化机制:AOF日志。

Redis的第二个持久化策略:AOF日志

AOF日志的全称是Append Only File,从名字上我们就能看出来,它是一个追加写入的日志文件。与一般数据库不同的是,AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令。

每一条写命令都生成一条日志,AOF文件会越来越大,所以Redis又提供了一个功能,叫做AOF rewrite。其功能就是重新生成一份AOF文件,新的AOF文件中一条记录的操作只会有一次,而不像一份老文件那样,可能记录了对同一个值的多次操作。其生成过程和RDB类似,也是fork一个进程,直接遍历数据,写入新的AOF临时文件。在写入新文件的过程中,所有的写操作日志还是会写到原来老的 AOF文件中,同时还会记录在内存缓冲区中。当AOF rewrite操作完成后,会将所有缓冲区中的日志一次性写入到临时文件中。然后调用原子性的rename命令用新的 AOF文件取代老的AOF文件。

Redis持久化性能是否可靠?

从上面的流程我们能够看到,RDB是顺序IO操作,性能很高。而同时在通过RDB文件进行数据库恢复的时候,也是顺序的读取数据加载到内存中。所以也不会造成磁盘的随机读取错误。

而AOF是一个写文件操作,其目的是将操作日志写到磁盘上,所以它也同样会遇到我们上面说的写操作的5个流程。那么写AOF的操作安全性又有多高呢?实际上这是可以设置的,在Redis中对AOF调用write写入后,何时再调用fsync将其写到磁盘上,通过appendfsync选项来控制,下面appendfsync的三个设置项,安全强度逐渐变强。

1、appendfsync no

当设置appendfsync为no的时候,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。

2、appendfsync everysec

当设置appendfsync为everysec的时候,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一 次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞。 所以,结论就是:在绝大多数情况下,Redis会每隔一秒进行一次fsync。在最坏的情况下,两秒钟会进行一次fsync操作。 这一操作在大多数数据库系统中被称为group commit,就是组合多次写操作的数据,一次性将日志写到磁盘。

3、appednfsync always

当设置appendfsync为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到影响。

而在利用RDB和利用AOF启动上,其启动时间有一些差别。RDB的启动时间会更短,原因有两个,一是RDB文件中每一条数据只有一条记录,不会像 AOF日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。另一个原因是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不需要再进行数据编码工作。在CPU消耗上要远小于AOF日志的加载

Redis的集群模式

1、主从复制

2、哨兵模式

3、Redis官方提供的Cluster集群模式(服务端)

4、Jedis sharding集群(客户端sharding)

5、利用中间件代理,比如豌豆荚的codis等

主从复制

Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。

为了分担Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成

哨兵模式

无论是主从模式,还是哨兵模式,这两个模式都有一个问题,不能水平扩容,并且这两个模式的高可用特性都会受到Master主节点内存的限制。

Sentinel(哨兵)进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用。

哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。

当被监控的某个Redis节点出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。

当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将一个Slave升级为新的Master, 并让其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址

缺点

Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

Redis官方 Cluster集群模式

任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点。对其进行存取和其他操作。

当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。

理论上集群中的每个节点至少有一个备用的redis服务。

如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。如果某个节点和所有从节点全部挂掉,我们集群就进入faill状态。还有就是如果有一半以上的主节点宕机,那么我们集群同样进入发力了状态。

Jedis sharding集群

Redis Sharding可以说是在Redis cluster出来之前业界普遍的采用方式,其主要思想是采用hash算法将存储数据的key进行hash散列,这样特定的key会被定到特定的节点上。

利用中间件代理

中间件的作用是将我们需要存入redis中的数据的key通过一套算法计算得出一个值。然后根据这个值找到对应的redis节点,将这些数据存在这个redis的节点中。

缓存穿透、缓存击穿、缓存雪崩

缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,

如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决方案

接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;

从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

解决方案

设置热点数据永远不过期。

加互斥锁,当缓存中没有的时候,只允许一个线程去数据库获取,其余线程自旋等待

缓存雪崩

缓存雪崩是指缓存中大批量数据同时过期,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决方案

设置热点数据永远不过期。

缓存数据的过期时间设置为固定+随机,防止同一时间大量数据过期现象发生。

缓存双写一致性

数据库和缓存中存储的数据不一致的问题

1、先更新数据库,再更新缓存

2、先删除缓存,再更新数据库,再延迟删缓存

3、先更新数据库,再删除缓存

第三种最靠谱

redis应用

1、分布式锁

2、延时队列

zset +score + 轮询(score > now)

3、定时任务(分布式锁)

4、接口频率控制zset

5、服务发现

zset实现,多个服务列表,用多个zset,score存储心跳,value存储服务地址,

服务提供者每隔几秒执行一次zadd来更新心跳时间,服务提供者停止服务时,使用zrem删除服务

服务有可能异常终止,需要专门的线程定时清理停止的服务,

通知消费者服务列表发生了变更,可以使用版本号轮询机制,当服务列表变更时,递增版本号

如果消费者依赖了很多服务列表,就需要轮询很多版本号,这样的IO效率会比较低下,

可以使用全局版本号+服务版本号来控制

如果全局版本号没有改变,则说明整体没有改变,如果全局版本号改变,再去轮询各个服务列表的子版本号

6、位图

节省存储空间

7、模糊计数

hyperLogLog 误差0.81%

8、布隆过滤器

9、发布/订阅

Redis的过期策略和内存淘汰机制

过期的数据,不会及时删除

如何删除?

定期删除+惰性删除

定期删除

redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。

定期删除可能会导致很多过期key到了时间并没有被删除掉,所以就得靠惰性删除了

惰性删除

获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除

如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?

大量过期key堆积在内存里,导致redis内存块耗尽了

如何处理?

内存淘汰机制

内存淘汰机制

redis的内存占用过多的时候,此时会进行内存淘汰,有如下一些策略

1、noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧

2、allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)

3、allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧

4、volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)

5、volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key

6、volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

布隆过滤器

布隆过滤器是一种数据结构

可以用来告诉你 “某样东西一定不存在或者可能存在”。

特点是高效地插入和查询

有点是相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少

缺点是其返回的结果是概率性的,而不是确切的。

Redis相关概念的更多相关文章

  1. 分布式数据库对比评测(Es,mongodb,redis)基础知识篇

    前言 我建议大家看下这个,否则后面你不知道我在说什么. 1.ES数据库相关概念 啥是Es,说白了就是支持文档搜索的分布式数据库,专门方便搜索的,GITHUB京东现在都在用. 1.ES的数据库存放在哪里 ...

  2. Redis集群的相关概念

    1.1 redis-cluster架构图 架构细节: (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽. (2)节点的fail是通过集群中超过半数的节 ...

  3. Redis之个人简单理解

    1.什么是redis? 在过去的几年中,NoSQL数据库一度成为高并发.海量数据存储解决方案的代名词,与之相应的产品也呈现出雨后春笋般的生机.然而在众多产品中能够脱颖而出的却屈指可数,如Redis.M ...

  4. Azure Redis Cache (2) 创建和使用Azure Redis Cache

    <Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的Azure China. 注意: 截至今日2015年10月7日,国内由世纪互联运维的Azur ...

  5. 在Tomat7上使用Redis保存Session

    源博客http://my.oschina.net/gccr/blog/321083 当用户量大.应用服务器使用集群来布署时,使用Tomcat默认自带的Session就不能满足需求了.当然解决方法有很多 ...

  6. 基于nginx tomcat redis分布式web应用的session共享配置

    一.前言 nginx 作为目前最流行的开源反向代理HTTP Server,用于实现资源缓存.web server负载均衡等功能,由于其轻量级.高性能.高可靠等特点在互联网项目中有着非常普遍的应用,相关 ...

  7. Memcached、Redis OR Tair

    一.前言 非关系型数据库(NoSQL = Not Only SQL)的产品非常多,常见的有Memcached.Redis.MongoDB等优秀开源项目,相关概念和资料网上也非常丰富,不再重复描述,本文 ...

  8. nginx redis tomcat 分布式web应用 session共享

    目标:多台tomcat 使用redis实现共享session.redis的安装请参阅:centos上安装redis nginx 作为目前最流行的开源反向代理HTTP Server,用于实现资源缓存.w ...

  9. Redis单机版以及集群版的安装搭建以及使用

    1,redis单机版 1.1   安装redis n  版本说明 本教程使用redis3.0版本.3.0版本主要增加了redis集群功能. 安装的前提条件: 需要安装gcc:yum install g ...

随机推荐

  1. 块元素&行内元素

    大多数HTML 元素被定义为块级元素或内联元素.块级元素在浏览器显示时,通常会以新行来开始(和结束) block元素特点 1 总是在新行上开始: 2 高度,行高以及外边距和内边距都可控制: 3 宽度缺 ...

  2. html 获取项目根路径

    html 获取项目根路径 function getContextPath(){ var pathName = document.location.pathname; //当前文件的绝度路径 var i ...

  3. Mybatis(上)

    Mybatis 一.MyBatis 简介 1. MyBatis作用 MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架. MyBatis 避免了几乎所有的 JDBC 代码和手 ...

  4. 第07组 Beta版本演示

    组长博客:求戳 队名:摇光 成员 学号 姓名 组长 031702203 容慧珺 杨明哲 031702202 高星 杨明哲 031702307 黄森敏 杨明哲 031702308 朱丽辰 杨明哲 031 ...

  5. elementui 走马灯图片自适应

    点击单元格后弹出对话框轮播图片,用Carousel 走马灯实现. 希望图片无论分辨率多少,都能在一屏内显示,这时就要用图片自适应. 图片外层容器,使用 flex 布局,设置对齐方式为主轴.交叉轴居中 ...

  6. codeDecodeError ascii codec can't decode byte 0xe2 in position 44 ordinal not in range(128)

  7. JVM探究之 —— Java内存区域

    1. 概述 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们既是拥有最高权力的“皇帝”又是从事最基础工作的“劳动人民”——既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的 ...

  8. Java线程的wait(), notify()和notifyAll()

    Java线程生命周期 类java.lang.Thread包含一个静态的State enum用于定义每种可能的状态. 在任意的时间点, 线程会处于以下的状态之一: NEW – 新创建的线程, 还未启动( ...

  9. v-if和v-for一起使用的几个方法

    方法一(推荐): 不带if <ul> <li v-for="(item, index) in list" :key="index" > ...

  10. spring 技术内幕读书笔记1

    1 在 java 应用开发中,往往会涉及复杂的对象耦合关系,在 代码中处理这些耦合关系,对代码的维护性和应用扩展性会带来许多不便.通过使用spring 的 IOC 容器,可以对这些耦合关系实现一个文本 ...