http://www.94geek.com/2015/albianj.html
摘要
我们设计并开发了内容中心统一的分布式开发框架。我们把它取名为albian, albian是基于java的(故以下简称albianj)。他主要是面向海量数据处理、海 量数据访问、并解决互联 开发中经常会碰到的数据海量增长问题,也一并解决 互联 开发团队中,开发人员的水平参差不齐的问题。albianj还应当具有良好 的伸缩性和可定制性。他设计并且运行在简单的 web容器中,比如tomcat或者是jetty,也可以运行在application类型的应用中, 但是它依然提供了企业级开发应该具备的一切效能。
从业界来说,目前成熟的框架有很多,但是从EJB因为复杂性而被大多数公 司放弃后,spring+Hibernate在业界成为了事实上的标准。总体来说 spring+Hibernate可以解决掉企业开发的很多问题,但是在互联 行业,在快速 开发、海量数据处理和快速迭代引起的统一问题面前,这个组合还是有或多或少 的问题。所以我们最后决定自己开发一个适合我们自己的框架出来,来解决sh组 合不能很好的解决的问题。
albianj的使用满足了我们在业务上对于程序代码控制和功能上对于处理海量实 时数据的需要。目前albianj已经使用在我们的生产环境中,主要为内容中心提 供数据的存储和读取之用。目前它一共被部署在上百台的机器上,来完成对于几 十台数据库的各种不同模式的访问。
简介
albianj主要完成的任务就是统一程序员的工作,让程序员在统一的口径 下完成他们的工作,这仅仅是一个长远的战略目标;更现实的目标是alabianj必 须提供一套简单的机制在应对对于拥有复杂部署结构的后端数据库的访问和在数 据量增长的过程中,方便的切合数据的再划分等等功能。在开源的项目中,我们 考察了guzz和hbm shared,但是前者过于复杂,导致我们迷失在了配置文件中, 而且对于他显式的指定数据路由有一定的不可接受;而后者,它仅仅只是一个补 丁,而且这个补丁的质量真的令人堪忧,不支持分布式事务这是完全不能接受的 事实,而且当使用数据路由之后,分布式事务肯定是无法避免的、肯定会有所需 求的重要功能。所以我们综合的考量下来,决定自己来设计并完成整个框架系统。
对于albianj,其实它和市面上提供的各种开发框架功能类似,最最基本的功能 也仅仅只是IoC和ORM,所以从这2个方面可以看出,我们还是在追求对于OO的控 制。但是albianj不仅仅只是完成这些功能,它更多需要强调一致性。不仅仅是 数据的一致性,而是对于程序员写代码的一致性和可控性,兼具对于各种 albianj中主键的一致性和可控性;其二,它还需要解决一个大多数的框架都没 有解决的问题,那就是数据路由的能力。简单而一致的数据路由功能可以快速的 开发大数据量的业务,并且也可以在短时间让自己的系统重新适应并且无缝的连 连接已经重新切分好的数据。相比传统的开发框架,我们在设计和开发albianj的时候就已经 额外的考虑了更多的内容,并在其中进行了有的放矢的选择,引申出了和以往不 同的开发思路,也实现了我们开始对于albianj设计时制定的目标。
首先,albianj和别的框架不一样的核心点是“单维性”,简单来说就是一种需 求只会一种办法来解决,轻易不会出现第二种办法。就算为此牺牲一定的编程便 利性,albianj也需要守住这个底线。所以这个模式就和spring或者诸如此类的 框架有质的不同,一方面我们没有必要为了迎合新的概念或者新的技术频繁的对 albianj进行升级和改造,另一方面,我们也没有必要为了多功能而引入不必要 的复杂税。从程序员写代码的角度来说,他们也仅仅只需要学会一种途径就可以 依葫芦画瓢似的解决类似的问题。这样的结果就是代码会无比的统一,熟悉 albianj过后开发也是无比的迅速。这一点是albianj一直在追求的,也是一直在 遵循的一个必须准则。albianj所有的功能都是建立在这个标准之上的。
其次,和别的框架一样,我们必须也需要使用配置。但是我们和别的框架不一样 的地方是我们没有“约定优于配置原则”。在稍早之前,随着java对于xml的配 置越来越依赖,导致了很多的java程序员40%的时间在写代码,另外的时间都在 写配置或者是copy配置。后来随着各种抱怨的产生,遂订立了一个规则,就是坑 爹的“约定优于配置”。这个出发点其实和hbm的sharing是一样的,它仅仅只是一 个补丁而已。其实我们经过10多年的互联 开发,总结了一下,我们认为,目前 xml的配置一部分是因为功能的复杂而决定了,另外一部分是被滥用了,两点相 加造成了目前的这种境况,然而为了前面的失误,后面加入了一个补丁(约定优 于配置)来解决这个问题。其实并没有真正的解决问题。所以albianj在设计的 过程中就是尽量的对配置做减法,仅仅保留必要的配置,但是在配置和一致性、 可维护性冲突的时候,我们选择了一致性和可维护性,放弃了对于配置精简的需 求。
第三:albianj是所有组件的总称。其实它里面包括了多个不同功能的组件。对 于这些功能性组件,除了基本kernel以外,所有的组件都是被设计成插件式的。 我们采用了一键安装和尽量透明使用的策略。在一些需要使用的地 方只需要配置项加上某些配置,功能会自动启用。这样在保证解决问题一致性的 同时对程序员又不失开发上的便捷。对于我们的整个系统来说,它不仅仅解决了 开发效率的问题,更是解决了年久失修这个困扰我们团队已久的问题。
第四:albianj对于我们团队来说,还解决了团队中开发人员水平参差不齐的问题。因为 albianj恪守一致性的原则,只要对albianj使用得当,写出来的代码几乎是一个 模板刻出来的,不管程序员的水平是应届生还是具有开发经验的程序员,几乎写 的代码大同小异。在关键的数据路由等功能性问题上,albianj提供的解决方案 是提供一些接口来供程序员使用,程序员要做的事情就是实现这些接口而已,中 间并没有除此之外的任何代码需要程序员来完成。
最后:最重要的一点是,albianj的完成是我们整个团队在互联 开发10多年来的 经验结晶。它容易设计并且容易完成,而且因为它是为我们量身定做的,所以在 使用上并不存在任何碍手碍脚的地方。总体上的架构因为全部是我们自己从头开 始搭建,所以解决bug或者易用性问题也是一件非常简单的事情。我们并没有因 为整个albianj的开发而导致业务的延期,相反在业务的开发中,我们不时的发 现albianj改进的点,对此我们加以了改进,生成的效率也有所提升。我们进行 了逐一的更改和优化。这些更改和优化也会一并在这篇文章中体现。
设计概述
目标
在上面的介绍中,我们简单的介绍了albianj的一些设计的思想和准则。并且我 们声明了albianj在系统存在的地位和它的一些基本功能。在这一节中,我们将 详细的说明albianj设计的目标和对我们的挑战。在设计和实现的过程中,我们 印证了一些我们初定的目标,在项目使用和实施的过程中,我们也根据我们实际 的情况对于初定的目标进行了一定的筛减和优化。
-
首要的目标就是一致性。在开始设计albianj的时候就把albianj的一致 性作为极致的追求来实现。我们认为在一个软件的声明周期内,一致性起到 的作用不仅仅体现在代码的可读性上,而且更有利于后期的软件的可维护性 上。特别当团队的人员开始流动的时候(其实我们一直觉得人员的流动是无 法避免的),拥有一致性和可维护性的软件会拥有更长的生命周期。而且一 致性不仅仅体现在可维护性上,还有更多的是可以节省前期程序员的工作量 和降低bug出现的机率。
-
albianj必须可以应对海量数据的访问。在现在的互联 系统中,海量的数据 和高并发的访问已经变得越来越普遍。对于庞大的系统来说,应对海量数据和 高并发流量的策略就是拆分。所以本质上,albianj其实需要面对上百台甚至 是上千台的后端服务器,他们可能是分布式的存储,也可能是关系型的数据 库,或者是后端的业务接口服务器。albianj可以提供一种简单而有效的方法 来应对那么多的机器。实际的情况其实并不仅仅只是这么简单,因为albianj本 身就在分布式的环境中,它需要部署在成百上千台服务器上,以提供最基本 的框架服务。
-
作为一个开发框架,albianj必须要可以随时来应对机器的增加和损坏。 albianj必须在有限的时间内来应对机器的部署改变,而不需要更改代码或者 仅仅只是更改有限的配置。传统来说,就算机器一切安全而稳固,整个服务 也会因为数据量的增加而需要重新审视架构和机器的部署。更多的时候是需 要拆分数据和移动数据,而albianj需要在面对复杂的架构调整的时候,轻易 的来应对问题。从而让系统重新稳定架构的成本降到最低。
-
作为整个系统的最基本的底层,albianj需要适应更多功能的快速加入。并且 在albianj的规范内快速的形成组件化,做到即插即用的效应。这不仅仅只是 代码级别所考虑的事情,更多的是需要在设计的过程中就注意对于新功能添 加的便捷性。也就是说需要从头就开始考虑以后的可扩展性,做到一致性、 可维护性、可扩展的平衡和兼得。
-
albianj作为这个内容中心的框架,也必须要对程序员做到尽可能的友好,又 必须考虑一些敏感信息对于系统安全的影响,在这两者之间取得相应的平衡, 来达到albianj最好的亲和性和安全性。这个挑战不仅仅在于对于albianj的 使用上,更多的是需要平衡团队内部参差不齐的开发者的编程水平。
-
因为albianj是从头开始搭建的一整套完整的框架,所以难免会出现bug或者 是开发者觉得使用不是那么顺畅的地方。albianj还必须提供一整套的完备机 制来第一时间解决bug或者是易用性的问题。
在总体的设计思想上,albianj的挑战非常的严峻,特别是对于一致性的特别的追求和 对于安全性、易用性、可扩展性之间平衡的需求不是一点点的难度。然而,不管 怎么样,最后还是需要具体的细化到各个技术点的目标上才可以告别空中楼阁, 才会有落地实现的机会,所以我们又对albianj在技术上定下了一些目标,这些 目标组合起来,可以实现上文提到的一些对于albianj的期望。
-
首先为了解决一致性问题,我们必须使用一致的方法来实现各种功能。albianj 必须设计和实现一套OOP编程机制,其中包括接口、实现、配置之类的相关标准。 albianj还必须设计和实现一套代码的命名标准、代码的相关逻辑组织标准。 必须建立和实施一套我们使用albianj的标准和方法。因为 我们的业务代码最后都会建立在albianj上,所以必须要夯实作为基础的 albianj和相关的规则规章,我们才有可能实现严格的一致性需求。
-
对于albianj来说,它其实是一整套我们经常使用的功能性工具集的集合,所 以务必要做到在不损失alabinaj整体性的同时,使用合理的切分方法 来设计和实现albianj的各个子功能集。所谓合理的方法,其实无非也就是系 统的划分原则,在albianj中,我们使用了”统一依赖、各自管理、各自实现、 减少干涉”的原则,我们给这个原则取了一个名字:边界原则。具体的办法就 是各自实现自己的功能,尽可能的减少子系统间的相互依赖,尽可能的减少 跨系统的生命周期内的依赖。
-
albianj不推荐并且放弃了“惯性原则”,albianj使用显式的声明来完成所有的功能 性配置或者是代码的编写。每个人的受教育程度不同、开发经历也不一样、 对待系统的认知和视角也各不相同,所以基本上是无法真正的做到大家 在同一个认知水平上来处理事务,也就是说“惯性原则”中最重要的“惯性”对 整个团队来说基本上是无法实现的。所以必须要提供一种技术或者 是一种机制来约束这个开发者各自的”惯性“,已达到对于整个系统拥有 一个一致的惯性的理解。
-
albianj作为大家使用的一个功能性集合,必要还要做到albianl自身必须要 保持简单,并且要做到因为albianj的存在,可以隐藏albianj的后端的业务 部署关系。不管是业务集群还是数据库集群。开发者 只要认为使用了albianj就可以简单的把整个系统当成单机系统一样的开发和 测试。
架构
在设计albianj之初,其实并没有一个非常明确的对于架构的标准。我们一 致的认为架构的设计实现与架构的层次类别区分并不是由某些理论或者是某篇论 文或者是某个观点来进行的,而是在真正的实现过程中,随着功能点的增加和实 现的代码逐渐的增多,会自然而然的去对整个的系统进行审视和调整,这部分的 工作会一直循序渐进的继续下去,永远不会停止下来。
到目前为止,albianj已经演化成了具有8个子功能集的大架构。它们之间 并无复杂的依赖关系,除了简单的依赖于同一个kernel以外,别的所有的依赖都 是按需而定的。
稍微复杂一点的是需要同时保存多个对象到各自指定的路由数据库,典型的 操作是在保存一个对象的同时再保存一份日志.
最后是albianj必须还有路由sql语句的能力,而不仅仅是路由数据对象.
对着这3部的路由选择,在albianj中也提供了一个基类来完成实现这个功能。 在albianj中,FreeAlbianObjectDataRouter基类就是这个实现类,在通常的情 况下,开发者只有继承这个类就可以了,对于自己的路由需求,可以通过这个类 里面的不同的方法来实现,这个类一共提供了6个方法,分成2组,一组提供给读 服务,另外一组提供给写服务。但是仅仅是这个基类还无法完成albianj提到的路由 功能,整个的路由功能必须还需要配置文件的配合。其中drouter.xml就是配置 路由的配置文件,drouter根据每个对象来定义它的路由,在发生数据操作的时 候这些路由会被albianj自动调用;还有一个配置文件是storage.xml,这是配置 所有数据库连接的文件,这里的配置信息需要和drouter.xml中的路由配合起来 使用。
ORM
在albianj中,因为一些异构数据库的问题,要实现数据路由,必须要依靠ORM来 解决这个问题,那么现在,我们开始说说ORM。
在albianj中,ORM也是被作为一个基本的组件实现。但是albianj中的ORM和很多开源框 架的ORM有很多功能上的取舍。albianj对于ORM进行了精简,已保留albianj最需要 的部分为前提,把所有不相干的功能全部删除掉。所以albianj中的ORM其实仅仅 只是一个对象和关系数据库的实体和表结构映射和相关操作。它并不提供在ORM层面处理复 杂的对象间关系依赖的问题,它也没有涉及到很多的ORM都会存在的多种功能, 比如查询方言等等。这部分的工作有的被albianj转嫁给了程序员来完成,有的 直接就是不在albianj的设计理念之内,所以被删除了。而被转嫁的部分,在 albianj的设计理念中,可以让程序员更好的完成业务开发,也可以更好的处理数据的加载等 问题,虽然在工作量上看似增加了开发者的工作,其实对于系统整体来说,这部 分的工作可以让开发者更好的应对业务问题和系统压力问题。
但是albianj的ORM集成了上文提到的DataRouter,albianj主要是为互联 开发 而设计和实现的。对于albianj来说,解决大并发和海量数据显然要急迫于解决复 杂而吃力不讨好的ORM中的对象问题、全功能问题等等。也因为加入了DataRouter,albianj必 须要重新设计ORM的数据一致性功能。
数据一致性的问题在ORM中可以简单的转换成事务的一致性问题。当数据库只有一台的 时候或者数据都塞在同一个数据库的时候,数据库可以解决掉事务 的一致性问题,但是当需要使用分布式数据库的时候,显然单机的事务已经 无法满足系统对于数据一致性的要求,所以albianj必须引进能在多台数据库服务器 之间可以保证数据一致性要求的技术。在albianj中,这种技术使用了二次提交 来完成。
在albianj中,每一次的数据库访问被成为是一个job,这个job仅仅与现 实业务相关,和albianj需要访问的数据库实例的数量没有关系。或者说albianj 可以在一次job中访问多个数据库实例。所以,job在abianj中其实是一个分布式 事务的控制中心,它对多个数据库实例的事务进行了抽象和统一接管,但是job 不直接管理各个数据库实例的事务和链接,这部分的工作被albianj交给了task 来处理。在一个job中,需要操作的数据库实例一一对应于task。task接管了对 于数据库实例的操作和事务过程。从而可以让albianj支持分布式事务。

