并发到底带来了什么问题?

说在前面

我曾不止一次据说过这句话:html

“十个女人没法在一个月内生出孩子”数据库

我明白这句话的意思,用来形容咱们的开发工做须要按部就班,没有办法简单的增长人员就能加快研发速度。后端

这句话也常常被用于反驳产品经理或者老板,试图让他们明白咱们心里所表达的观点,老实说我也说过这样的话,当时还以为挺有道理,如今想来可能有些一厢情愿了。缓存

没错,在现实世界中,固然不可能在一个月内生出孩子,但咱们毕竟是作产品写代码的,而不是真的要去生孩子,因此这种说法未免有点偷换概念。服务器

我并非较真,若是只是想让产品经理明白咱们所要表达的观点,咱们彻底能够用其余的比喻,如实反馈存在的困难与问题便可。网络

言归正传,这句话与本文有什么关系呢?本文想要就“并发”所带来的问题进行探讨,相信看完后你会对此有一个感受。多线程

与我以前写的几篇文章同样,并发一词在本文中所表达的意思是:架构

“在分布式环境下,超过一个线程同时对同一个状态进行访问和变动所致使的一致性问题和可用性问题”并发

 

问题的根源:状态

我没法给出一个百分比数据用以说明到底有多少后端应用程序在使用数据库,但我想国内涉及到增删查改之类的各类“管理系统”应该不在少数。分布式

说到底,增删改查是落地,而怎么落地则取决于业务的须要,也就是说,业务规则以及流程表达了咱们的逻辑,但终究离不开柴米油盐(增删改查)。

那么什么是状态?

它能够是文件,也能够是数据库,能够是一个变量,也能够是缓存,它表明了计算的结果或者依赖(中间结果),因为它是可变的,而且能够被超过1个以上的程序同时访问或者修改。

因此由此产生了两个问题:

  • 一致性:确保业务代码的逻辑符合设计指望。即:咱们如何保证在并发的时候确保状态始终处于咱们预期?
  • 可用性:确保系统能够知足伸缩需求,但同时,也必需要知足一致性。即:在保持一致性的同时,如何提升系统的负载能力?

一致性要求是必须的,没法知足一致性的状况要么是业务逻辑自己有问题,要么就是咱们在编码过程当中出现了BUG,而若是是咱们的编码出现问题,很明显就不符合验收标准。

可用性要求则取决于运营的实际状况,随着系统使用规模的上升,咱们须要保证系统始终处于用的状态下,由于业务方不但愿服务被中断或者超时。

我来描述一下完整的逻辑:

  1. 因为咱们须要确保系统的设计与编码符合业务的流程与规则,因此咱们须要保证一致性。
  2. 因为咱们须要为更多的用户提供服务,因此咱们须要提升系统的可用性。
  3. 因为单台服务器所提供的硬件能力已经达到极限,因此咱们不得不使用多台服务器,造成集群同时服务业务请求。
  4. 因为集群后多个服务器可能会访问和修改同一个状态(状态一致性问题的产生缘由),因此咱们必须使用协调多个服务修改状态的机制(锁、事务,问题的解决方案)。

接下来,我会分别就状态的一致性和可用性进行讨论。

 

问题:一致性

在上一节中,咱们说状态一致证实咱们最终落地的数据是正确的,符合业务逻辑的。不一致是因为咱们对业务的理解或者编码出现了BUG,而BUG是咱们必需要解决的。

这里有两个层面的问题,咱们分别来看一下。

业务层面

若是在业务逻辑的层面上自己就存在悖论,存在漏洞,经验丰富的开发人员会在进行系统设计或者编码的时候就能察觉出来,道理很简单,由于没法被实现,无论怎么样都会存在BUG,而这种BUG是咱们技术人员没法解决的,咱们不可以去猜业务方到底想要什么,由于这极有可能不符合他们的指望,最后仍然有可能会致使返工,形成成本的上升。

