Ddata用于在节点间共享数据,我们知道一说到共享麻烦事儿就来了,特别是集群情况下,因为它意味着并行/并发的读和写、不知道什么时候、不知道在什么地方随机发生读或者写。传统RDB数据库没这个烦恼,因为它是单点(分布式存储也需要这么一个单点即主节点),数据访问方法都是串行的。这期间包含两种IO:网络和磁盘的,如果是事务还可能有多次磁盘IO、如果是分布式事务那可能有多次网络/磁盘IO...
ddata使用键值形式存储和访问数据(所以数据可看做data entry)、值即所谓的Conflict Free Replicated Data Types(CRDT),CRDT基于因果推断允许在任意节点更新数据,而不需要和外部协调,大数据首先就得干掉分布式事务,分布式事务就是需要外部协调的典型,要提高效率,每个节点首先需要是自恰自驱的、自主决策,要crud干就完了,用不着跟谁商量,只要能够merge即可,求同存异、埋头苦干就是效率最高的。CRDT数据结构保障自动merge更新,这些数据结构包括:counters, sets, maps and registers.
ddata分布式数据和Amazon Dynamo的相似点比较多,目前看CRDT由于需要支持数据merge带来额外负担是肯定的,所以ddata可以用于集群状态同步、但不适用大数据量高并发业务数据。Akka的集群就用ddata同步成员状态,The cluster membership state is a specialized CRDT, which means that it has a monotonic merge function. When concurrent changes occur on different nodes the updates can always be merged and converge to the same end result.

和其他Akka组件如分片套路类似,ddata也是基于actor style来使用的:你可以用Replicator复制器actor访问ddata数据、每台节点机都需要启动这个actor我们把它叫做replica、各个节点机上的replica组成一个分布式数据复制层(类似分片的分布式ShardRegion层)、你的程序在哪个节点机上就和那个节点机上的replica打交道;所有replica都是一样的名字、一样的path. 拿到本机replica actorRef有个便利方法:
val replicator = DistributedData(context.system).replicator
写和读数据就是给replicas !Update消息,CRDT基于gossip收敛的,默认一致性保障是保证最终一致性,最终一致的系统,可能读到过期值:a read may return an out-of-date value. 注意只是可能,这还要取决于一致性级别:类似卡珊德拉,Akka分布式数据对每条读写都可以指定一致性级别(代码示例):
1、WriteLocal写本地:写入本地replica、写方法立即返回、之后disseminated with gossip;
2、WriteTo(n)写n个:写入值需要写到至少n个replicas去包括本地replica;
3、WriteMajority写多数:写入值需要写到占集群多数个的replicas去,比如:N/2 + 1个,N是集群节点机数量。WriteMajority配ReadMajority,可以为它们定义最少节点数minCap,这样可以减少/甚至消除读到陈旧数据的风险,minCap定义了多数值Majority,最低是N / 2 + 1.
对于小集群来说(节点机<7),成员变动可能很容易影响多数值Majority. 此时minCap更有意义。
4、WriteAll写全部:实时的、同步的、强一致写,集群所有节点全写完、才算写完,此时是CP系统;
读一样有上述一致性指定。在你本地,你所做的所有写以及读写之间都是有序的、有保障的。写是否成功是通过消息告知你的:Replicator.UpdateSuccess/UpdateFailure,这是异步的,我们知道凡是异步消息其ack需要采用类似correlationID形式做到:In the Update message you can pass an optional request context, which the Replicator does not care about, but is included in the reply messages. This is a convenient way to pass contextual information (e.g. original sender) without having to use ask or maintain local correlation data structures.

归纳来说:
1、异步消息可以看作同步RPC的超集,用Akka我们可以ask然后同步等待;
2、基于gossip协议的最终一致架构可以看做强一致的超集;
上述的前者都可以做到后者的功能(性能需要测试验证),反之不然,这是因为架构约束。最终一致架构也可以支持强一致,反之不然,比如HBase只能强一致,但是Akka/Cassandra都可以灵活支持某条数据的一致性级别:写入/读取一个节点机(最高性能、最终一致)、写入/读取大多数节点机(一致性和性能的均衡)、写入/读取所有节点机(集群范围强一致)。总之,基于Akka可以简便的构建即支持异步消息传输、也支持同步RPC调用的合理系统,比如对于海量流式metric/log数据,以异步传输为主(也可以支持异步ack);对于UI界面查询请求或命令下发,以RPC方式调用。
小总结一下你为什么选择Akka:Akka实现了Actor模型,并且在此之上提供了诸多价值,首要价值也是Actor模型的主要价值即解耦,actor的解耦是在最深层次的对象级别上的解耦,打破了单体程序的局限,达到真正的高并发的同时使得分布式成了水到渠成,与此技术路线相似的有ErLang、Go语言的goroutine或在其他语言中称之为协程、纤程的技术。Akka不仅仅在运行时提供价值,更重要的可能是对开发也提供了诸多价值:
1. 对并发模型进行了更高的抽象,使程序员构建并发、并行应用的难度大幅度降低并且统一了二者,基于Akka开发的分布式并行程序,可以在单机调试,之后不改代码只改配置直接部署到多机运行;
2. 基于scala语言,使代码量显著降低,同时大幅度提升代码的业务描述能力。大幅消减java等传统语言中的模板代码、固定流程代码,可以消除所有业务无关的例行公事的操作代码,实现代码直接表达业务,达到近似DSL的精简业务描述效果;
3. 与scala语言的面向并发特性良好结合,scala语言与Akka由一家公司统一维护,创始人也是java语言编译器作者,所以在Akka当中结合scala的面向并发编程有明确、全面的最佳实践总结和误区、注意点总结,Akka的一些经过实践检验的优良特性也会合并到scala语言,而scala语言一直在引领java语言的发展方向。另外,所有java生态圈中的工具,scala语言都可以无缝采用,反之不然;
4. Akka以库依赖形式使用,可以很方便的结合springBoot。其actor开发模型兼容面向对象,actor既可以有状态也可以有行为,使其业务建模更加自然合理(个人认为这是DDD死灰复燃的唯一机会);可以实现核心业务模块完全无锁、无阻塞,这使得核心业务代码在开发时完全可reason out
最后,说说微服务,其本质就是SOA2.0,就是新瓶装旧酒,基本属于一波技术泡沫。依据是SOA做得好的微服务就能做好,SOA做不好的微服务也做不好:
1、SOA ESB做得好,微服务Service Mesh就比较火。这里面唯一变数是服务间交互协议,希望在于RSocket,sm如果紧跟反应式大趋势,做好RSocket支持,尚能峰回路转漂亮转身;
2、SOA服务注册+编排做的不好,微服务一样做不好;特别是编排,微服务也必将在服务编排上困难重重。而没有了服务编排的服务注册,也叫不响了,类似jmDNS早就有轻量级的局域网服务发现能力,再搞个服务注册中心近乎鸡肋;
网友评论