为什么会有数据库的事务隔离级别
从我们学习关系型数据库的时候就知道了数据库有四种隔离级别。那么为什么要做隔离级别这样的设置呢。
TIP:MySQL有四种隔离级别,Oracle有两种隔离级别。
任何一种数据库在数据存储的同时都不得不面临性能问题的考虑,另外关系型数据库事务的ACID这四种特性,真的需要同时满足吗。
其实,对于大多数应用系统来讲,事务的原子性和持久性肯定是要保证的,不然事务就没有存在的必要性了。但是,一致性和隔离性多少都是可以牺牲的,然后来换取性能。
这样便有了隔离级别。
比如,可重复读这个隔离级别,事务A获取了一份数据,在事务A还没有结束的时候,事务B开始更新同一份数据,如果事务A能够得到更新的数据,则表明事务A是不可重复读的,也就说明隔离性差,隔离性差就说明数据库在保持数据一致性上”使用的劲“小,数据库在整体的性能上表现的就更好些。不然,如果事务A是可重复读的,那数据库就要付出”更大的劲“,然后性能自然就下降些。
所以为了这样的平衡,数据库有了这样的事务隔离级别,按需索取。为了平衡性能和准确性,提出了不同的隔离级别,用户就可以按照自己的需求去平衡选择。
这样的平衡,有时候我们也可以说是在数据的一致性设计上的”无奈“。除了有ACID不能同时满足的无奈,分布式CAP理论也从分布式环境中描述了一种无奈。
CAP 定理决定了 C 与 A 不可兼得,传统的 ACID 强一致性在分布式环境中,要想能保证一致性(C),就不得不牺牲可用性(A)。
那么这个时候,随着分布式系统中节点数量的增加,整个系统发生服务中断的概率和时间都会随之增长。所以,我们只能退而求其次,把“最终一致性”作为分布式架构下事务处理的目标。
可靠事件队列、TCC 和 SAGA,都是实现最终一致性的三种主流模式。
任何数据库存储系统,每一次查询数据的时候所耗费的时间,都取决于两个因素:
1、查找时间的复杂度;
2、数据总量;
查找时间的复杂度,又取决于两个因素:
1、查找算法;
2、存储数据的数据结构;
算法和数据结构,都是由数据库本身实现的,我们基本改变不了,业务系统更没有办法改变它。
MySQL 在 InnoDB 存储引擎下创建的索引都是基于 B+ 树实现的,所以查询时的 I/O 次数很大程度取决于树的高度,随着 B+ 树的树高增高,I/O 次数增加,查询性能也就越差。
所以最后只剩下,数据总量,这一个抓手。
所以,我们就开始分库分表。
搞不定算法,就搞定数据量。
这里,问你一个问题,如果是并发高,侧重点是分库?还是分表?
答案是分库,分库涉及到数据库实例的粒度,一个数据库实例扛不住,就把请求分散到更多的实例上,这跟我们的应用维度抗用户量的道理是一样的。
不过呢,我们一般分库分表是同时进行的。
但是,分库分表还有一个”能不就不“原则:能不拆就不拆,能少拆就不多拆。
拆,这个动作,跟我们从单体到微服务一样,微服务自然有它的优势,但应用服务节点多了,跨进程依赖关系就多了,可能出错的节点也多了,同时也给我们的维护工作带来一定挑战,当然,总体是利大于弊的。
这里的分库分表也是一样。数据拆分得越散,开发和维护起来就越麻烦,系统出问题的概率就越大。
Redis在分布式环境中的作用确实很大,我们用它来做分布式缓存减轻后端数据库的压力,用它来做分布式锁确保应用程序的一致性,在这两种场景下Redis极大的帮助我们处理了分布式环境下既需要抗住用户的高并发请求又需要保证数据一致性的”窘境“。
但是Redis也不是万能的。
比如,我们用它来做缓存的时候,当然是希望缓存的命中率越高越好。在缓存商品数据、用户搜索这样的场景下,每个最终用户所看到的数据都是一样的,此时Redis缓存的命中率自然是非常高的。但是像我的订单这样的场景,不同的用户要看到不同的数据内容,缓存的命中率相对就没有那么高了,这种情况下就会有一部分请求到数据库上。
Redis本身是不可靠的存储,它有丢失数据的可能性,也不支持事务查询,另外自由的查询能力也太弱,而我们的应用需求场景中往往需要各种各样的查询需求。基于这些现实的情况,一方面是我们不可能抛弃我们的关系型数据库,另外一方面我们也只能在局部的环境下使用Redis。
----END----
这里记录,我每周碰到的,或想到的,引起触动,或感动的,事物的思考及笔记。不见得都对,但开始思考记录总是好的。