31百科知识网

31百科知识网

SQL Server 事务

大家好,今天来为大家解答sql server在高并发状态下同时执行查询与更新操作时发生死锁怎么办这个问题的一些问题点,包括并发查询解决办法也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~

本文目录

  1. 如何有效处理数据并发操作问题
  2. sql server在高并发状态下同时执行查询与更新操作时发生死锁怎么办
  3. 宽带并发数超限
  4. 如何设计每秒十万查询的高并发架构

如何有效处理数据并发操作问题

想要知道如何处理数据并发,自然需要先了解数据并发。

什么是数据并发操作呢?

就是同一时间内,不同的线程同时对一条数据进行读写操作。

在互联网时代,一个系统常常有很多人在使用,因此就可能出现高并发的现象,也就是不同的用户同时对一条数据进行操作,如果没有有效的处理,自然就会出现数据的异常。而最常见的一种数据并发的场景就是电商中的秒杀,成千上万个用户对在极端的时间内,抢购一个商品。针对这种场景,商品的库存就是一个需要控制的数据,而多个用户对在同一时间对库存进行重写,一个不小心就可能出现超卖的情况。

针对这种情况,我们如何有效的处理数据并发呢?

第一种方案、数据库锁

从锁的基本属性来说,可以分为两种:一种是共享锁(S),一种是排它锁(X)。在MySQL的数据库中,是有四种隔离级别的,会在读写的时候,自动的使用这两种锁,防止数据出现混乱。

这四种隔离级别分别是:

读未提交(ReadUncommitted)读提交(ReadCommitted)可重复读(RepeatedRead)串行化(Serializable)

当然,不同的隔离级别,效率也是不同的,对于数据的一致性保证也就有不同的结果。而这些可能出现的又有哪些呢?

脏读(dirtyread)

当事务与事务之间没有任何隔离的时候,就可能会出现脏读。例如:商家想看看所有的订单有哪些,这时,用户A提交了一个订单,但事务还没提交,商家却看到了这个订单。而这时就会出现一种问题,当商家去操作这个订单时,可能用户A的订单由于部分问题,导致数据回滚,事务没有提交,这时商家的操作就会失去目标。

不可重复读(unrepeatableread)

一个事务中,两次读操作出来的同一条数据值不同,就是不可重复读。

例如:我们有一个事务A,需要去查询一下商品库存,然后做扣减,这时,事务B操作了这个商品,扣减了一部分库存,当事务A再次去查询商品库存的时候,发现这一次的结果和上次不同了,这就是不可重复读。

幻读(phantomproblem)

一个事务中,两次读操作出来的结果集不同,就是幻读。

例如:一个事务A,去查询现在已经支付的订单有哪些,得到了一个结果集。这时,事务B新提交了一个订单,当事务A再次去查询时,就会出现,两次得到的结果集不同的情况,也就是幻读了。

那针对这些结果,不同的隔离级别可以干什么呢?

“读未提(ReadUncommitted)”能预防啥?啥都预防不了。

“读提交(ReadCommitted)”能预防啥?使用“快照读(SnapshotRead)”方式,避免“脏读”,但是可能出现“不可重复读”和“幻读”。

“可重复读(RepeatedRed)”能预防啥?使用“快照读(SnapshotRead)”方式,锁住被读取记录,避免出现“脏读”、“不可重复读”,但是可能出现“幻读”。

“串行化(Serializable)”能预防啥?有效避免“脏读”、“不可重复读”、“幻读”,不过运行效率奇差。

好了,锁说完了,但是,我们的数据库锁,并不能有效的解决并发的问题,只是尽可能保证数据的一致性,当并发量特别大时,数据库还是容易扛不住。那解决数据并发的另一个手段就是,尽可能的提高处理的速度。

因为数据的IO要提升难度比较大,那么通过其他的方式,对数据进行处理,减少数据库的IO,就是提高并发能力的有效手段了。

最有效的一种方式就是:缓存

想要减少并发出现的概率,那么读写的效率越高,读写的执行时间越短,自然数据并发的可能性就变小了,并发性能也有提高了。