就像咱们拿本文开头的那个例子去怼产品经理同样,不少时候是因为咱们不善表达,没有清楚表达出咱们的疑惑,从而形成尴尬的场面。

沟通和管理是困难的,众口难调。如何跟业务人员进行高效的沟通一直以来都是一个难题,但咱们必需要清楚一点的是:

“只有咱们充分洞悉和理解所要实现的业务领域,才可以使咱们更加轻松和加强信心,由于只有这样,咱们才可以选择最适合的技术和模型帮助咱们灵活的完成任务。”

个人意思并非让我们都成为该领域的专家,由于术业有专攻,分工配合才是重中之重,若是咱们没有跟业务需求方达成紧密的一致,就有可能形成浪费。

有关这一块的内容,建议你们看一本书,叫作《领域驱动设计》,英文名是《Domain Driven Design》,简称DDD。

技术层面

技术层面出现不一致的问题通常有两种状况:

  • 咱们没有理解业务的原始需求。
  • 咱们彻底理解业务的需求,可是因为编码形成了BUG,出现了意外的不一致。

若是是第一种,这个没什么好说的,返回业务层面与业务专家进行真诚层面的沟通,获取真正的需求。

若是是第二种,那么咱们首先应该找出不一致的缘由,分析不一致的缘由有助于咱们加深理解和避免此类问题。

若是是因为小失误形成的问题咱们直接修复便可,这其实很常见,咱们写的代码或多或少都要通过测试与修复。

若是是因为并发竞争形成的问题,那咱们就须要用到相关的解决方案了,最多见的是使用数据库事务来保证状态落地的时候不会产生不一致,由于不一致会致使事务的回滚。

还有就是使用锁来限制资源的访问以及修改,这些都是很常见的技术,鉴于本文的重点是想说明产生这些问题的缘由,因此不会对这些解决方案进行详细的讲述,有兴趣的朋友能够翻看一下我以前的文章或者查阅相关资料文档。

问题:可用性

可用性每每决定了系统架构的实现方式,可用性致使了咱们最终将不得不使用分布式集群来应对大规模的访问需求。

能够说,产生并发问题的直接缘由就是可用性,由于它让咱们对状态的管理变得十分复杂。

若是没有可用性要求,最简单的咱们甚至可能都不须要数据库,但现实中,对于一款成功的产品,咱们不可能告诉咱们的老板我们没法实现对不对?

“量变致使质变,当可用性要求愈来愈高,系统规模愈来愈大,即使是再简单的增删改查都将不会再简单”

如何在提高可用性的同时还能保证状态的一致性?这真的不是技术可以解决的。

先冷静一下,个人意思是,因为网络分区的存在,状态的强一致会致使可用性下降,而可用性的提升又会形成分区状态的不一致,从而下降了一致性。

这就是著名CAP定理[1],咱们要么取CP,下降系统的可用性,要么取AP,下降状态的一致性。

那么咱们有没有什么办法来达到一个比较好的平衡呢?

答案是固然能够,可是,就如我一开始所说的,这并非技术一我的就可以解决的问题。

事实已经很明显了,咱们不可能取CP来下降系统的可用性,那样就没得玩了,因此咱们只可以选择AP。

“在业务能够容许范围内,设计一种最终一致的中间流程步骤,来提升系统的可用性,同时,又得以让业务能够正常不受影响,处于预期的运转。”

所以基于BASE理论[2][3]的最终一致更贴近于现实与业务,CAP定理只是证实和告诉咱们,哪些事情行不通,可是BASE理论告诉咱们,上有政策下有对策,使用柔性事务,反脆弱的系统才能让咱们更加的灵活。

因此咱们要怎么作呢?咱们要告诉产品经理,系统的可用性瓶颈必需要更改业务的流程才能得以实现。

咱们要学会表达,告诉产品经理,这不是能不能作的问题,或者我能不能行的问题。

而是计算机科学目前的发展水平就是如此,也会存在极限,咱们必需要学会相互适应,才能保证健康的发展。

 

