NoSQL


技术的分类

  • 解决功能性的问题: Java,Jsp,RDBMS,Tomcat,HTML,Linux, Jdbc, SVN
  • 解决扩展性的问题:Structs,Spring,SpringMVC,Hibernate,Mybatis
  • 解决性能的问题:NoSQL,Java线程,Hadoop,Nginx,MQ,ElasticSearch

背景

在这里插入图片描述

NoSQL

NoSQL (Not Only SQL) 不仅仅是SQL,泛指非关系型的数据, 解决大规模数据集合 - 多重数据种类的存储
(比如google每天为用户收集万亿比特的数据,这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展)

特点

  1. 去掉关系数据库的关系型特性,易于扩展

  2. 读写性能高:NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。
    这得益于它的无关系性,数据库的结构简单。
    一般MySQL使用Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,
    在针对web2.0的交互频繁的应用,Cache性能不高。而NoSQL的Cache是记录级的,
    是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了

  3. NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,
    增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦

(sql和noSQL配合使用)

使用场景

  • 对数据高并发的读写
  • 海量数据的读写
  • 对数据高可扩展性的

不适用场景

  • 需要事务支持
  • 基于sql的结构化查询存储,处理复杂的关系,需要即席查询
RDBMS vs NoSQL
RDBMS
- 高度组织化结构化数据
- 结构化查询语言(SQL)
- 数据和关系都存储在单独的表中。
- 数据操纵语言,数据定义语言
- 严格的一致性
- 基础事务
 
NoSQL
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
--值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- CAP定理
- 高性能,高可用性和可伸缩性

NoSQL数据模型:聚合模型
KV键值
Bson:类似Json
列族:按列存储数据的
图形

NoSQL数据库的四大分类

Memcache 高速缓存
Mongdb:基于分布式文件存储的数据库,C++编写,介于关系数据库和非关系数据库之间的产品
在这里插入图片描述
在这里插入图片描述

关系型数据库遵循ACID规则
事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:

1、A (Atomicity) 原子性
原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

2、C (Consistency) 一致性
一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

3、I (Isolation) 独立性
所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。比如现有有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的

4、D (Durability) 持久性
持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。


在分布式数据库中CAP + BASE

在这里插入图片描述
强一致性:commit给数据库后,是什么就是什么
可用性:系统不能崩
分区容错性:

CAP的3进2

CAP理论就是说在分布式存储系统中,最多只能实现上面的两点
而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的

所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。


C:强一致性 A:高可用性 P:分布式容忍性

CA 传统Oracle数据库
AP 大多数网站架构的选择
CP Redis、Mongodb

强一致性:浏览数点赞数 – 精确知道多少,不能错 – 双11在高并发大数据量的时候 ,很难保证
由于点赞数 不需要即时知道,需要先保证的是可用性

注意:分布式架构的时候必须做出取舍。
一致性和可用性之间取一个平衡。多余大多数web应用,其实并不需要强一致性。
因此牺牲C换取P,这是目前分布式数据库产品的方向

一致性与可用性的决择

对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地

数据库事务一致性需求
  很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低, 有些场合对写一致性要求并不高。允许实现最终一致性。

数据库的写实时性和读实时性需求
  对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比方说发一条微博之 后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。(读己之所写,自己首先能看到,小伙伴慢慢能看到)

对复杂的SQL查询,特别是多表关联查询的需求
  任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的报表查询,特别是SNS类型的网站,从需求以及产品设计角 度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。


经典CAP图

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,
最多只能同时较好的满足两个

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

  • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
  • CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。
  • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
    在这里插入图片描述

BASE

为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。

BASE其实是下面三个术语的缩写:

  • 基本可用(Basically Available)
  • 软状态(Soft state)
  • 最终一致(Eventually consistent)

它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。
为什么这么说呢,缘由就在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一种方式来完成,这里BASE就是解决这个问题的办法
(双11当天为了AP放弃强一致,高峰之后可以统计到)


