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. golang 文件传输小demo(转载)

    转载地址:https://www.cnblogs.com/qq702368956/p/10195497.html 获取文件信息需要用到os. Stat接口,发送文件前开启接收者(服务端),启动客户端先 ...

  2. a标签伪类选择器+过度模块

    a标签的伪类选择器 1.什么是a标签的伪类选择器?a标签的伪类选择器是专门用来修改a标签不同状态的样式的. 2.格式: 1):link 修改从未被访问过状态下的样式. 2):visited 修改被访问 ...

  3. windows环境下安装nginx

    (1)下载 官网:http://nginx.org/en/docs/windows.html 下载:http://nginx.org/en/docs/windows.html 点击:nginx/Win ...

  4. 单细胞数据整合方法 | Comprehensive Integration of Single-Cell Data

    操作代码:https://satijalab.org/seurat/ 依赖的算法 CCA CANONICAL CORRELATION ANALYSIS | R DATA ANALYSIS EXAMPL ...

  5. locust参数化(数据库取值)

    locust参数化(数据库取值) 基于上一篇参数化的梳理,本篇用另一种方法从数据库中取出这100个用户来登录 思路:在 TaskSet 中的 on_start 方法表示执行任务前的操作,可以将数据库取 ...

  6. js组件常用封装方法。。。。。【组件封装】 ★★★★★★

    公共弹窗js写法:mcake弹窗封装Dialog.js function Dialog(bg,els,opts) { this.$els = $(els); this.$Dialogbg = $(bg ...

  7. [报错处理]Python Requests - No connection adapters

    出错信息很清楚:Python请求 - 没有连接适配器. 你得把网络协议加进入网址: http://192.168.1.61:8080/api/call 没有 http:// 请求不知道如何连接远程. ...

  8. Spring MVC -- 表达式于语言(EL)

    JSP 2.0最重要的特性之一就是表达式语言(EL),JSP用户可以用它来访问应用程序数据.由于受到ECMAScript和XPath表达式语言的启发,EL也设计成可以轻松地编写免脚本(就是不用在jsp ...

  9. Python爬虫笔记安装篇

    目录 爬虫三步 请求库 Requests:阻塞式请求库 Requests是什么 Requests安装 selenium:浏览器自动化测试 selenium安装 PhantomJS:隐藏浏览器窗口 Ph ...

  10. [LeetCode] 224. Basic Calculator 基本计算器

    Implement a basic calculator to evaluate a simple expression string. The expression string may conta ...