42.NoSQL 数据库--redis的简介

1.为什么引入Redis?

在我们日常的Java Web开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者是主页访问量瞬间较大的时候,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的严重生产问题。

NoSQL 技术

为了克服上述的问题,Java Web项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能。
Redis和MongoDB是当前使用最广泛的NoSQL,而就Redis技术而言,它的性能十分优越,可以支持每秒十几万次的读/写操作,其性能远超数据库,并且还支持集群、分布式、主从同步等配置,原则上可以无限扩展,让更多的数据存储在内存中,更让人欣慰的是它还支持一定的事务能力,这保证了高并发的场景下数据的安全和一致性。

redis是Nosql数据库,是一个key-value存储系统
虽然redis是key-value的存储系统,但是redis支持的value存储类型是非常的多,比如字符串、链表、集合、有序集合和哈希

那么为什么要使用类似redis这样的Nosql数据库呢?
(1) 当数据量的总大小一个机器放不下时;
(2)数据索引一个机器的内存放不下时;
(3)访问量(读写混合)一个实例放不下时。
单机时代,存储只用一台机器装mysql,如果每次存储成千上万条数据,这样很会导致mysql的性能很差,存储以及读取速度很慢,然后就演变成缓存+mysql+垂直拆分的方式。
Cache作为中间缓存时代,将所有的数据先保存到缓存中,然后再存入mysql中,减小数据库压力,提高效率。
但是当数据再次增加到又一个量级,上面的方式也不能满足需求,由于数据库的写入压力增加,缓存只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。
主从分离模式时代,在redis的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。

2.什么是Redis?

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作。Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存List链表和Set集合的数据结构,而且还支持对List进行各种操作,它的值可以是string,list,sets,或者是ordered sets。例如 从List两端push和pop数据,取List区间,排序等等,对Set支持各种集合的并集交集操作,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。 Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,并且它没有原生的可扩展机制,不具有scale(可扩展)能力,要依赖客户端来实现分布式读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。根据Redis的官网测试报告,50个并发请求,10w次访问,写速度为11x10e4/s,读速度为8100次/s.目前使用Redis的网站有 github,Engine Yard。

(1)Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(high availability)。
(2)Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
(3)redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
(4)Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
(5)Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
(6)redis的官网地址,非常好记,是redis.io。(特意查了一下,域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)目前,Vmware在资助着redis项目的开发和维护。

3.Redis 特点

与其它 Key-Value 缓存产品相比,Redis 有以下特点:

  • Redis 支持数据的持久化(包括 AOF 和 RDB 两种模式),可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用,性能与可靠性兼顾;
  • Redis 不是仅仅支持简单的 Key-Value类型的数据,还支持字符串、列表、集合、散列表、有序集合数据结构的存储,这一优势使 Redis 适用于更广泛的应用场景;
  • Redis 支持数据的备份,即 Master-Slave 模式,Master 故障时,对应的 Slave 将通过选举升主,保障可用性;
  • Redis 主进程是单线程工作,因此,Redis 的所有操作都是原子性的,即操作要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性;
  • Redis 性能优越,读的速度达110000次/s,写的速度达81000次/s。
    除了上述特点,Redis 还支持Publish/Subscribe,通知,Key 老化逐出等特性。

在这里插入图片描述
注意:

  • 数据库事务必须具备ACID特性,ACID是Atomic原子性,Consistency一致性,Isolation隔离性,Durability持久性。
  • 数据的持久存储,尤其是海量数据的持久存储,还是需要一种关系数据库。

4.Redis的应用?

Redis 在 Java Web 中的应用主要有两个场景:
存储缓存用的数据;需要高速读/写的场合使用它快速读/写;