还是用刚才的秒杀举例,我们为的就是保证库存的数据不出错,卖出一个商品,减一个库存,那么,我们就可以将库存放在内存中进行处理。这样,就能够保证库存有序的及时扣减,并且不出现问题。这样,我们的数据库的写操作也变少了,执行效率也就大大提高了。

当然,常用的分布式缓存方式有:Redis和Memcache,Redis可以持久化到硬盘,而Memcache不行,应该怎么选择,就看具体的使用场景了。

当然,缓存毕竟使用的范围有限,很多的数据我们还是必须持久化到硬盘中,那我们就需要提高数据库的IO能力,这样避免一个线程执行时间太长,造成线程的阻塞。

那么,读写分离就是另一种有效的方式了

当我们的写成为了瓶颈的时候,读写分离就是一种可以选择的方式了。

我们的读库就只需要执行读,写库就只需要执行写,把读的压力从主库中分离出去,让主库的资源只是用来保证写的效率,从而提高写操作的性能。

当然,提高数据并发能力的方法还有很多,也还有很多可以研究的技术,我们可以一起共同讨论,共同进步。

sql server在高并发状态下同时执行查询与更新操作时发生死锁怎么办

a要处理一个有A和B的数据,正好同时b也要处理一个有A和B的数据,但是呢,a是从A到B这样处理,b是从B到A这样处理然后互相等待就造成了死锁现象如果理解了上面的概念就可以制造一个死锁的现象了。。关键就是要两个人同时处理同一个数据,但是从不同的顺序来处理

宽带并发数超限

出现此问题有可能是因为目前上网电脑台数超过套餐规定数量,造成后台数据不支持,请拆除多接设备后再试,如不行或连接的设备并未超过套餐规定数量,微信缴费,一键查话费充值,流量、积分、账单、详单均可自助操作,方便快捷。

如何设计每秒十万查询的高并发架构

首先回顾一下,整个架构右侧部分演进到的那个程度,其实已经非常的不错了,因为百亿流量,每秒十万级并发写入的场景,使用MQ限流削峰、分布式KV集群给抗住了。

接着使用了计算与存储分离的架构,各个Slave计算节点会负责提取数据到内存中,基于自研的SQL内存计算引擎完成计算。同时采用了数据动静分离的架构,静态数据全部缓存,动态数据自动提取,保证了尽可能把网络请求开销降低到最低。

另外,通过自研的分布式系统架构,包括数据分片和计算任务分布式执行、弹性资源调度、分布式高容错机制、主备自动切换机制,都能保证整套系统的任意按需扩容,高性能、高可用的的运行。

下一步,咱们得来研究研究架构里左侧的部分了。

二、日益膨胀的离线计算结果

其实大家会注意到,在左侧还有一个MySQL,那个MySQL就是用来承载实时计算结果和离线计算结果放在里面汇总的。

终端的商家用户就可以随意的查询MySQL里的数据分析结果,支撑自己的决策,他可以看当天的数据分析报告,也可以看历史上任何一段时期内的数据分析报告。

但是那个MySQL在早期可能还好一些,因为其实存放在这个MySQL里的数据量相对要小一些,毕竟是计算后的一些结果罢了。但是到了中后期,这个MySQL可是也岌岌可危了。

给大家举一个例子,离线计算链路里,如果每天增量数据是1000万,那么每天计算完以后的结果大概只有50万,每天50万新增数据放入MySQL,其实还是可以接受的。

但是如果每天增量数据是10亿,那么每天计算完以后的结果大致会是千万级,你可以算他是计算结果有5000万条数据吧,每天5000万增量数据写入左侧的MySQL中,你觉得是啥感觉?

可以给大家说说系统当时的情况,基本上就是,单台MySQL服务器的磁盘存储空间很快就要接近满掉,而且单表数据量都是几亿、甚至十亿的级别。

这种量级的单表数据量,你觉得用户查询数据分析报告的时候,体验能好么?基本当时一次查询都是几秒钟的级别。很慢。