albianj的分布式事务并没有采用并行策略,也没有采用嵌套策略。而是同时采 用了这两者的结合体。因为分布式事务的性质决定了在一些极端的是情况下,数 据库中的数据还是会有可能存在不一致的情况。这是采用分布式事务的时候无法 避免的问题。但是albianj也进行了最大程度的去规避这个严重的问题。albianj直 接使用分布式锁搭配上job-task结构就可以处理规避掉这个问题。
albianj在对操作数据的接口中,置入了通知机制,当albianj的事务发生错 误的时候,首先是自动的去回滚,但是当发生了硬件级别的错误后,比如断电等 等问题,那么这时候自动的回滚无济于事,所以albianj会通过通知机制来通知 到系统的维护人员,维护人员会对于这个数据进行回滚。那么在这个回滚的时间段, albianj的锁服务(下面会讲到锁服务)一直锁定着资源保存事务发生时的状态,最 后会由维护人员把这个资源释放。这种极端的情况几乎是不太可能发生的。现实 中,因为业务的特殊性问题,albianj目前服务的严重的资源抢占情况比较少, 所以这套流程还没有真正的派上什么用处,但是albianj为分布式事务提供了这 种机制,以满足以后系统扩展所带来的数据一致性问题。
显然,albianj的分布式事务对于使用的环境要求是相对比较苛刻的,而且产生 的效果并不一定能达到100%的事务完整性。但这并不是我们故意为之,而是因为 分布式事务本身的不可控性导致的。分布式的不可控性到目前为
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!