分布式系统

一致性和可扩展性redis

  一致性是系统内比较复杂的属性,它会随着系统的变化而变化。简单来讲,一致性就是数据保持一致,在分布式系统中,能够理解为多个节点中数据的值是一致的。一旦系统具备并行性(分布式只是并行的一种表现),保持一致性就变得困难了,毕竟须要协调全局状态。数据库

事务和一致性缓存

  一致性意义上的事务是指单一的原子操做。也就意味着一系列操做要么全成功,要么全不成功,不涉及中间状态。好比A转帐给B,不能存在A余额已经扣除但B余额没有增长的状况。并发

强一致性和最终一致性异步

  数据在任一时刻都是被原子性的事务操做所更新的,这种状况称为强一致性,即系统的全部节点可能会从一个彻底一致的状态转移到另外一个彻底一致的状态。最终一致性意味着在一段时间内发生的更新无论跨度多短,系统的不一样节点在这段时间内都会有不一样的状态,但在一段时间后,节点间的状态最终会达到一致。在分布式环境中,最终一致性一般比强一致性更容易实现。不知道做者为啥很奇怪,这不是很显然的么?哈哈。世界原本就是异步的,异步的就意味着,数据的更新老是有前后的嘛,就看你能不能丈量获得了。分布式

并发性与并行性性能

  并发性是指两个进程从某一个时刻开始,同时存在,但他们不必定在同一时刻运行,也能够在重叠的时间段内运行。并行性引入了两个进程同时执行的意思。支持并行性意味着也支持并发性,但反过来就不必定了。由于并行性的时间要求更高。分布式系统是支持并行性的,单核心单处理器系统是支持并发性的。优化

全局一致的分布式状态影响可扩展性代理

  全局一致的分布式状态违反了现实世界的物理法则,也很难实现。毕竟它在更新状态时,要“暂停整个世界”,以确保系统的每一个模块更新到正确的状态,而后全部节点继续工做。其实吧,这也能够实现,但这样作还有神马意义呢。它严重限制了并行处理的能力,下降了可扩展性。进程

交付保证

  交付保证是创建分布式系统时常常被忽略的一部分,就是如何确保消息消息被送达、处理后返回响应的结果。看看TCP三次握手协议就知道这有多麻烦了。

最多投递一次

  最多投递一次的交付机制最容易实现。由于它就是简单的发送一次消息,而后继续其余工做。这是Akka默认的交付机制,也就是 fire and forget

最少一次

  跟最多一次相反,它容许重复发送数据,以确保被正确处理。但这每每须要存储消息,以便没有收到接收方的确认消息时重发数据。这其实有点麻烦,由于数据存内存吧,可能把内存撑爆,毕竟如今的内存还比较贵,存硬盘吧,存取又比较慢。特别是在海量数据的场景下,就更麻烦了。引入redis等第三方分布式缓存虽然能够折中的解决效率的问题,但也引入了系统的复杂性、不稳定性。

刚好一次交付

  这每每不可能,特别是在分布式系统中,但能够近似作到。刚好一次意味着消息从发送者到接受者只须要刚好一次可靠的传递,没有多余的重复。想一想都不可能,其实也没有必要。其实咱们常常谈论的“刚好一次”,是对刚好一次的变种:消息从发送者到接受者只通过一次正确的处理!其实就是重复的发消息给接受者,接受者消息只进行了一次业务上的处理,对多余的消息只是简单的进行了应答。

集群单例

  有时候系统中一些区域必须是惟一的。好比全局惟一ID的生成器,这个生成器须要跟踪以往使用的ID或者可能使用单调递增的数值。简单来讲就是须要一个全局协调器,一旦不惟一可能形成灾难性的后果。其实我更喜欢局部协调器,这虽然没有解决问题的复杂性,但至少解决了问题影响的范围。幸运的是Akka帮咱们实现了这一机制,能够确保整个集群系统中只有一个actor实例可用,也就是集群单例。它运行在集群中存在时间最长的可用节点上。这有时候也是合理的,运行时间最长意味着最稳定,毕竟活了那么久竟然没有挂,很是可靠。要否则像Windows那样,每天重启就很差了。幸运的是Akka的gossip机制能够肯定哪一个节点是运行最久的节点。

  单例就意味着没有并行,每每也意味着性能瓶颈与可用性问题。毕竟单例不可用期间,发送到集群单例中的任何消息都将被缓存,也就意味着消息不能被及时处理。另外,当集群单例进行节点漂移时,全局状态如何进行漂移也是一件棘手的事情。分布式缓存和单例数据库能够保存这个状态,但也没法避免的增长系统的复杂性和不肯定性。由于它没有完全解决问题,只是暂时转移了问题。使用Akka Persistence能够维持状态,在从新建立实例时,能够恢复先前的状态。

  做者建议除非绝对必要,否则尽可能避免使用。其实咱们能够改变一下思路,把“集群单例”转换成“逻辑单例”,以缩小“单例”不可用时影响的系统的范围。

  在Akka中,集群单例是经过其代理接收消息的,毕竟单例会发生漂移,其ActorRef会发生变化,用代理来消除这一变化是很是合理的。也就是用不变来封装变化,以减小系统的复杂性。

可扩展性

  具有可扩展的系统在处理更高的负载时不会出现故障或性能急剧降低的问题。它与性能的关系微乎其微,优化性能不能保证可扩展性。其实这句话说的有点歧义,由于我以为这亮点仍是有点关系的。毕竟可扩展性是能够用来提升系统高负载时的性能问题的。系统的可扩展性能够分为垂直扩展和水平扩展。垂直扩展意味着增长更多的资源,例如CPU/内存/带宽;水平扩展意味着增长系统的节点数量。在处理某个问题时,若是原来的人忙不过来了,那就有两种方法来解决。一是提升工人的技术熟练程度或用高技能工人替换低产能工人,另一种就是增长工人数量了。两种方案各有优劣,都须要付出必定的代价。

  一个和可扩展性高度相关的概念是弹性。具备弹性是指具有在运行的系统中增长资源的能力,可以经过增长资源来扩展系统,而不影响客户端。其实就是水平扩展的能力。好比,某件工做须要用到一个限定数量的资源,那么提升工人的数量,并必定能提升工做的效率。使系统具备弹性就是消除这个关键资源,以增长水平扩展的能力,那么怎么增长弹性呢?

避免全局状态

  其实也就是避免关键资源。若是必需,能够用集群单例实现。

避免共享状态

  全局状态实际上是共享状态的极端状况,她是集群全部节点之间的共享状态。