本文是关于 Newbe.Claptrap 项目主体内容的介绍,读者能够经过这篇文章,大致了解项目内容。html
轮子源于需求
随着互联网应用的蓬勃发展,相关的技术理论和实现手段也在被不断创造出来。诸如 “云原生架构”、“微服务架构”、“DevOps” 等一系列关键词愈来愈多的出如今工程师的视野之中。总结来看,这些新理论和新技术的出现,都是为了解决互联网应用中出现的一些技术痛点:git
更高的容量扩展性要求。在商业成功的基础前提下,互联网应用的用户数量、系统压力和硬件设备数量等方面都会随着时间的推移出现明显的增加。这就对应用本省的容量可扩展性提出了要求。这种容量可扩展性一般被描述为 “应用须要支持水平扩展”。github
更高的系统稳定性要求。应用程序可以不间断运行,确保商业活动的持续进展,这是任何与这个应用系统相关的人员都但愿见到的。可是要作到这点,一般来讲是十分困难的。而现今的互联网应用在面对诸多同类竞争者的状况下,若是在这方面作得不够健全,那么极可能会失去一部分用户的青睐。数据库
更高的功能扩展性要求。“拥抱变化”,当人们提到 “敏捷项目管理” 相关的内容时,都会涉及到的一个词语。这个词语充分体现了当今的互联网应用若要成功,在功能性上作到出彩作到成功是多么的重要。也从一个侧面体现了当前互联网环境下产品需求的多变。而做为系统工程师,在应用创建之初就应该考虑这点。编程
更高的开发易用度要求。这里所属的开发易用度是指,在应用系统自身在进行开发时的难易程度。要作到越易于开发,在应用自身的代码结构,可测试性,可部署性上都须要做出相应的努力。多线程
更高的性能要求。这里提到的性能要求,是特指在系统容量增长时的性能要求。避免系统的单点性能问题,让应用系统具有可水平扩展的特性。一般来讲,在性能出现问题时,若能够经过增长物理设备来解决问题,一般来讲是最为简单的办法。而在不一样的系统容量之下,系统性能的优化方案一般是不一样的。所以结合应用场景进行技术方案的选型一直都是系统工程师所须要考虑的问题。架构
本项目,就是基于以上这些系统功能特性要求所总结出来的一套开发框架。这其中包含了相关的理论基石、开发类库和技术规约。并发
世界上本也不存在 “银弹”。一套框架解决不了全部问题。 ——不肯意透露姓名的月落框架
从需求出发
在讲解分布式系统时,经常会用到 “帐号转帐” 这个简单的业务场景来配合描述。这里阐述一下这个业务场景。异步
假设咱们须要建设一个具有帐号体系的业务系统。每一个帐号都有余额。如今须要执行一次转帐操做,将帐号 A 的余额中的 300 划转给帐号 B。另外,基于上节的基本要求,咱们在实现这个场景时,须要考虑如下这些内容:
- 须要应对系统容量的激增。应用初期可能只有 1000 个初始用户。因为应用推广效果良好以及机器人帐号的涌入,用户数量实现了在一个月内实现了三个数量级的攀升,也就是增加到了百万级别。
- 须要考虑系统的稳定性和可恢复性。尽量减小系统总体的平均故障时间,即便出现系统故障也应该是尽量易于恢复的。也就是,要避免出现单点故障。
- 须要考虑业务的可扩展性。后续可能须要增长一些业务逻辑:按照帐户等级限制日转帐额、转帐成功后进行短信通知、转帐支持必定额度的免密转帐、特定的帐号实现 “T+1” 到帐。
- 须要考虑代码的可测试性。系统的业务代码和系统代码可以良好的分离,可以经过单元测试的手段初步验证业务代码和系统代码的正确性和性能。
轮子的理论
本节将介绍一些和本框架紧密结合的理论内容,便于读者在后续的过程当中理解本框架的工做过程。
Actor 模式
Actor 模式是一种并发编程模型。经过这种编程模型的应用能够很好的解决一些系统的并发问题。这里所提到的并发问题是指计算机对同一数据进行逻辑处理时,可能因为存在多个同时发起的请求可能致使数据出现不正确的问题。这个问题在进行多线程编程时必定会遇到的问题。举个简单的例子,假如在不加同步锁的状况下,使用 100 个线程并发对内存中的一个int
变量执行++
操做。那么最终这个变量的结果每每小于 100。此处 Actor 模式是如何避免此问题的。
首先,为了便于理解,读者在此处能够将 Actor 认为是一个对象。在面向对象的语言(Java、C# 等)当中,能够认为 Actor 就是经过new
关键词建立出来的对象。不过这个对象有一些特别的特性:
拥有属于自身的状态。对象均可以拥有自身的属性,这是面向对象语言基本都具有的功能。在 Actor 模式中,这些属性都被统称为Actor的状态(State)
。Actor 的状态由 Actor 自身进行维护。
这就强调了两点:
第1、Actor 的状态只能由自身进行改变,若要从外部改变 Actor 的状态,只能经过调用 Actor 才能改变。
第2、Actor 的状态只在 Actor 内部进行维护,不与当前 Actor 以外的任何对象共享。这里说的不共享也是强调其不能经过外部某个属性的改变而致使 Actor 内部状态的变化。这点主要是为了区别于一些具有 “对象引用” 语言特性的编程语言而言的。例如:在 C# 的class
的public
属性,假如是引用类型,那么在外部得到这个class
以后是能够改变class
中的属性的。可是这在 Actor 模式当中是不被容许的。
不过从 Actor 内部读取数据到外部,这仍然是容许的。
单线程。Actor 一般同一时间只能接受一个调用。这里所述的线程不彻底是指计算机中的线程,是为了凸显 “Actor 同一时间只能处理一个请求的特性” 而使用的词语。假如当前 Actor 正在接受一个调用,那么剩余的调用都会阻塞,直到调用结束,下一个请求才容许被进入。这其实相似于一个同步锁的机制。经过这种机制就避免了对 Actor 内部状态进行修改时,存在并发问题的可能。具体一点说明:若是使用 100 个线程对一个 Actor 进行并发调用,让 Actor 对状态中的一个int
变量进行++
操做。最终这个状态的数值必定是 100。
不过单线程也不是绝对的,在不存在并发问题的请求状况下,容许并发处理。例如读取 Actor 中的状态,这一般不会有并发问题,那么此时就容许进行并发操做。
读到 Actor 单线程特性时,一般读者会考虑到这是否会致使 Actor 自己处理过慢而产生性能问题呢?关于这点,但愿读者继续持有这个问题日后阅读,寻找答案。
事件溯源模式
事件溯源模式是一种软件设计思路。这种设计思路一般与传统的采用增删查改(CRUD)为主的系统设计思路相区别。CRUD 应用一般存在一些局限性:
- 一般来讲 CRUD 应用会采用直接操做数据存储的作法。这样的实现方式可能会因为对数据库优化不足而致使性能瓶颈,而且这种作法会较难实现应用伸缩。
- 在特定的领域一般存在一些数据须要注意对并发问题进行处理,以防止数据更新的错误。这一般须要引入 “锁”、“事务” 等相关的技术来避免此类问题。但这样又有可能引起性能上的损失。
- 除非增长额外的审计手段,不然一般来讲数据的变动历史是不可追踪的。由于数据存储中一般保存的是数据最终的状态。
与 CRUD 作法对比,事件溯源则从设计上避免了上述描述的局限性。接下来围绕上文中提到的 “转帐” 业务场景简述事件溯源的基础工做方式。
采用 CRUD 的方法实现 “转帐”。
采用事件溯源的方式实现 “转帐”。
如上图所示,经过事件溯源模式将转帐业务涉及的余额变更采用事件的方式进行存储。一样也实现了业务自己,而这样却带来了一些好处:
- 经过事件,能够还原出帐号任何阶段的余额,这就必定程度实现了对帐号余额的跟踪。
- 因为两个帐号的事件是独立处理的。所以,两个帐号的处理速度不会相互影响。例如,帐号 B 的转入可能因为须要额外的处理,稍有延迟,但帐号 A 仍然能够的转出。
- 能够经过订阅事件来作一些业务的异步处理。例如:更新数据库中的统计数据,发送短信通知等其余的一些异步操做。
固然引入事件溯源模式以后也就引入了事件溯源相关的一些技术问题。例如:事件所消耗的存储可能较为巨大;不得不该用最终一致性;事件具有不可变性,重构时可能较为困难等。相关的这些问题在一些文章中会有较为细致的说明。读者能够阅读后续的延伸阅读内容,进而进行了解与评估。
系统复杂度是不会由于系统设计变化而减小的,它只是从一个地方转移到了另外的地方。——总说本身菜的月落
让轮子转起来
基于读者已经大致理解了上节理论的基础上,本节将结合上述描述的 “转帐” 业务场景,介绍本框架的工做原理。首先读者须要了解一下本框架的两个名词。
Claptrap
Claptrap 是本框架定义的一种特殊 Actor。除了上文中提到 Actor 两种特性以外,Claptrap 还被定义为具备如下特性:
状态由事件进行控制。Actor 的状态在 Actor 内部进行维护。Claptrap 一样也是如此,不过改变 Claptrap 的状态除了在 Actor 以外,还限定其只能经过事件进行改变。这就将事件溯源模式与 Actor 模式进行告终合。经过事件溯源模式保证了 Actor 状态的正确性和可追溯性。这些改变 Claptrap 状态的事件是由 Claptrap 自身产生的。事件产生的缘由能够是外部的调用也能够是 Claptrap 内部的类触发器机制产生的。
Minion
Minion 是本框架定义的一种特殊 Actor。是在 Claptrap 基础上作出的调整。其具有如下特性:
从对应的 Claptrap 读取事件。与 Claptrap 相同,Minion 的状态也由事件进行控制。不一样的是,Minion 就像其字面意思同样,老是从对应的 Claptrap 处获取事件,从而改变自身的状态。所以,其能够异步的处理 Claptrap 产生事件以后的后续操做。
业务实现
接下来有了前面的基础介绍,如今介绍一下本框架如何实现上文中的 “转帐” 场景。首先能够经过下图来了解一下主要的流程:
如上图所示,整个流程即是本框架实现业务场景的大致过程。另外,还有一些须要指出的是:
- 图中 Client 与 Claptrap 的调用等待只有第一阶段的时候存在,也就是说,这使得 Client 能够更快的获得响应,没必要等待整个流程结束。
- Claptrap A 在处理完自身请求,并将事件发送给 Minion A 以后就能够从新接受请求,这样提升了 Claptrap A 的吞吐量。
- Minion 不只仅只能处理 Claptrap 之间的调用代理。在 Minion 当中还能够根据业务需求进行:发送短信,更新数据库统计数据等其余操做。
- Minion 也能够具有本身的状态,将部分数据维持在自身的状态中以便外部能够从自身进行查询,而不须要从对应的 Claptrap 中进行查询。例如:统计该帐号最近 24 小时的转帐变更,以便快速查询。
业务容量
前文提到本框架须要建设的是一个能够水平扩展的系统架构,只有如此才能应对业务容量的持续增加。在这点上,本框架现阶段采用的是微软开源的 Orleans 和 Service Fabric 搭配,实现应用程序和物理设备的放缩。固然,涉及数据存储部分时势必也涉及到数据库集群等一系列问题。这些属于技术应用的细节,而非框架理论设计的内容。所以,此处只代表本框架能够基于以上的开源架构进行容量放缩。应用过程当中的实际问题,读者能够在后续的项目内容中寻求解答。
轮厂现状
当前项目正处于设立初期,主体的体系结构设计与编码仍在进行中,读者能够经过项目地址了解项目的最新进展:
Github,主要项目源码管理:https://github.com/newbe36524/Newbe.Claptrap
Gitee,码云仓库地址:https://gitee.com/yks/Newbe.Claptrap
延伸阅读
如下这些内容都对本框架产生了深远的影响。读者能够经过阅读如下这些内容,增长对本框架的理解。