(1)缓存
在日常对数据库的访问中,读操作的次数远超写操作,比例大概在 1:9 到 3:7,所以需要读的可能性是比写的可能大得多的。
当我们使用SQL语句去数据库进行读写操作时,数据库就会去磁盘把对应的数据索引取回来,这是一个相对较慢的过程。
如果我们把数据放在 Redis 中,也就是直接放在内存之中,让服务端直接去读取内存中的数据,那么这样速度明显就会快上不少,
并且会极大减小数据库的压力,但是使用内存进行数据存储开销也是比较大的,限于成本的原因,
一般我们只是使用 Redis 存储一些常用和主要的数据,比如用户登录的信息等。
一般而言在使用 Redis 进行存储的时候,我们需要从以下几个方面来考虑:
业务数据常用吗?命中率如何?如果命中率很低,就没有必要写入缓存;
该业务数据是读操作多,还是写操作多?如果写操作多,频繁需要写入数据库,也没有必要使用缓存;
业务数据大小如何?如果要存储几百兆字节的文件,会给缓存带来很大的压力,这样也没有必要;
在考虑了这些问题之后,如果觉得有必要使用缓存,那么就使用它!使用 Redis 作为缓存的读取逻辑如下图所示:
在这里插入图片描述
从上图我们可以知道以下两点:
当第一次读取数据的时候,读取 Redis 的数据就会失败,此时就会触发程序读取数据库,把数据读取出来,并且写入 Redis 中;
当第二次以及以后需要读取数据时,就会直接读取 Redis,读到数据后就结束了流程,这样速度就大大提高了。
从上面的分析可以知道,读操作的可能性是远大于写操作的,所以使用 Redis 来处理日常中需要经常读取的数据,速度提升是显而易见的,同时也降低了对数据库的依赖,使得数据库的压力大大减少。
分析了读操作的逻辑,下面我们来看看写操作的流程:
在这里插入图片描述
从流程可以看出,更新或者写入的操作,需要多个 Redis 的操作,如果业务数据写次数远大于读次数那么就没有必要使用 Redis。

(2)高速读/写的场合
在如今的互联网中,越来越多的存在高并发的情况,比如天猫双11、抢红包、抢演唱会门票等,这些场合都是在某一个瞬间或者是某一个短暂的时刻有成千上万的请求到达服务器,如果单纯的使用数据库来进行处理,就算不崩,也会很慢的,轻则造成用户体验极差用户量流失,重则数据库瘫痪,服务宕机,而这样的场合都是不允许的!
所以我们需要使用 Redis 来应对这样的高并发需求的场合,我们先来看看一次请求操作的流程图:
在这里插入图片描述
当一个请求到达服务器时,只是把业务数据在 Redis 上进行读写,而没有对数据库进行任何的操作,这样就能大大提高读写的速度,从而满足高速响应的需求;
但是这些缓存的数据仍然需要持久化,也就是存入数据库之中,所以在一个请求操作完 Redis 的读/写之后,会去判断该高速读/写的业务是否结束,这个判断通常会在秒杀商品为0,红包金额为0时成立,如果不成立,则不会操作数据库;如果成立,则触发事件将 Redis 的缓存的数据以批量的形式一次性写入数据库,从而完成持久化的工作。

5.Redis的核心原理

  • Redis的单线程和高性能

Redis 单线程为什么还能这么快?
因为它所有的数据都在内存中,所有的运算都是内存级别的运算(纳秒),而且单线程避免了多线程的切换(上下文切换)性能损耗问题。正因为 Redis 是单线程,所以要小心使用 Redis 指令,对于那些耗时的指令(比如keys),一定要谨慎使用,一不小心就可能会导致 Redis 卡顿。

Redis 单线程如何处理那么多的并发客户端连接?
Redis的IO多路复用:redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,
依次放到文件事件分派器,事件分派器将事件分发给事件处理器。
在这里插入图片描述

  • 持久化

RDB快照(snapshot)
在默认情况下, Redis 将内存数据库快照保存在名字为dump.rdb的二进制文件中。
你可以对 Redis 进行设置, 让它在N秒内数据集至少有M个改动这一条件被满足时, 自动保存一次数据集。
比如说, 以下设置会让 Redis 在满足60秒内有至少有1000个键被改动”这一条件时, 自动保存一次数据集:
redis.conf文件里面有默认的3种情况,3种是或的关系。