分布式系统

分布式系统(distributed system)由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。分布式系统是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。分布式系统可以应用在在不同的平台上如:Pc、工作站、局域网和广域网上等。

简单来讲:
分布式:不同的多台服务器上面部署不同的服务模块(工程),他们之间通过Rpc/Rmi之间通信和调用,对外提供服务和组内协作。

集群:不同的多台服务器上面部署相同的服务模块,通过分布式调度软件进行统一的调度,对外提供服务和访问。

Redis

Redis:REmote DIctionary Server(远程字典服务器)

用C语言编写,遵守BSD协议

Redis 是速度非常快的非关系型(NoSQL)内存键值(key/value)数据库,可以存储键和五种不同类型的值之间的映射。
键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。
Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,使用复制来扩展读性能,使用分片来扩展写性能。

和Memcached区别

都是非关系型内存键值数据库

  • 支持存储的value类型更多:string,list,set,zset,hash。Memcached只能存储简单的字符串
  • 支持数据的持久化:为了保证效率,数据都是缓存在内存中。但是Rdis会周期地把更新的数据写入磁盘 或者 把修改操作写入追加的记录文件,并在此基础上实现了master- slave同步(数据备份)。Memcached不能持久化
  • Redis使用单线程+多路复用IO,Memcached使用多线程+锁
  • 分布式 Redis Cluster 实现了分布式的支持。Memcached 不支持分布式,只能通过在客户端使用一致性哈希来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。
  • 内存管理机制
    在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘,而Memcached 的数据则会一直在内存中。
    Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题。但是这种方式会使得内存
    的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。

应用场景

1.配合关系型数据库做高速缓存

  • 高频次,热门访问的数据,降低数据库IO
  • 分布式架构,做session共享

2 . 由于其拥有持久化能力,可以利用其多样的数据结构存储特定的数据
在这里插入图片描述
Redis是 单线程 + 多路IO复用技术
多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态(监视),比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)

  • 阻塞IO:默默等待,期间不做其他事情,直到女神下楼(备胎做法)
  • 非阻塞IO:一直给女神发信息,如果不回,接着发,直到女神下楼,期间除了发短信等待不会做其他事情(专一)
  • IO多路复用:找一个宿管大妈帮你监视下楼的女生,这个期间你可以做其他的事情。IO复用包括select,poll,epoll模式
    select大妈:每个女生下楼,她不知道这个是不是你的女神,需要一个个去询问,并且select大妈能力有限,最多一次帮你监视1024个女生
    poll大妈不限制盯着女生的数量,只要经过宿舍楼门口的女生,她都会帮你去问是不是你找的人
    epoll大妈不限制盯着女生的数量,并且也不需要一个一个去问。她会为每个进宿舍的女生脸上贴上女生自己名字的大字条,只要女生下楼,epoll大妈就知道这个是不是你要找的,然后通知你
持久化

Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上。
在这里插入图片描述

  • RDB(Redis DataBase)
    在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
    如果系统发生故障,将会丢失最后一次创建快照之后的数据。
    如果数据量很大,保存快照的时间会很长

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能
如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失

Fork:Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程

Rdb 保存的是dump.rdb文件
RDB是整个内存的压缩过的Snapshot,RDB的数据结构,可以配置复合的快照触发条件,

默认是1分钟内改了1万次,
或5分钟内改了10次,
或15分钟内改了1次

优势:
适合大规模的数据恢复
对数据完整性和一致性要求不高
劣势:
在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改
Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑

在这里插入图片描述

  • AOF(Append Only File)
    以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
    Aof保存的是appendonly.aof文件

Rewrite:
AOF采用文件追加方式,文件会越来越大。为避免出现此种情况,新增了重写机制。当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof

重写原理:
AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),
遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,
而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
触发机制:
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马
上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项:

  • 每修改同步:appendfsync always 同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
  • 每秒同步:appendfsync everysec 异步操作,每秒记录 如果一秒内宕机,有数据丢失
  • 不同步:appendfsync no 从不同步

