数据库概述(从SQL到NOSQL发展历程讲解)
数据库发展历程概述
一个技术的兴起是有其原因的,了解其兴起的背景,能更好的掌握与运用。
注意,新技术的产生并不代表旧技术的落后和不再使用。
单机MySQL时代
在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。 在那个时候,更多的都是静态网页,动态交互类型的网站不多。
DAL dal是数据访问层的英文缩写,即为数据访问层(Data Access Layer)
上述架构下,我们来看看数据存储的瓶颈是什么?
- 数据量的总大小一个机器放不下时
- 数据的索引(B+ Tree)一个机器的内存放不下时
- 访问量(读写混合)一个实例不能承受
Memcached(缓存)+MySQL+垂直拆分
后来,随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大的时候,多台web机器通过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候,Memcached就自然的成为一个非常时尚的技术产品。
例如Mybits缓存技术
MyBatis缓存机制也有一些不足之处,在使用中容易引起脏数据,形成一些潜在的隐患。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sx0RMb5M-1638103369810)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bbc2112ef13b4c21ba4df1596ee5bd44~tplv-k3u1fbpfcp-watermark.image?)]
一级缓存
应用场景
在一次数据库会话中,执行多次查询条件完全相同的SQL,MyBatis提供了一级缓存的方案优化这部分场景,如果是相同的SQL语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能。
Mybits的一级缓存有两个级别,SESSION或者STATEMENT,默认是SESSION级别的缓存,存放在BaseExecutor中的localCache中。
查询就将结果缓存进去,一旦有更新,删除,插入类的操作就清空缓存。
不同的sqlSession之间的缓存是互相不影响的。
缺点 MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。
二级缓存
概览
二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。
当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
二级缓存的级别是一个个mapper,对应数据库的一张表,当第一次访问某条数据库记录时,记录会被加入缓存,当重新请求获取该记录时直接从缓存里取,当然,为了防止读取脏数据,当进行插入、更新、删除的时候会清除所有的缓存,这是粗颗粒的缓存,因为一旦有修改,就要删除所有的缓存。如果缓存里不存在,则会去数据库里取,这便是缓存的原理,减轻了数据库的压力。
缺点 二级缓存不适应用于映射文件中存在多表查询的情况
Mybatis的二级缓存是和命名空间绑定的,所以通常情况下每一个Mapper映射文件都有自己的二级缓存,不同的mapper的二级缓存互不影响。这样的设计一不注意就会引起脏读,从而导致数据一致性的问题。引起脏读的操作通常发生在多表关联操作中,比如在两个不同的mapper中都涉及到同一个表的增删改查操作,当其中一个mapper对这张表进行查询操作,此时另一个mapper进行了更新操作刷新缓存,然后第一个mapper又查询了一次,那么这次查询出的数据是脏数据。出现脏读的原因是他们的操作的缓存并不是同一个。
垂直拆分
垂直拆分是指:将一个属性较多,一行数据较大的表,将不同的属性拆分到不同的表中,以降低单库(表)大小,达到提升性能的目的的方法,垂直切分后,各个库(表)的特点是:
(1)每个库(表)的结构都不一样
(2)一般来说,每个库(表)的属性至少有一列交集,一般是主键
(3)所有库(表)的并集是全量数据
Mysql主从读写分离
概述
由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。
从库进行数据更新
备库B和主库A之间维持了一个长连接。主库A内部有一个线程,专门用于服务备库B的这个长连接,然后两库之间通过传递事务日志同步进行同步。
解决的问题
- 读写分离最大的作用就是缓解服务器的压力,同时也有利于数据备份
- 所以读写分离,解决的是,数据库的写入,影响了查询的效率。
- 读写分离是用来解决数据库的读性能瓶颈的
为什么能提高性能
- 系统提供的主从复制机制,和我们单纯通过SQL语句来更新还是差别很大的。从库不需要做sql解析和复杂的写查询,从机重放SQL的时,只要回放到内存中就可以了,所以速度要快上许多。实际测试可以发现,实际上数据库至少一大半的cpu是消耗到sql解析处理的。
- 分担负载,可以将读的任务分散到slaves上
存在的问题
既然涉及到同步,那一定有延迟; 有延迟,就一定可能在读的时候产生脏数据;所以,能够在从MYSQL上进行的读操作,一定对实时性和脏数据有一定容忍度的数据;比如,登陆日志,后台报表,首页统计信息来源;文章;资讯;SNS消息;实时性要求高的数据仍然需要从主数据库获得。
总结
即主库主要负责处理写请求,大量对实时性要求不是特别高的读请求通过负载均衡分布到多个从库上,从而降低主库的压力。
分表分库+水平拆分+mysql集群
在Memcached的高速缓存,MySQL的主从复制, 读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。
MyISAM和InnoDB引擎区别
-
MyISAM管理非事务表,而InnoDB存储引擎提供事务安全表 -
MyISAM只支持表锁。InnoDB支持表锁、行锁。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的 -
MyISAM适合SELECT密集型的表,而InnoDB适合INSERT和UPDATE密集型的表 -
MyISAM速度可能超快,占用存储空间也小,但是程序要求事务支持,故InnoDB是必须的
但是MyISAM可以用于主从复制的从库中,从库引擎可以设置为MyISAM。
不支持事务的情况
例如执行下面两条sql语句,第二条SQL语句存在语法存在错误如果数据库引擎支持事务就可以回滚,两个账户的money不变
如果不支持回滚的话第一条数据的"money"的值就会减少一百,而第二条数据的值仍然为不变
//执行SQL语句
statement.addBatch("update account set money=money-100 where card_id= '1234567890'");
statement.addBatch("update account money=money+100 where card_id= '0987654321'");
分表分库分区
同时,开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候,分表分库成了一个热门技术,是面试的热门问题也是业界讨论的热门技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力一般的公司带来了希望。虽然MySQL推出了MySQL Cluster集群,但性能也不能很好满足互联网的要求,只是在高可靠性上提供了非常大的保证。
什么是表分区?
mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存表索引的。如果一张表的数据量太大的话,那么myd,myi就会变的很大,查找数据就会变的很慢,这个时候我们可以利用mysql的分区功能,在物理上将这一张表对应的三个文件,分割成许多个小块,这样呢,我们查找一条数据时,就不用全部查找了,只要知道这条数据在哪一块,然后在那一块找就行了。如果表的数据太大,可能一个磁盘放不下,这个时候,我们可以把数据分配到不同的磁盘里面去。
表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。
表分区与分表的区别
分表:指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。
分表与分区的区别在于:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。
表分区有什么好处?
- 与单个磁盘或文件系统分区相比,可以存储更多的数据。
- 对于那些已经失去保存意义的数据,通常可以通过删除与那些数据有关的分区,很容易地删除那些数据。相反地,在某些情况下,添加新数据的过程又可以通过为那些新数据专门增加一个新的分区,来很方便地实现。
- 一些查询可以得到极大的优化,这主要是借助于满足一个给定WHERE语句的数据可以只保存在一个或多个分区内,这样在查找时就不用查找其他剩余的分区。因为分区可以在创建了分区表后进行修改,所以在第一次配置分区方案时还不曾这么做时,可以重新组织数据,来提高那些常用查询的效率。
- 涉及到例如SUM()和COUNT()这样聚合函数的查询,可以很容易地进行并行处理。这种查询的一个简单例子如 “SELECT salesperson_id, COUNT (orders) as order_total FROM sales GROUP BY salesperson_id;”。通过“并行”,这意味着该查询可以在每个分区上同时进行,最终结果只需通过总计所有分区得到的结果。
- 通过跨多个磁盘来分散数据查询,来获得更大的查询吞吐量。
MySQL的扩展性瓶颈
MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小, 如果能把这些数据从MySQL省去,MySQL将变得非常的小。
关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySOL的开发人员面临的问题。
今天面临的挑战
大数据时代的3V
- 海量Volume
- 多样Variety
- 实时Velocity
互联网需求的3高:
- 高并发
- 高可扩
- 高性能
仅仅靠传统的mysql,是无法需求的!
为什么使用NoSQL
今天我们可以通过第三方平台( 如: Google,Facebook等) 可以很容易的访问和抓取数据。用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了,NoSQL数据库的发展也却能很好的处理这些大的数据。
NoSQL概述
NoSQL是什么
NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
NoSQL能干什么
易扩展
NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。
大数据量高性能
NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。
这得益于它的无关系性,数据库的结构简单。
一般MySQL使用Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,在针对web2.0的交互频繁的应用,Cache性能不高。
而NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了。
多样灵活的数据模型
NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。
而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。
常见NoSQl
Redis MongDB Memcache
NoSQL学习要点
KV 键值对 Cache 缓存 Persistence 持久化
NOSQL和SQL区别
NoSQL数据模型简介
NOSQL技术与传统的关系数据库相比,最明显的转变是抛弃了关系模型。NoSQL主要有四种模型,前三种都是面向聚合的
健值 - 面向聚合
临时性键值存储:Memcached,Redis 永久性键值存储:ROMA,Redis
应用场景:内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等 数据模型:Key指向Value的键值对,通常用HashTable来实现
优点:查找速度快
缺点:数据无结构化,通常只被当做字符串或者是二进制数据
文档 - 面向聚合
Mongodb是一个基于分布式文件存储的数据库,由c++语言编写。 为web应用提供可扩展的高性能数据存储解决方案,是一个介于关系数据库和非关系数据库之间的产品,是非关系数据中功能最丰富,最像关系数据库的
应用场景:WEB应用(与key-value类似,value是结构化的,不同的是数据库能够了解到value的内容)
数据模型:Key-Value对应的键值对,Value是结构化的数据
优点:数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构
缺点:查询性能不高,而且缺乏统一的查询语法
列族 - 面向聚合
应用场景:分布式的文件系统
数据模型:以列簇式存储,将一列数据存储在一起
优点:查找速度快,可扩展性强,更容易进行分布式扩展
缺点:功能相对局限
图形
应用场景:社交网络,推荐系统等,专注于构建关系图谱
数据模型:图结构
优点:利用图结构相关算法。比如最短路径寻址,N度关系查找等等。
缺点:很多时候要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案。
四种模型的比较
什么是聚合模型
聚合是“领域驱动设计(DDD)”中的术语: 把一组相互关联的对象视为一个整体单元来操作,这个单元叫聚合。一般通过原子操作更新聚合的值,并且在与数据存储通信时,也以聚合为单位。以聚合为单位来复制和分片比较自然。
关系模型:元组(行)是受限的结构:只能包含一系列的值,不能嵌套另外的元组和列表。所有操作都以元组为目标,而且其返回值必须是元组。
面向聚合:是NoSQL操作数据时所用的单元,其结构比元组复杂,这种结构可以存放列表或嵌套其他记录。
为什么要聚合模型来处理
- 高并发的操作是不太建议用关联查询的,互联网公司用冗余数据来避免关联查询
- 分布式事务是支持不了太多的并发的
在分布式数据库中CAP原理CAP+BASE
传统的ACID
ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性
- A (Atomicity) 原子性
原子性:原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。 - C (Consistency) 一致性
一致性:一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。 - I (Isolation) 独立性
独立性:所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。比如现有有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的 - D (Durability) 持久性
持久性:持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。
CAP
RDBMS一般指关系数据库管理系统
CAP的三选二
AP 浏览数,点赞数没必要保证强一致性
BASE
分布式+集群简介
集群:人多力量大
|