AOF(append-only file)
快照功能并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化,将修改的每一条指令记录进文件
你可以通过修改配置文件来打开 AOF 功能:
开启后,每当 Redis 执行一个改变数据集的命令时(比如SET), 这个命令就会被追加到 AOF 文件的末尾。
这样的话, 当 Redis 重新启时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。
你可以配置 Redis 多久才将数据fsync到磁盘一次。
有三个选项:
每次有新命令追加到 AOF 文件时就执行一次fsync:非常慢,也非常安全。
每秒fsync一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。
从不fsync:将数据交给操作系统来处理。更快,也更不安全的选择。
推荐(并且也是默认)的措施为每秒fsync一次, 这种fsync策略可以兼顾速度和安全性。

  • RDB 和 AOF ,我应该用哪一个?

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份,
并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。

  • 缓存淘汰策略(解决数据热点问题)

当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换 (swap)。
交换会让 Redis 的性能急剧下降,对于访问量比较频繁的 Redis 来说,这样龟速的存取效率基本上等于不可用。
在生产环境中我们是不允许 Redis 出现交换行为的,为了限制最大使用内存,
Redis 提供了配置参数 maxmemory 来限制内存超出期望大小。
当实际内存超出 maxmemory 时,
Redis 提供了几种可选策略 (maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务。

1> noeviction
不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。

2> volatile-lru
尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。
没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。

3> volatile-ttl
跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。

4> volatile-random
跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。

5> allkeys-lru
区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。
这意味着没有设置过期时间的 key 也会被淘汰。
allkeys-random跟上面一样,不过淘汰的策略是随机的 key。

6> volatile-xxx
策略只会针对带过期时间的 key 进行淘汰,allkeys-xxx 策略会对所有的 key 进行淘汰。如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时不必携带过期时间。如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被 LRU 算法淘汰。

6.Redis和Mysql的区别?

(1)mysql和redis的数据库类型
mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。
redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,
能够大大的提高运行效率,但是保存时间有限。

(2)mysql的运行机制
mysql作为持久化存储的关系型数据库,相对薄弱的地方在于每次请求访问数据库时,都存在着I/O操作,如果反复频繁的访问数据库。
第一:会在反复链接数据库上花费大量时间,从而导致运行效率过慢;
第二:反复的访问数据库也会导致数据库的负载过高,那么此时缓存的概念就衍生了出来。

(3)缓存
缓存就是数据交换的缓冲区(cache),当浏览器执行请求时,首先会对在缓存中进行查找,如果存在,就获取;否则就访问数据库。
缓存的好处就是读取速度快

(4)redis数据库
redis数据库就是一款缓存数据库,用于存储使用频繁的数据,这样减少访问数据库的次数,提高运行效率。

(5)redis和mysql的区别总结
类型上
从类型上来说,mysql是关系型数据库,redis是缓存数据库
作用上
mysql用于持久化的存储数据到硬盘,功能强大,但是速度较慢
redis用于存储使用较为频繁的数据到缓存中,读取速度快
需求上
mysql和redis因为需求的不同,一般都是配合使用

MySQL是关系型数据库,是持久化存储的,查询检索的话,会涉及到磁盘IO操作,为了提高性能,可以使用缓存技术,而memcached就是内存数据库,数据存储在内存中(当然也可以进行持久化存储),可以用作缓存数据库。用户首先去memcached查询数据,如果未查询到(即缓存未命中),才去MySQL中查询数据,查询到的数据会更新到缓存数据库中,提供给下次可能进行的查询。提高了数据查询方面的性能。
Redis和memcached都是缓存数据库,可以大大提升高数据量的web访问速度。
但是memcached只是提供了简单的数据结构string,而Redis的value可以是string、list、set、hash、sorted set这些,功能更加强大。
web应用中一般采用MySQL+Redis的方式,web应用每次先访问Redis,如果没有找到数据,才去访问MySQL。
Redis是内存数据库,数据保存在内存中,访问速度快。MySQL是关系型数据库,功能强大,存储在磁盘中,数据访问速度慢。像memcached,MongoDB,Redis等,都属于No sql系列。
在这里插入图片描述

7.Sql和Nosql的区别

(1)概念
SQL (Structured Query Language) 数据库,指关系型数据库。主要代表:SQL Server,Oracle,MySQL(开源),PostgreSQL(开源)
NoSQL(Not Only SQL)泛指非关系型数据库。主要代表:MongoDB,Redis,CouchDB

(2)区别

存储方式
SQL数据存在特定结构的表中;而NoSQL则更加灵活和可扩展,存储方式可以省是JSON文档、哈希表或者其他方式。
SQL通常以数据库表形式存储数据

表/数据集合的数据的关系
在SQL中,必须定义好表和字段结构后才能添加数据,例如定义表的主键(primary key),索引(index),触发器(trigger),存储过程(stored procedure)等。表结构可以在被定义之后更新,但是如果有比较大的结构变更的话就会变得比较复杂。
在NoSQL中,数据可以在任何时候任何地方添加,不需要先定义表。
NoSQL也可以在数据集中建立索引。以MongoDB为例,会自动在数据集合创建后创建唯一值_id字段,
这样的话就可以在数据集创建后增加索引。
从这点来看,NoSQL可能更加适合初始化数据还不明确或者未定的项目中。

外部数据存储
SQL中如何需要增加外部关联数据的话,规范化做法是在原表中增加一个外键,关联外部数据表。
而在NoSQL中除了这种规范化的外部数据表做法以外,我们还能用非规范化方式把外部数据直接放到原数据集中,以提高查询效率。

SQL中的JOIN查询
SQL中可以使用JOIN表链接方式将多个关系数据表中的数据用一条简单的查询语句查询出来。
NoSQL暂未提供类似JOIN的查询方式对多个数据集中的数据做查询。所以大部分NoSQL使用非规范化的数据存储方式存储数据。

数据耦合性
SQL中不允许删除已经被使用的外部数据,以保证数据完整性。而NoSQL中则没有这种强耦合的概念,可以随时删除任何数据。

事务
SQL中如果多张表数据需要同批次被更新,即如果其中一张表更新失败的话其他表也不能更新成功。
这种场景可以通过事务来控制,可以在所有命令完成后再统一提交事务。
而NoSQL中没有事务这个概念,每一个数据集的操作都是原子级的。

查询性能
在相同水平的系统设计的前提下,因为NoSQL中省略了JOIN查询的消耗,故理论上性能上是优于SQL的。

目前许多大型互联网项目都会选用MySQL(或任何关系型数据库) + NoSQL的组合方案。
关系型数据库适合存储结构化数据,如用户的帐号、地址:
1)这些数据通常需要做结构化查询(嗯,好像是废话),比如join,这时候,关系型数据库就要胜出一筹
2)这些数据的规模、增长的速度通常是可以预期的
3)事务性、一致性
NoSQL适合存储非结构化数据,如文章、评论:
1)这些数据通常用于模糊处理,如全文搜索、机器学习
2)这些数据是海量的,而且增长的速度是难以预期的,
3)根据数据的特点,NoSQL数据库通常具有无限(至少接近)伸缩性
4)按key获取数据效率很高,但是对join或其他结构化查询的支持就比较差
基于它们的适用范围不同,目前主流架构才会采用组合方案,一个也不能少。
目前为止,还没有出现一个能够通吃各种场景的数据库,而且根据CAP理论,这样的数据库是不存在的。

8.Nosql数据库的优势

(1)易扩展
这些类型的数据存储不需要固定的模式,无需多余的操作就可以进行横向的扩展。
相对于关系型数据库可以减少表和字段特别多的情况。也无型之间在架构的层面上带来了可扩展的能力
(2)大数据量提高性能
(3)多样灵活的数据模型

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值