那么事务怎么办?我该使用分布式事务吗?

尽可能避免使用分布式事务,这是由衷的建议,事实证实分布式事务不只不会提升性能,反而会拖垮高可用场景的系统。

若是你遇到了这个问题,那么说明状态分区隔离以及事务场景有可能存在不合理的地方。

若是你确实有这种需求,那么尽可能避免使用分布式事务,或者将分布式改成本地事务,也就是说不要将它们放到不一样的地方进行事务处理。

若是这样也不行的话,那就必须让事务这个概念被明确包含进业务范围,做为一个独立的实体存在,不要让它隐藏在技术细节中。

这样的话,咱们就可以对这个定义明确的事务“句柄”或者“钩子”进行补偿或者回滚等最终一致幂等操做。

这也是我一直强调表达的,不要仅仅从技术层面来看待分布式事务,它多是一个潜在的业务需求,存在生命周期的潜在概念。

就像咱们对接支付宝同样,根据订单号来确保幂等,返回明确的信息给支付宝代表处理成功或失败,实现最终一致的交易处理。

 

并行就必定快于串行?

这个问题要从两个方面来看,若是并行运行的程序没有相互依赖,没有状态、资源竞争,那么水平拓展是很是容易的。

好比MapReduce,将大规模的数据分发并行处理,最后并归计算结果,速度确定快于串行执行。

相反,若是状态特征在进行并归的时候,先后依赖就产生了耦合,并行处理致使的切换加载开销就变得没有意义。

什么意思呢?

好比将一个个事件进行存储,由于状态本质上来说就是就是一系列事件施加计算后的快照而已(详见https://www.cnblogs.com/xingxueliao/p/11561263.html#event_and_state

因此若是咱们想要计算某一个时间点上的快照,就须要从头将事件播放到指定的位置上,事件对状态的影响是严格按照前后顺序来的。

由于事件致使的状态结果是先后依赖的关系,所以并行运算并不会获得什么帮助,反而会由于切换致使无必要的状态加载以及卸载开销。

这种状况下,串行处理是惟一的方式,咱们应该在这个上下文中,对输入的事件流进行持久批量的计算,并且不用考虑并发所带来的一致性问题。

所以,盲目的使用多线程或者多实例集群不只不会让可用性得以提高,反倒由于竞争的关系致使可用性被下降。

对数据特征进行分析,如何隔离状态才是咱们须要关注的重点,由于只有将没有依赖关系的状态隔离后咱们才有可能提升整个系统的可用性。

 

最后

这就完了?好像你没有提到任何关于如何解决这些问题“具体方案”。

没有具体的方案,由于这超出了本文的范畴,若是你想知道BASE理论或者最终一致须要用到哪些技术,能够参阅一下下面引用链接。

本文只是简单的讲述问题产生的缘由,试图以比较清晰的一个视角来发现和看待问题是为何存在的。

如今,让咱们回到本文一开始提到的那个比喻,为何十个女人没法再一个月内生出一个孩子?

由于孩子是一个总体,是一个聚合,他不能再被细分隔离,进行并行怀孕(原谅我这种比喻)。

所以,若是你的状态是一个不可细分,先后依赖的聚合体,那么并行并不会起到任何帮助,可是换句话来讲,十个妈妈能够在十个月内生出十个孩子,好好琢磨一下这句话。

好了,本文到此也就结束了,若有疑问能够评论,我有时间将会回复。

 

[1]:CAP定理维基百科

[2]:BASE和最终一致

[3]:Abandoning ACID in Favor of BASE in Database Engineering

 

其余有用的资料:

书籍《微服务设计》,强烈推荐。

网站:https://microservices.io/patterns/cn/index.html,一个有关微服务模式汇总网站,每个模式都能解决特定的问题,能够收藏当作手册,虽然是微服务,但它终究是有关分布式以及部署相关的知识,这对于咱们的学习也颇有必要。

相关文章
相关标签/搜索