劣势:
相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
Aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

  • AOF 还是RDB?
  1. RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
  2. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些
    命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.
    Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
  3. 只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式
  4. 同时开启两种持久化方式
    在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据, 因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整
    RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。

性能建议

因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。

如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。

如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构

Redis的事务

一个事务包含了多个命令,服务器在执行事务期间,不会改去执行其它客户端的命令请求。
事务中的多个命令被一次性发送给服务器,而不是一条一条发送,这种方式被称为流水线,它可以减少客户端与服务
器之间的网络通信次数从而提升性能。
Redis 最简单的事务实现方式是使用 MULTI 和 EXEC 命令将事务操作包围起来。

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞

悲观锁/乐观锁/CAS(Check And Set)

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改, 所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,
乐观锁策略:提交版本必须大于记录当前版本才能执行更新

Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,
比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行

通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,
EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败

事务三阶段:
开启:以MULTI开始一个事务
入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
执行:由EXEC命令触发事务

事务三特性:
1单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
2没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,
也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
3不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

Redis的发布订阅

进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息
在这里插入图片描述

Redis的复制(Master/Slave)

行话:也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

用途:读写分离,容灾恢复

使用 slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。
一个从服务器只能有一个主服务器,并且不支持主主复制。
连接过程

  1. 主服务器创建快照文件,发送给从服务器,并在发送期间使用缓冲区记录执行的写命令。快照文件发送完毕之
    后,开始向从服务器发送存储在缓冲区中的写命令;
  2. 从服务器丢弃所有旧数据,载入主服务器发来的快照文件,之后从服务器开始接受主服务器发来的写命令;
  3. 主服务器每执行一次写命令,就向从服务器发送相同的写命令

主从链
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超
载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务
器,又是最下层服务器的主服务器。
在这里插入图片描述
使用

  • 配从(库)不配主(库)
  • 从库配置:slaveof 主库IP 主库端口
    每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件
    Info replication

在这里插入图片描述

招数:

  • 一主二仆:一个Master两个Slave
  • 薪火相传:上一个Slave可以是下一个slave的Master,Slave同样可以接收其他
    slaves的连接和同步请求,那么该slave作为了链条中下一个的master,
    可以有效减轻master的写压力
  • 反客为主:SLAVEOF no one:使当前数据库停止与其他数据库的同步,转成主数据库

在这里插入图片描述

哨兵模式(sentinel)
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库

Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务
器。

复制延时:
由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

分片

分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级
别的性能提升。
假设有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,… ,有不同的方式来选择一个
指定的键存储在哪个实例中。

  • 最简单的方式是范围分片,例如用户 id 从 0~1000 的存储到实例 R0 中,用户 id 从 1001~2000 的存储到实例
    R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。
  • 哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。

根据执行分片的位置,可以分为三种分片方式:

  • 客户端分片:客户端使用一致性哈希等算法决定键应当分布到哪个节点。
  • 代理分片:将客户端请求发送到代理上,由代理转发请求到正确的节点上。
  • 服务器分片:Redis Cluster。
数据结构

字典
在这里插入图片描述
Redis 的字典 dict 中包含两个哈希表 dictht,这是为了方便进行 rehash 操作。在扩容时,将其中一个 dictht 上的键
值对 rehash 到另一个 dictht 上面,完成之后释放空间并交换两个 dictht 的角色
rehash 操作不是一次性完成,而是采用渐进方式,这是为了避免一次性执行过多的 rehash 操作给服务器带来过大
的负担。

跳跃表

是有序集合的底层实现之一。
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。
下图演示了查找 22 的过程
在这里插入图片描述
与红黑树等平衡树相比,跳跃表具有以下优点:
插入速度非常快速,因为不需要进行旋转等操作来维护平衡性;
更容易实现;
支持无锁操作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值