更有甚者,出现过用户一次查询要十秒的级别,甚至几十秒,上分钟的级别。很崩溃,用户体验很差,远远达不到付费产品的级别。

所以解决了右侧的存储和计算的问题之后,左侧的查询的问题也迫在眉睫。新一轮的重构,势在必行!

三、分库分表+读写分离

首先就是老一套,分库分表+读写分离,这个基本是基于MySQL的架构中,必经之路了,毕竟实施起来难度不是特别的高,而且速度较快,效果比较显著。

整个的思路和之前第一篇文章(《大型系统架构演进之如何支撑百亿级数据的存储与计算》)讲的基本一致。

说白了,就是分库后,每台主库可以承载部分写入压力,单库的写并发会降低;其次就是单个主库的磁盘空间可以降低负载的数据量,不至于很快就满了;

而分表之后,单个数据表的数据量可以降低到百万级别,这个是支撑海量数据以及保证高性能的最佳实践,基本两三百万的单表数据量级还是合理的。

然后读写分离之后,就可以将单库的读写负载压力分离到主库和从库多台机器上去,主库就承载写负载,从库就承载读负载,这样避免单库所在机器的读写负载过高,导致CPU负载、IO负载、网络负载过高,最后搞得数据库机器宕机。

首先这么重构一下数据库层面的架构之后,效果就好的多了。因为单表数据量降低了,那么用户查询的性能得到很大的提升,基本可以达到1秒以内的效果。

四、每秒10万查询的高并发挑战

上面那套初步的分库分表+读写分离的架构确实支撑了一段时间,但是慢慢的那套架构又暴露出来了弊端出来了,因为商家用户都是开了数据分析页面之后,页面上有js脚本会每隔几秒钟就发送一次请求到后端来加载最新的数据分析结果。

此时就有一个问题了,渐渐的查询MySQL的压力越来越大,基本上可预见的范围是朝着每秒10级别去走。

但是我们分析了一下,其实99%的查询,都是页面JS脚本自动发出刷新当日数据的查询。只有1%的查询是针对昨天以前的历史数据,用户手动指定查询范围后来查询的。

但是现在的这个架构之下,我们是把当日实时数据计算结果(代表了热数据)和历史离线计算结果(代表了冷数据)都放在一起的,所以大家可以想象一下,热数据和冷数据放在一起,然后对热数据的高并发查询占到了99%,那这样的架构还合理吗?

当然不合理,我们需要再次重构系统架构。

五、数据的冷热分离架构

针对上述提到的问题,很明显要做的一个架构重构就是冷热数据分离。也就是说,将今日实时计算出来的热数据放在一个MySQL集群里,将离线计算出来的冷数据放在另外一个MySQL集群里。

然后开发一个数据查询平台,封装底层的多个MySQL集群,根据查询条件动态路由到热数据存储或者是冷数据存储。

通过这个步骤的重构,我们就可以有效的将热数据存储中单表的数据量降低到更少更少,有的单表数据量可能就几十万,因为将离线计算的大量数据结果从表里剥离出去了,放到另外一个集群里去。此时大家可想而知,效果当然是更好了。

因为热数据的单表数据量减少了很多,当时的一个最明显的效果,就是用户99%的查询都是针对热数据存储发起的,性能从原来的1秒左右降低到了200毫秒以内,用户体验提升,大家感觉更好了。

六、自研Elasticsearch+HBase+纯内存的查询引擎

架构演进到这里,看起来好像还不错,但是其实问题还是很多。因为到了这个阶段,系统遇到了另外一个较为严重的问题:冷数据存储,如果完全用MySQL来承载是很不靠谱的。冷数据的数据量是日增长不断增加,而且增速很快,每天都新增几千万。

因此你的MySQL服务器将会面临不断的需要扩容的问题,而且如果为了支撑这1%的冷数据查询请求,不断的扩容增加高配置的MySQL服务器,大家觉得靠谱么?

肯定是不合适的!

要知道,大量分库分表后,MySQL大量的库和表维护起来是相当麻烦的,修改个字段?加个索引?这都是一场麻烦事儿。

此外,因为对冷数据的查询,一般都是针对大量数据的查询,比如用户会选择过去几个月,甚至一年的数据进行分析查询,此时如果纯用MySQL还是挺灾难性的。

因为当时明显发现,针对海量数据场景下,一下子查询分析几个月或者几年的数据,性能是极差的,还是很容易搞成几秒甚至几十秒才出结果。

因此针对这个冷数据的存储和查询的问题,我们最终选择了自研一套基于NoSQL来存储,然后基于NoSQL+内存的SQL计算引擎。

具体来说,我们会将冷数据全部采用ES+HBase来进行存储,ES中主要存放要对冷数据进行筛选的各种条件索引,比如日期以及各种维度的数据,然后HBase中会存放全量的数据字段。

因为ES和HBase的原生SQL支持都不太好,因此我们直接自研了另外一套SQL引擎,专门支持这种特定的场景,就是基本没有多表关联,就是对单个数据集进行查询和分析,然后支持NoSQL存储+内存计算。

这里有一个先决条件,就是如果要做到对冷数据全部是单表类的数据集查询,必须要在冷数据进入NoSQL存储的时候,全部基于ES和HBase的特性做到多表入库关联,进数据存储就全部做成大宽表的状态,将数据关联全部上推到入库时完成,而不是在查询时进行。

对冷数据的查询,我们自研的SQL引擎首先会根据各种where条件先走ES的分布式高性能索引查询,ES可以针对海量数据高性能的检索出来需要的那部分数据,这个过程用ES做是最合适的。

接着就是将检索出来的数据对应的完整的各个数据字段,从HBase里提取出来,拼接成完成的数据。

然后就是将这份数据集放在内存里,进行复杂的函数计算、分组聚合以及排序等操作。

上述操作,全部基于自研的针对这个场景的查询引擎完成,底层基于Elasticsearch、HBase、纯内存来实现。

七、实时数据存储引入缓存集群

好了,到此为止,冷数据的海量数据存储、高性能查询的问题,就解决了。接着回过头来看看当日实时数据的查询,其实实时数据的每日计算结果不会太多,而且写入并发不会特别特别的高,每秒上万也就差不多了。

因此这个背景下,就是用MySQL分库分表来支撑数据的写入、存储和查询,都没问题。

但是有一个小问题,就是说每个商家的实时数据其实不是频繁的变更的,在一段时间内,可能压根儿没变化,因此不需要高并发请求,每秒10万级别的全部落地到数据库层面吧?要全都落地到数据库层面,那可能要给每个主库挂载很多从库来支撑高并发读。

因此这里我们引入了一个缓存集群,实时数据每次更新后写入的时候,都是写数据库集群同时还写缓存集群的,是双写的方式。

然后查询的时候是优先从缓存集群来走,此时基本上90%以上的高并发查询都走缓存集群了,然后只有10%的查询会落地到数据库集群。

八、阶段性总结

好了,到此为止,这个架构基本左边也都重构完毕:

热数据基于缓存集群+数据库集群来承载高并发的每秒十万级别的查询冷数据基于ES+HBase+内存计算的自研查询引擎来支撑海量数据存储以及高性能查询。

经实践,整个效果非常的好。用户对热数据的查询基本多是几十毫秒的响应速度,对冷数据的查询基本都是200毫秒以内的响应速度。

九、下一阶段的展望

其实架构演进到这里已经很不容易了,因为看似这么一张图,里面涉及到无数的细节和技术方案的落地,需要一个团队耗费至少1年的时间才能做到这个程度。

但是接下来,我们要面对的,就是高可用的问题,因为付费级的产品,我们必须要保证超高的可用性,99.99%的可用性,甚至是99.999%的可用性。

但是越是复杂的系统,越容易出现问题,对应的高可用架构就越是复杂无比

OK,关于sql server在高并发状态下同时执行查询与更新操作时发生死锁怎么办和并发查询解决办法的内容到此结束了,希望对大家有所帮助。

sql server 2012数据库基础 并发控制 实验报告

标签:# 死锁# 并发# 同时# 执行# 怎么办