从0开始,设计研发一个全功能通用大数据系统

在计算机产业发展的 70 年时间里,每一次的 IT 革命,无不带来:更低廉的价格、更完善的功能、更便捷的使用、更广阔的市场!

大数据经过 10 年发展,现在已经到了一个重要的分水岭阶段:通用性和兼容性能力成为大数据发展主流,运行的稳定可靠和使用的简捷、易开发、易维护成为产品发展的驱动力,而这正是 Hadoop/Spark 这类积木式模块框架无法满足的。

本 Chat 讲述这样一个通用大数据系统:系从 0 开始设计研发,从最底层做起,首次将云计算、大数据、数据库、容器、中间件的技术和功能溶为一体。在满足:简单、稳定可靠、易开发、易维护、低成本的同时,在集群规模和数据处理能力上,更是达到惊人的1,000,000级节点、 EB 量级可计算数据(1EB=1,073,741,824GB)、100,000,000次/秒响应规模。目前已是诸多云计算、物联网、超级计算机、人工智能、区块链等大数据应用的基础平台。

讲述内容包括:

  1. 系统架构设计
  2. 网络通信
  3. 数据的组织、结构、存取、调配
  4. 各种场景的分布算法
  5. 体系安全设计
  6. 系统的冗余容错
  7. 人机交互接口
  8. 大数据应用开发(分为系统层和用户层)
  9. 运行测试

本 Chat 的核心要点众多,涉及大数据的理论、技术、产品设计、实践应用,篇幅很长(六、七万字),敬请耐心阅读理解。

摘要

本文阐述一套全功能的通用大数据管理系统。虽然目前市场上已经有各种大数据软件,但是它们无一不是针对某个场景而设计,且缺乏统一标准和兼容性不足,导致用户需要具备足够的专业知识,才有能力去组织搭配不同厂商的产品整合到一起运行。这也是造成后期开发、维护困难,影响运行稳定性,增加使用成本的根本原因。

为此,我们摒弃模块框架思维,提供一种全新方案:在总结大量业务需求和应用案例的基础上,结合软硬件平台特点,从最底层做起,采用体系化、集成化、全功能、一站式的设计思想,将云管理、大数据、数据库、容器、中间件的技术和功能溶为一体。同时满足用户的部署、运行、开发、测试、维护需求,和具备使用的便捷性、安全性和极低的成本。并且在集群规模和数据处理能力上,首次达到1,000,000级节点和 EB 量级(1EB = 1,073,741,8s24GB)可计算数据。使之成为适合全行业、全球用户使用的通用大数据管理系统。

前言

过去七年,我们设计开发了 Laxcus 大数据管理系统。在设计这套产品前,市场上虽然已经有多种数据产品,却没有一家能够提供一套功能完整、适合各行业使用的通用大数据软件,这是我们设计这套系统的初衷。更重要的原因是,随着大数据应用的快速发展,存储计算规模越来越大,以及需求多样性的增加,导致数据处理过程更加复杂和缓慢。如何解决这个问题,在保证效能的前提下,改变大数据应用现状?针对软硬件性能特点,采用架构/功能一体化设计,增加内聚,减少调用层次和处理流程,改进人机界面,提高分布效能,无疑是一个很好的解决思路。但是这个方案也因为体系化和集成化设计的缘故,需要涉及多个技术领域,在当时的技术条件下,设计这种级别的复杂系统,当中有许多不确定因素,在实践中面临着巨大的研发风险。这些风险归纳起来,主要包括以下几个方面:

  1. 对硬件成本和运营成本的考量。
  2. 分布环境下,系统稳定性和可靠性的问题。
  3. 数据业务和处理规模可扩展性、可承载能力、适用性的问题。
  4. 软硬件冗错和处理的问题。
  5. 系统安全的问题。
  6. 人机接口的设计,包括简化开发、管理、操作流程的问题。
  7. 软硬件结合和多平台兼容的问题。
  8. 各个子系统整合和设计指标平衡的问题。

在此后七年时间里,经过我们持续研发和版本升级,上述问题已经全部解决,目前 Laxcus 大数据管理系统的主要特征是:

  1. 系统总体设计成松耦合架构,在此框架下实现数据业务的可定制、可扩展。
  2. 网络通信采用二进制协议,来提高数据传输和处理效率。
  3. 依托多集群并行和弱中心管理为基础,实现超大规模、可伸缩的数据存储和计算。
  4. 引入自适应机制,使集群具备自组织自管理能力,包括数据处理和软硬件故障管理。
  5. 底层数据采用混合存储方案,支持 OLTP 和 OLAP 业务两种业务模式,实现数据即时存取。
  6. 数据处理融入 SQL 思想,兼容数据库,满足高并发和高可靠性两种需求。
  7. 全新设计的分布算法,保证数据处理流程的简捷高效。
  8. 组件化编程,结合容器管理,来减少数据业务的开发和维护难度。
  9. 体系化安全策略,将安全管理纳入系统每一个环节。
  10. 使用类自然语句命令操纵集群,覆盖全部数据处理和管理工作。
  11. 支持全球已知字符集,满足不同国家地区的用户语言使用习惯。

Laxcus 大数据管理系统运行在普通硬件设备上,操作系统涵盖 Linux/Windows,硬件平台包括 X86、ARM、POWER PC、NVIDIA。以下将以2.6版本为基础,结合之前版本,来介绍 Laxcus 大数据管理系统主要的设计、技术、实现,以及发展过程。

《从0开始,设计研发一个全功能通用大数据系统》

图1 Laxcus 大数据管理系统架构。

系统架构

Laxcus 大数据管理系统被设计成松耦合架构。这个松耦合架构可以理解成:为适应复杂分布网络环境,被临时组织起来的工作模型。在这个架构下,所有硬件的设备和软件的模块,以及其上运行的数据处理工作,都被视为一项服务。它们在获得授权许可的条件下,可以自由的加入和退出,以离散、独立、弱依赖的形态存在。其中少量故障不影响系统的整体运行,从而使系统具备极强的稳定性、可靠性、可伸缩、冗余容错的能力。

角色设计和定位

Laxcus 大数据管理系统建立在计算机和网络基础上,通过网络连接管理大量的计算机,形成计算机集群,来组织和实施大规模的数据并行存储和计算工作,这是 Laxcus 大数据管理系统的基本形态。同时,由于计算机集群固有的不稳定特性,需要特别强调软件对分布资源可随机增减的适应性,来弥补计算机集群不稳定造成的损失。这种运行过程中动态波动和需要瞬时感知的特点,完全不同与传统的集中处理模式。这个特点衍生出一系列的新变化,促使我们重新审视产品需要面对的目标和业务需求,并衍生出不同的设计。

以节点为单位的计算集群

在 Laxcus 大数据管理系统的设计里,节点是计算机集群的基本单位。相较与物理性质的计算机来说,节点是一个逻辑概念的单位。以一台实体计算机为例,在它上面可以部署最少一个节点,也可以部署多个节点,共享一台计算机的资源,甚至可以组成一个微型的计算机集群。按照工作属性划分,节点分为四种类型:前端节点、网关节点、工作节点、管理节点。前端节点负责发起任务请求和显示数据处理结果,类似我们通常所说的“客户端”。网关节点将 Laxcus 集群分成内外彼此隔绝的两个部分,它处于“边界”位置。对外,它接受来自前端节点的任务请求;对内,它将前端节点的任务请求转发给集群内部的工作节点处理,同时对外部网部屏蔽集群内部拓扑结构,起着“反向代理服务器和防火墙”的安全作用。在集群的内部运行着工作节点和管理节点。工作节点承接网关节点的任务请求,负责组织和实施具体的数据处理工作。当数据处理工作完成后,将结果返回给边界节点。管理节点在集群里是一个“维护者”的角色,它没有任何实质的数据处理任务,只起到管理和控制集群的作用,包括对下属的网关节点和工作节点的检测和协调。在 Laxcus 集群里,前端节点的部署和维护由是用户来实施,没有特别明确的要求。被大量部署的是工作节点,以及少量的网关节点,和一个管理节点。 Laxcus 大数据管理系统将它们组织起来,来完成许多大规模的数据存储和计算工作。这些大型数据处理工作的工作量,通常是一台或几台计算机不能完成,或者短时间内不能完成的。

超大规模集群

在 Laxcus 大数据管理系统的语义规范里,“域”被定义为计算机集群的单位。在一个计算机集群里,管理节点处于核心地位,负责监督、维护整个集群的运行,它的作用非常重要。管理节点实质也是一台计算机,也受到自身 CPU、内存、网络接口等硬件性能的限制,随着集群内计算机数量的增加,它的管理负荷也在随之升高。因为有这样的限制,在实际部署时,一个集群内的计算机数量是不可能无限增加的。根据我们对多套硬件和数据应用的组合测试显示,当一个集群内的节点数量达到3000至8000这个范围时,会出现管理峰值,超过这个范围,稳定性会大打折扣。但是在实际使用中,用户对数据存储和计算需求总是在持续增加的,这样就产生一个矛盾:如何在保证集群稳定运行的情况下,仍然能够满足用户更大规模存储数据和计算数据需要?多域并行集群就成为这样的一个选择。

Laxcus 的多域并行集群是对现有单域集群的升级和改进。通过把原来多个孤立运行的集群连接起来,在这些集群之上,建立更高一层的管理模型,形成一个两级的管理架构。这个两级架构的集群,在 Laxcus 中被称为“主域集群”,原来的集群成为它下属的子集群,这个集群被称为“子域集群”。子域集群接受主域集群的管理,实时向主域集群汇报自己的运行状态。按照 Laxcus 对集群的设计定义,子域集群需要集中在一个物理环境里,主域集群允许跨地域分散存在。就是说,如果 A 子域集群的机房在北京,B 子域集群的机房在广州,天津机房是 C 主域集群,只要它们之间能够通过网络进行通信,就可以在天津的 C 主域集群管理下协同工作。

通过这样的组合,集群的节点数量获得巨大的提升,极大地拓展了数据存储、计算范围,满足了当前包括未来一段时间内数据处理业务的需要。在跨域测试中,主域集群管理下的计算机节点数量可以达到百万级的规模,数据的存储和计算能力可以达到EB量级。

多用户共享

Laxcus 是多用户系统,支持任意数量的用户同时使用计算机集群。用户通过远程登录的方式接入系统。区分用户身份的唯一标识是账号,账号由用户名和密码组成。在一个系统里,用户名是唯一的,一旦建立不可修改,但允许修改密码。建立账号,包括后续的账号管理工作由系统管理员或者拥有管理员权限的用户来实施。用户在获得管理员的授权后,就拥了建立、管理、操纵数据的权力,可以在自己的数据空间里,执行写入、更新、删除、计算、查询等一系列操作。从这一点来说,用户与数据的关系,更接近博客、推特等网络应用,而与关系数据库中的用户、数据的定义有所区别。在逻辑空间里,系统中的每一个用户和用户持有的数据都是独立的,彼此不存在关联,也不会发生冲突。为了充分发挥多集群并行处理能力,实施大规模并行处理工作,在权限许可的条件下,Laxcus 允许一个账号同时从多个地址登录,执行各种数据操作。

低成本的硬件设备

大数据系统运行依赖于计算机集群。部署计算机集群,需要大量的计算机,以及连接它们网络通信设备,这对所有运营大数据的企业和机构来说,都是一笔庞大的开支。而大数据分布处理和“以多胜强”的特点,更强调运用软件技术和算法所带来的效能,对硬件设备本身并没有太多的要求。所以,低价、性能稳定的硬件设备成为首选。具备这样特点的硬件设备,目前有很多选择,典型如 PC 架构的 X86 系统,还有移动架构的 ARM 系列,Laxcus 都实现了支持。

实际上,但是无论上述哪款系列的计算机,在稳定性和可靠性上都不能和专业服务器相比,发生故障和宕机的可能性比服务器要大得多。针对这个情况,Laxcus 采用了一个简单的办法:冗余和去中心化,来解决这个问题。实现这项功能的要求是 Laxcus 具备实时的节点感知能力,当集群内任何一个节点发生故障,都能很快被 Laxcus 捕获到。在确认故障节点失效后, Laxcus 将执行“隔离”方案,将故障节点从集群中排除,然后从集群中寻找一个新的备用节点,或者通知其它同类型的节点,来分担故障节点的工作。排除故障的处理过程,都会同步通知给集群的维护管理人员。在执行数据处理工作时, Laxcus 要确保每个节点是正常且有效的,才执行数据处理工作。这项措施简单且有效,在多次故障和修复过程中,都验证了这个结论。

弱中心化管理

在 Laxcus 集群里,大量计算机被用来执行数据处理工作,管理节点做为集群的核心,起着监督和协调的作用。如果管理节点的工作内容过多或者复杂,势必将增加管理计算机的工作负荷,降低处理效率,延长处理时间,不能对下级节点的请求及时做出反馈,减弱对集群的监督和协调作用。在此前的几个运行环境,上述情况都分别发生过,是造成系统稳定性变差,影响集群正常运行的重要原因。所以,进一步分散管理节点的工作内容,减少计算开销,降低工作负荷,是提高集群稳定性的主要办法。“弱中心化”思想即由此衍生而来。

鉴于此前的教训,通过对1.x版本的运行统计和评估,在2.0版本中,管理节点的工作被压缩到只有两项内容:监听节点心跳、记录节点元数据。这两项工作由子节点上传,管理节点负责汇总和分析,网络通信量极少,内容简单,计算量非常少,并且只有计算内存里存储和执行,不存在计算瓶颈和计算压力,管理节点的工作负荷因此大幅度减少,从而提高了集群的稳定性。目前因为管理节点问题造成的故障已经基本消失。

负载自适应机制

截止到目前,Laxcus 已经部署到很多应用场景中。这些系统在运营过程中,我们通常不限制用户发出的命令数量,这种忽略经常导致集群的某个节点涌现大量的计算任务,发生超载现象。例如在此前的一次例行检测时,就发现有一个计算节点并行着8000多个计算任务。面对如此庞大的计算压力,如果任由这些现象持续下去而不加以控制,计算机宕机现象随时可能发生。

在1.x版本中,负载控制是由管理节点来监视和协调控制的。在实地运行中显示,这种处理方式虽然达到了协同节点工作和平衡集群负载的目的,但是也存在很多隐忧,主要体现以下几个方面:

  1. 每个节点的负载情况都被反馈到管理节点上,增加了管理节点的数据存储量和计算量,不利于管理节点的弱中心化管理。
  2. 负载的平衡和分配调度依赖于网络通信,当发生大面积超载时,往往也意味着网络中存在大量数据传输,这时的通信成功率会直线下降。实际上为了保证通信成功,就需要进一步加大了管理节点通信量和工作负担,这种情况对管理节点稳定运行有巨大影响。
  3. 负载控制要求实时处理,如果管理节点汇聚了大量任务请求,很难做到实时处理,延时将不可避免发生。同时下属的节点收不到命令,超载会持续下去,宕机的可能性大幅增加。
  4. 整套过载处理机制过于复杂,管理成本颇高,不符合简单化的设计原则。

鉴于以上问题,2.x版本的负载控制,取消了以管理节点为中心的协同处理方式,改为分散到每个节点的自适应调节。这样,当节点在执行计算任务的时候,也监视自己的运行负载。如果发生超载现象,可以立即做出反应,停止分配新的计算任务,或者根据运行任务的权重和资源占用比率,有选择地要求某些任务进入暂停、休眠状态,以达到即时发现即时处理,降低运行负载的目的。原来管理节点承担的平衡运行负载的工作,交给网关节点来协调解决。新的负载处理方式避免了上述1.x版本的问题,同时简化了负载管理的处理流程,提高了运行系统的稳定性。

命名

在 Laxcus 体系里,命名是一组由文字和数字组成的有意义的字符串,是网络设备、分布目录、任务接口、数字数据资源等各种实体资源抽象化的表示,被应用到所有与数据处理有关的环节上。通过命名,系统在运行过程中,屏蔽了许多裸露环节,简化了分布计算方法和计算流程,使复杂的网络运行环境变得简单,同时减少和避免了因为网络拓扑和数据分散可能导致的错误和漏洞。命名只在系统运行过程中产生,被存储到内存里,在节点之间分发,随时间和节点的变动同步发生变化。每个命名在系统中都是唯一的,不允许出现重叠现象。因为命名只应用于系统内部环境,所以它对用户是透明的,注册用户和系统管理员不必在意,也无需了解它的使用、执行情况。

设计命名,对简化系统架构设计,提高系统稳定性、保障系统安全有重要作用。

全语种字符

在2.6版本之前,Laxcus 大数据管理系统只支持中文和英文两种语言的输入和处理。但是随着全球范围内用户的增加,根据用户语言习惯,提供和支持本地字符集,来满足全球用户使用本地文字输入参数和操纵数据处理工作,就显得非常迫切了。所以,2.6版本的一项主要改进工作就是支持全球已知主流字符,在 Laxcus 平台实现各种语言文字的统一输入和处理。

这个修改工作包括两个部分:可视化部分和非可视化部分。可视化部分由 UI 界面和各种字符命令组成,它为用户提供直观的文字输入和显示。非可视化部分承接可视接口的输入,并把数据处理工作贯穿 Laxcus 分布处理的所有层面,最终进入存储层保存。

目前,Laxcus 大数据管理系统已经完整支持不同语言用户在同一个平台的输入和输出,系统会正确识别这些文字,不会产生乱码问题和导致运行错误。

节点的分类

按照设计定义,Laxcus 集群被分为内部和外部两个网络环境。内部网络由集群的所有权人负责实施和管理,为保证集群能够有效可靠运行,需要遵守一系列的集群部署和管理规定。外部网络是用户负责范围,用户可以通过互联网或者 VPN 的方式,远程登录进入集群,通过交互命令传达到集群上,执行数据操作。这样一个布局,可以理解为集群层面的客户机/服务器结构。另外,如果集群没有对外服务的业务,也可以把整个集群部署在内网里,成为一个纯粹的 Intranet 集群。

由于集群这些特点,我们在选择目标硬件设备时,利用集群多节点冗余的属性,和以此为基础研发的分布管理和容纠错技术,使 PC 级的硬件也能很好地运行高端硬件设备才能完成的数据处理工作,并且在价格费用、并行处理规模、可扩展性方面,远超高端设备。这为降低用户运营成本和提高工作效率开辟一条新的通道。

如前所述,节点是 Laxcus 集群的基本单位,由前端节点、网关节点、工作节点、管理节点4类节点组成。理论上,一台物理计算机上可以部署任意多个节点,包括组成一个小型的集群。从节点的工作性质来看,它具有双重身份,即是服务器又是客户机。当它做为服务器使用时,它接受其它节点的命令请求和执行数据处理;当处于客户机状态时,又可以向其它节点发送命令。软件层面上,节点实质是操作系统下的一个进程,在后台运行,通过网络与外界保持联系。在 Laxcus 2.0 版本中,节点共设计有4类11种节点。对每一种节点,我们都详细规定了它的工作内容和处理范围,以下将逐一进行介绍。

《从0开始,设计研发一个全功能通用大数据系统》

图2 Laxcus 大数据集群拓扑结构

Top 节点

Top 是管理节点,在 Laxcus 集群的二级管理构架中,是整个集群的核心,必须保证绝对存在。集群中的其它节点都是 Top 节点的下属节点。按照 Laxcus 集群管理规定,这些节点的工作,必须在 Top 节点启动后启动,在 Top 节点停止前停止。因为 Top 的顶级管理节点身份,它节点只负责最关键的数据资源管理工作,包括用户账号的建立、删除、查询,用户操作权限的授权和回收,数据库资源的分配、释放、检查。Top 有两个直接的下属节点:Home、Aid,Top 要接受它们的注册,以及监测它们的运行状态。由于 Top 节点在集群中的重要性,它的故障将造成整个集群的管理混乱,所以在实际部署时,要求一个 Top 节点在运行的同时,还应该有最少一个 Top 备用节点。为了区分这两类节点,在 Laxcus 集群管理规定里,我们把接受和执行业务处理中的 Top 节点称为 Master 节点,备用的 Top 节点称为 Monitor 节点。Monitor 节点的工作,除了监视 Master 节点运行外,还会同步备份它的数据资源和运行记录。当 Master 节点发生故障失效后,Monitor 节点将启动故障切换过程,接手它的全部管理工作。如果有多个 Monitor 节点,它们会通过协商的方式,在它们中间推举一个 Monitor 节点成为新的 Master 节点。新的 Master 节点会要求原来的下属节点重新注册它的下面,来保证集群继续有效运行,同时新 Master 节点还把故障和切换过程通知集群管理员,由管理员来负责后续的故障计算机检查、维修工作。

因为 Top 节点只负责数据资源管理,以及与 Home、Aid 节点保持少量的通信,所以通常情况下,它的工作负荷很轻。

Home 节点

Home 是管理节点,在 Laxcus 集群二级管理架构中,它是子域集群的核心。对上,向 Top 节点注册,和接受 Top 节点的管理;对下,接受下属节点的注册,以及监督和协调它们的运行。在 Laxcus 集群里,工作节点全部运行在 Home 节点下面,并且弱中心化管理思想也主要体现在 Home 节点上。运行过程中,它只负责两项工作:追踪工作节点运行状态,收集和分析工作节点元数据。这些工作的数据量和产生的计算量都很小,不会对 Home 节点正常运行构成影响。与 Top 节点一样,Home 也要求有一个 Master 节点和最少一个 Monitor 节点。当 Master 节点发生故障时,Monitor 节点可以接替 Master 节点的工作。

Archive 节点

Archive 节点是工作节点,注册到 Top 节点下面,为用户的分布任务组件提供存储、管理、转发服务。在实际使用时,Top 会把它重定向给关联的 Home 节点,再经过 Home 节点结合自己的数据资源进行判断后,分派给自己的下属节点,让它们与 Archive 节点进行数据交互。与 Archive 节点进行直接数据交互的节点有 Data、Work、Build、Call 四种节点,它们将根据自己的业务需要,请求关联的分布任务组件,并把分布任务组件下载下来,部署在自己的节点上,为用户提供分布数据处理。同时,每一个与 Archive 节点执行过成功交互的节点,Archive 节点会记录下它们的信息,当有新的分布任务组件上传后,Archive 节点会把这些新的分布组件,同步推送给这些节点,使得用户在发布分布任务组件后,集群可以立即部署和生效,省却了用户的等待时间。

按照上述流程介绍,实质上,Archive 节点是跨子域集群存在的,我们为 Archive 节点设计了一个 Top/Home/Home 下属节点的三层定向机制,每个 Archive 节点可以为整个集群提供分布任务组件服务,而不必拘泥于某个子域集群的限制。管理员也可以按照自己的需要,设置规则,为不同的用户选择合适的发布空间,提高了管理灵活性。

Log 节点

Log 节点是工作节点,注册到 Home 节点下面。为本集群的其它节点保存它们的日志数据,并提供格式化的日志检索服务。这样的工作内容使得 Log 节点成为 Laxcus 集群里最简单的一个节点。对于上传的日志,Log 节点将根据每个节点的类型和地址,在磁盘上分别建立目录和文件,然后按照时间的格式排列保存下来。在 Laxcus 集群里,各节点上传的日志内容,通常是它们的工作流程和运行错误,这些信息为分布状态下的数据追踪和分析、程序调试、快速定位和判断节点运行故障提供了重要的依据。所以 Log 节点的工作虽然简单,但是非常重要,这也是为什么要单独把日志单独保存并且列为一类节点的原因。

Data节点

Data 节点是工作节点,注册到 Home 节点下面,提供基于磁盘和内存的数据存取服务。在 Laxcus 集群里,Data节点保存着整个集群的数据,是所有数据处理的源头。为了保证正确的数据处理,我们在 Data 节点上,为数据处理设计了一系列的可靠性保证,包括数据完整性、一致性要求,以及各种数据纠错和冗余能力。这些元素的加入,使得 Data 节点的复杂性,远高于集群中的其它节点,它在集群中的重要性,也仅次于 Top、Home 节点。

另外 Data 节点与其它节点不同的是,Data 节点具有“级别”概念,在运行时,被分为主节点(Prime Site)和从节点(Slave Site)两种类型。它们的区别在于,主节点具有“读写”能力,可以执行全部数据操作,包括添加、删除、更新、检索。从节点只拥有“读”的能力,即数据检索操作。这个特点在实际应用中是非常重要的,它为 Laxcus 集群的许多初始指标,如数据冗余、平衡计算、并行处理,提供了基本的保证,成为了 Laxcus 集群实施大规模数据处理的必要条件。

Work 节点

Work 节点是工作节点,注册到 Home 节点下面,提供数据计算服务。在 Laxcus 集群中,Work节点承接来自Data节点的数据,大量重要性高、计算量大的数据处理工作都发生在 Work 节点上,这使得 Work 节点在整个 Laxcus 集群中,成为工作负荷最重的节点,也因此成为体现数据处理效率最关键的一环。

为了获得更高的数据处理效率,在 Laxcus 2.0中,Work 节点通常会把有限的硬件资源集中起来,采用任务队列的手段和快进快出的原则,来解决几个最重要的数据计算工作,从而避免因为无谓的任务空耗硬件资源,而其它需要作业的任务又不能获得工作许可的问题。使得 Work 节点在应对大规模数据处理时,能够充分利用硬件资源,来加快数据计算速度,同时也提高了数据处理效率。

Build 节点

Build 节点是工作节点,注册到 Home 节点,提供 ETL 服务。ETL 是的提取、转换、装载(extract、transform、load)的简称,这个名词很好地描述了一种数据处理过程,是当前许多商业数据应用和互联网数据处理业务的重要组成部分,可以理解为数据计算的前奏和加速器。ETL的核心要旨是把各种数据,按照各自不同的需求,经过重新组织整理后,形成新的数据。这些新的数据,将成为后续数据计算的必要材料。

在许多业务处理中,我们通常是采用 ETL 的方式,把一些数据组合工作从数据计算过程中分离出来,做成一个独立的单元,提前完成,来供后面的数据计算使用,以达到简化数据计算流程的目的。实际上,这种简化的数据计算工作,在很多大规模数据处理业务中使用时,不止是简化了数据处理流程,往往还获得了更高的处理效率。

Call 节点

Call 节点是网关节点,注册到 Home 节点下,提供分布数据管理和任务调度服务。在 Laxcus 集群中,Call节点是一个“中间人”的角色,起到类似路由器的作用。对内,它收集 Data、Work、Build 节点的元数据,并把这些元数据按照各种要求重新组合,保存在内存里。对外,它只接受 Front 节点的注册和命令请求,同时具有对外屏蔽了集群内部拓扑结构的作用,防止可能由外部发起的网络攻击,即使因此发生宕机现象,也可以做到尽量避免波及到集群内部其它节点。当收到 Front 节点的命令后,它将按照命令的要求,为 Front 节点筛选集群内部的数据资源,和定位目标节点。在目标节点完成数据处理后,Call 节点把数据结果返回给 Front 节点,从而完成一次数据处理工作。

与 Archive 节点一样,Call 节点也是可以跨越多个子域集群的。至于是否需要跨越,则由注册的 Front 节点来决定。当 Front 节点需要的数据分别存在于多个子域集群时,那么 Call 节点将自动发生跨越子域集群行为。

Aid 节点

Aid 节点是网关节点,注册到 Top 节点下面,提供账号和账号资源的管理服务。Aid 节点唯一的服务对象是 Front 节点,所有类型的 Front 节点都要首先注册到 Aid 节点下面,才能获得进入集群和操纵数据的权力。Front 节点发出的每一道命令,当通过 Aid 节点审核后,才能交给 Call 节点并转发到集群内部。与 Call 节点一样,Aid 节点也对 Front 节点屏蔽内部网络环境,避免可能的网络攻击行为影响到内部集群运行。Aid 节点这种布局和处理方式,具有分解数据业务负荷和保证集群安全的双重作用。

在 Laxcus 2.0版本中,Aid 节点新增加事务处理能力,这样命令在获得核准前,为了防止命令之间可能存在的事务冲突,Aid 节点给每个命令都增加了事务检查环节。

Front 节点

Front 节点是 Laxcus 集群唯一的前端节点,由用户操作和使用,被要求注册到 Aid 节点下面,为用户提供进入集群和操作集群数据的能力。当 Front 节点成功注册到 Aid 节点后,Front 节点会向 Aid 节点请求关联的 Call 节点地址,然后主动与它们建立联系,来获得执行命令的能力。

在 Laxcus 集群里,Front 节点被分为三种类型:字符界面的控制台、图形界面的终端、没有操作界面的驱动程序。前两种被用户直接使用,分别针对了 Linux 和 Windows 用户的使用习惯。用户在窗口上输入命令后,通过 Aid、Call 这两道网关节点的审查,被发往集群内部处理。后一种是嵌入到其它软件中使用(如 Apache、Tomcat 这类 Web 软件),命令由这些开放接口传递过来,经过 Aid、Call 节点审查通过,发往集群内部处理。Front 节点运行过程中,显示的语言默认与操作系统自动匹配,用户不用做任何设置。

三类 Front 节点允许同时并行存在,每一类又可以同时并发多组命令,所有命令都在 Aid 节点管理下,各自执行自己的数据处理工作,不会发生冲突。至于命令最大并发数,则由集群管理员分配,Aid 节点负责执行。

《从0开始,设计研发一个全功能通用大数据系统》

图3 Front 控制台字符界面

《从0开始,设计研发一个全功能通用大数据系统》

图4 Front 终端图形界面

Watch 节点

Watch 是工作节点,可以选择注册到 Top 或者 Home 节点下面,提供监视主域集群或者子域集群的服务。在 Laxcus 集群里,Watch 节点是唯一完全由集群管理员操纵的节点,它也是 Laxcus 集群另一种拥有图形操作界面的节点,为集群管理员提供可视化的管理工作。集群管理员通过 Watch 节点,能够实时追踪和检查所有节点、所有用户的当前状态。当集群中的节点需要通知管理员,或者感知、捕获到运行故障时,也会通过网络传递给 Watch 节点,Watch 节点将以文字、图像、声音的方式,提醒管理员加予关注,或者要求管理员去排除已经发生的故障。

《从0开始,设计研发一个全功能通用大数据系统》

图5 Watch 节点图形界面

松耦合架构

做为 Laxcus 大数据管理系统最重要的组成部分, Laxcus 架构设计经历了从紧耦合到松耦合的过程。在0.x版本里,我们采用了紧耦合架构。紧耦合架构如下图所示,它的本质是一个客户机/服务器模型,采用同步工作模式。客户机发起请求给服务器,服务器收到,根据请求做出应答,然后反馈给客户机。这种架构最典型的应用就是我们每天都用到的WEB服务。它的优点是简单,设计容易、开发周期短、能够快速投入部署和应用。在 Laxcus 集群的早期运行中,这些特点都得到有力的验证。

《从0开始,设计研发一个全功能通用大数据系统》

图6 紧耦合架构

情况在以后出现了变化。随着 Laxcus 集群规模的不断扩大,业务量的不断增加,尤其是数据计算量、计算时间成倍数的增长后,紧耦合架构渐渐不堪重负,缺点开始不断暴露出来,主要集中在以下几个方面:

  1. 无法支持大规模的计算业务。因为大数据业务对计算机资源占比普遍很大,导致多任务并行能力有限。根据我们在一台 Pentium IV 2.G + 4G 的机器上做的测试,当并行任务量达到100左右的时候,计算机已经发生超载现象。
  2. 无法限制任务载荷,管理设计难度大。由此导致计算机不能控制超载现象,而超载对硬件伤害非常大,会严重降低计算机稳定运行能力和使用寿命。
  3. 网络资源消耗大。紧耦合的本质是同步操作,而同步操作在数据的发送后和返回前,有很大一段时间是空闲的。这种空闲状态下的网络占用,是对网络资源的极大浪费,尤其当使用TCP通信时。
  4. 安全控制力度差。因为服务器直接暴露给客户机,容易引发网络攻击行为。
  5. 程序代码之间关联度过高,不利于模块化和抽象化处理。
  6. 以上现象最终导致系统稳定性变差。

鉴于以上问题,我们重新考虑了系统架构设计,并最终决定将紧耦合架构改为松耦合架构。新架构是原来的客户机/服务器模型之间,加入一层代理服务器(Agent),即把 CS 模型改为 CAS 模型,同时把同步处理模式改为异步处理模式。在新的架构下,客户机的角色不变,代理服务器承担起与客户机通信,和对客户机的识别判断工作,服务器位于代理服务器后面,对客户机来说不可见,它只负责数据处理工作。

在设计松耦合架构的同时,结合新增加的代理服务器这个角色,我们又设计了一套名为:“Invoke/Produce”的任务调度模型。它针对数据处理工作实施异步的抽象化处理和分组分级管理。原来的数据处理和业务逻辑套用这套机制后,程序代码基本不用修改,转移到CAS模型上运行就可以了。

《从0开始,设计研发一个全功能通用大数据系统》

图7 松耦合架构

松耦合架构设计和代码修改完成后,我们在原来的集群上,和紧耦合架构做了各种对比测试。其结果是不仅解决了紧耦合架构上存在的所有问题,而且其中很多技术指标还超出了我们的预估,主要表现以下一些方面:

  1. 多任务并行处理能力获得极大提升。同样是上述的数据处理,紧耦合架构只能支持最大约100多个并行,在松耦合架构上增加到10倍。
  2. 同步实现了负载自适应机制,避免了超载现象。
  3. 对运行任务实现了随机调度和随机控制,进一步避免了持续超载现象。
  4. 基本杜绝了网络攻击行为。由于代理服务器的隔绝和筛查作用,同时结合其它安全管理手段,外部攻击在代理服务器处就被识别和过滤掉了,保护了后面的服务器不受影响。
  5. Invoke/Produce 机制改进了程序的模块化和抽象化,有利实现更复杂的数据处理。
  6. 异步处理减少了网络资源消耗和操作关联。
  7. 综合以上措施,它们共同增强了系统稳定性。

以下我们用一张表格,来对两种架构的性能和特点做个比较总结:

紧耦合架构松耦合架构
工作方式同步异步
业务逻辑关系集中控制分散控制
代码关联依赖
设计开发难度容易复杂
响应能力略低于紧耦合架构
时效表现实时延时
适用范围简单计算复杂计算
安全表现
应用领域小规模并行处理环境大规模、超大规模并行处理环境
系统稳定性

表1 紧耦合/松耦合性能对比

网络通信

Laxcus 大数据管理系统网络建立在 TCP/IP 网络之上。从1.x版本开始,同时支持 IPv4 和 IPv6 两种网络地址。网络通信是 Laxcus 体系里最基础和重要的一环,为了能够利用有限的网络资源,获得最大化的使用效率,我们根据大数据网络环境的特点,设计了一套专属网络通信协议,以及在此协议基础上实现的多套网络通信方案,它们共同组成了 Laxcus 集群的网络通信基础。本章将以 TCP/IP 协议为起点,介绍与网络通信有关的各个组成部分。

FIXP 协议

Laxcus 采用 FIXP 协议通信。FIXP 协议全称是“自由信息交换协议(Free Information eXchange Protocol)”协议。这是一套建立在 TCP/IP 协议之上的应用层二进制通信协议。二进制字序采用小头编码(Little Endian)。协议具有平台独立、上下文无关、结构简单、数据尺寸小等特点。

协议结构

如图8所示,协议结构布局按排列顺序由三部分组成:命令、消息、数据实体。命令分为两种:请求和应答,命令的作用是说明本次通信的基本属性。每次通信由发起方发送请求命令,受理方返回应答命令。消息在命令之后出现,消息在一次通信协议中允许出现任意多个,消息中携带本次通信需要的多类附属信息。消息之间是衔接的,彼此无分隔标记,通过消息头中的标记长度加以区别。在最后面是数据实体部分,数据实体包含本次通信所要传递的内容。这些内容可以是任意格式的,如音频、图像、数据库数据、各种元数据等。数据实体是一个可选部分,是否存在会在消息中注明。比如通信发起方通常是不需要传递数据实体的。

《从0开始,设计研发一个全功能通用大数据系统》

图8 FIXP 协议结构

命令结构

如图9,命令是一个56位(7字节)的数字序列。第一个8位的标识的作用是区分当前是请求命令或者应答命令。之后的协议版本号占用16位,协议版本号是可变的,不同的协议版本号代表不同的协议格式,在应用中分别有不同的解释。目前协议的最新版本号是256(0x100)。 命令的主要区别在第24至40位,请求命令需要提供两个8位的主命令和从命令,说明本次操作的作用目标,应答命令返回一个16位的应答码,确认本次请求是接受、还是因为其它原因拒绝。最后是16位的消息成员数,理论上,一次 FIXP 通信最多可以携带65535个消息。

《从0开始,设计研发一个全功能通用大数据系统》

《从0开始,设计研发一个全功能通用大数据系统》

图9 命令(请求/应答)结构

消息结构

如图10,消息是一个不定长的数据结构,由键、类型、参数长度、参数组成。键占用16位,每个键都有一个固定的定义,键理论上有65536个,目前已经使用了大约100个。类型占用4位,说明后续的参数属性,包括布尔、短整数、整型、长整型,单浮点、双浮点、二进制数组、字符串、压缩二进制数组、压缩字符串。参数长度是一个12位的值,参数的实际尺寸由参数长度说明。需要特别指出的是,数值型参数具有字长压缩能力,例如一个整型数0x20,按照计算机字长标准需要占用4个字节,但是实际尺寸只有1个字节。这时参数长度会说明为1,忽略前面3个0。如本章开篇所述,数值型参数遵循小字头格式(Little Endian)。

《从0开始,设计研发一个全功能通用大数据系统》

图10 消息结构

通信方案

我们在 FIXP 协议基础上提供了四种通信方案。这些通信方案将根据所在环境条件和任务的不同需求,实现有区别的通信,以达到节约网络流量,降低运行负载,提高计算效率的目的。

TCP 通信

TCP 通信建立在 TCP/IP 协议的 TCP 堆栈之上,主要用来处理持续性高的、流量大的数据传输。如数据块的分发,以及 Diffuse/Converge 分布计算传递的数据等。在 Laxcus 集群中,它们是主要的通信流量,占用了大量的网络带宽,严重的时候会发生网络阻塞,影响到集群正常运行。为了避免这种现象,TCP 通信会受到流量控制机制的限制,通过采用降低数据传输流量的办法,腾出一部分网络带宽,来保证其它通信业务的数据传输和集群的稳定运行。

UDP 通信

UDP 通信建立在 TCP/IP 协议的 UDP 堆栈之上,主要针对于非持续、可靠性不高、流量小的数据传输。在 Laxcus 集群中,基于 UDP 传输的 FIXP 协议包,数据尺寸普遍介于20至300字节之间,小于一个 IP 包的最大传输单元(MTU),其中以网络监控包为主,测试节点状态的心跳包是最常用一种。目前 UDP 通信是 Laxcus 集群使用频率最高的通信方案。

KEEP UDP 通信

UDP 的优点在于对计算机的资源占用率低,缺点是数据通信不稳定,存在丢包现象。TCP 恰恰相反,可以提供稳定的数据通信通道,但是对 TCP/IP 堆栈的资源占用率高。在 Laxcus 集群里,存在着大量即需要保持稳定通信,又希望采用 UDP 的网络通信业务。如何在拥有二者优点的情况下又避免它们的缺点,答案就是“KEEP UDP(可持续的包通信)”。KEEP UDP 是我们在 TCP 和 UDP 之间,为 Laxcus 集群网络通信设计的一种过渡方案,通过在 UDP 基础上模拟 TCP 通信过程,为 UDP 数据提供稳定的通信保证。这个方案的实质就是将原来在 TCP/IP 堆栈上进行的包的分组和重组的工作,转移到 Laxcus 控制的工作线程上去执行。在减轻 TCP/IP 堆栈压力的同时,还能够根据当时需求,自由定义一些对包的特殊规则。目前 KEEP UDP 主要用来执行 RPC 处理和传输网络日志,这些都是数据流量不大但是要求可靠传输的通信业务。

RPC 通信

RPC(远程进程调用)的出现由来以久,是一种非常优秀的网络通信方案,至今仍在被广泛使用。它通过隐藏网络两端通信的方式,使网络上两台计算机之间进行的网络调用类似本地 API 调用的过程。这样就极大地简化了开发者对网络编程的难度,提高了工作效率,减少了出错的机会。

Laxcus 包含了对 RPC 的实现,它的通信建立在 TCP 和 KEEP UDP 通信基础之上,通过在本地嵌入接口和对开发者屏蔽网络流程,实现 RPC 调用处理。目前 Laxcus 集群里许多复杂的、安全度高的网络通信都是采用 RPC 方案执行。

通信检测

集群运行过程中,发生的很多故障都与网络和网络设备有关。根据统计,这些故障大致包括:线路损坏、插口松动、电磁影响、网络阻塞、网络设备损坏。其中有些是硬件故障,有些是暂时性的网络故障。判断故障的有效手段是通过发送 ICMP 包来检测网络可达。这项测试可以由单机处理,必要时需要多个节点对一个地址共同测试,然后汇总测试结果得出答案。系统将判断故障是暂时性的网络问题或是不可恢复的物理故障。如果问题严重,将报告给系统管理员,通过人工处理来解决故障问题。通信检测在所有节点都会执行,是体现集群弱中心化和自维持能力的必要手段。

通信服务器

通信服务器是节点管理下的一个工作模块,采用 FIXP 协议通信。通信服务器在启动时分别绑定 TCP/UDP 两个模式的监听套接字(SOCKET),套接字参数在配置文件中定义。根据系统的规定,工作节点的套接字地址在启动时由系统随机选择,管理节点的套接字必须有固定的 IP 地址和端口。因为只有管理节点的地址固定,工作节点才能够在网络上找到管理节点。通信服务器不主动发起通信工作,只接收外部发来的命令。在收到命令后,分派给下属的任务线程完成具体的任务处理。通信服务器还承担网络通信安全的职能,确保通信过程中,网络两端传输的数据是正确和可信任的。通信服务器的安全管理是一个可选项,是否使用由用户决定,在配置文件中设置。

全局时间

在网络通信过程中,为了能够辨别各节点之间数据处理的先后顺序,需要一个统一的参数来标识它们当时所处的位置。这个参数被称为全局时间,也称为主时钟或者时间轴。全局时间以集群中 Top Master 状态节点的操作系统时间为标准,其它所有节点必须遵从这个时间定义,与 Top Master 节点保持一致。全局时间在节点启动时向所属上级管理节点申请和获取,在本地操作系统上设置,误差要求不超过1秒。全局时间目前已经使用在网络日志、网络计算,以及主块冲突、数据冗灾处理中。

流量控制

在造成集群运行不稳定的因素中,有相当大一部分原因是网络传输流量过大所致,如果可以控制每项数据业务的通信流量,让它们以公平和合理的速率传输数据,对于改善集群运行的不稳定状况,将有很大促进作用。Laxcus 采用“等/停传输机制”来控制每项工作的网络传输速率,这是一项 TCP/IP 应用层的技术,是“Invoke/Produce”任务调度模型的一部分,具有实时判断网络流量和错误重传的能力。可以根据当时的网络状况,选择合适的传输速率去传输数据,如果丢包率增加,表明当前网络负载过重,就会延迟数据发送间隔。流量控制对上层是透明的,不用对它做任何管理控制措施。目前 Laxcus 集群所有数据处理业务中,网络通信都默认使用“等/停传输机制”。根据我们对各种数据流量的检测显示,当网络通信启用“等/停传输机制”后,网络传输速率是未启用前的70% – 84%左右,但是网络在面对重负载的数据通信时,它的适应能力增强了。所以,总体而言,这对提高系统稳定性是有利的。

数据存取

当前的很多大数据处理工作,一次计算产生几十个 GB、或者几十个 TB 的数据已是正常现象,驱动数百、数千、甚至上万个计算机节点并行运行也不足为奇。但是在数据处理的后面,对于这种在网络间传输、数量巨大、且发生频率日益增加的数据处理,需要大数据系统具备极高的稳定性和可靠性才能保证完成计算任务。这是一项极其复杂的工作,需要兼顾好数据处理的每一个环节,而在这些环节中,最底层的一环:数据存取,又基本决定了大数据处理的整体效率。

在这一章里,我们将从数据的一些本质特征谈起,从多个角度去阐述数据存取设计,以及如何优化它们。

数据块

在实际的数据应用中,一个单位的数据尺寸往往有很大的随机性。小的可能是几十、几百个字节,大的可能达到数十,数百兆。当一台计算机的数据存储量达到 TB 规模,每天处理的数据量超过TB规模的时候,即使操作系统的文件系统支持这种单位的存储,也将使磁盘运行不堪重负,况且因此产生的磁盘碎片也是一种极大的浪费。

针对这种情况,Laxcus 采用这样一套新数据存取流程,来保障高效率的数据处理。首先,将内存做为数据进入硬盘前的过渡,在内存开辟出一块固定尺寸的空间,此后的每一批数据,都以流式的串行追加方式写入。这样即使当时有多个写入者,因为内存处理效率高和串行写入的原因,在写入过程中几乎没有延迟或者很小,也不会产生写入冲突。当内存空间的数据量达到规定阀值的时候,系统将内存空间关闭,然后执行一系列的数据优化措施,包括对数据的压缩和重组,最后将这块数据以文件形式写入磁盘。进入磁盘的文件,被称为“数据块”。

当数据在内存驻留时,我们将它称为数据块的“CACHE”状态。数据写入磁盘后,我们称它为数据块的“CHUNK”状态。系统为内存数据空间设置的标准阀值是64M,这个参数或者可以由用户定义,最大不能超过4G。对于超大尺寸的内存数据空间,系统将视磁盘文件系统和可用内存空间而定,如果不能支持,将自动调整到合适的尺寸。

为了能够区分内存和磁盘上的每一个数据块,系统会在每个数据块生成时,为它设置一个64位的无符号长整数,做为唯一标识它的编号。这个数据块编号由 Top 运行节点分配,能够保证集群中唯一,不会重复。数据写入磁盘后,这个编号也成为数据块的文件名。

依据上述对 Data 节点的定义,数据块只会保存在 Data 节点上,并且依从 Data 节点的主从关系。即所有主节点上的数据块都是主块(PRIME CHUNK),从节点保存从块(SLAVE CHUNK)。数据块的主从角色也会根据所属 Data 节点级别发生变化。一个集群上,同质数据块只允许拥有一个主块,其它都是从块。写数据的传入,由 Call 节点负责实施,向相关的 Data 主节点均匀推送,这样可以使这些 Data 主节点,在各自拥有的数据量上保持一个相对均衡的状态。

系统不会在其它节点上缓存 Data 节点数据,这个设计是我们参考了大量实际案例后做的决定。据统计,单位时间内的网络计算,一个命令被重复执行的概率极低,这就连带影响到数据的重复命中率,使得缓存数据没有意义,并且缓存数据会占用大量宝贵的内存、硬盘空间,显得得不偿失。

数据块的采用,很好地消除了磁盘碎片的现象,也减轻数据输入磁盘时的写处理压力。按照数据块标准的64M计算,数据写入磁盘的时间不会超过1秒。检索数据时,将按照优化规则从磁盘读取数据,这样也降低了数据输出过程的读处理压力。

存储模型

存储模型是数据在磁盘上的物理组织结构。在许多介绍数据库的书籍里,存储模型又被称为内模型。它在很大程度上决定了数据的适用领域,是衡量数据存取性能的重要指标之一。

我们在数据块的基础上进行了行存储模型(NSM)和列存储模型(DSM)的设计。因为两种存储模型的组织结构完全不同,以下将结合图3.1和数据运作流程,来阐述这两种存储模型的特点及优劣。

见图11,这是一个网络音乐文件表,由6个属性组成。左侧是行存储模型,每一行由不同属性的列值组成,数据是从左到右、从上到下的排列,形成行与行连接的布局。右侧是列存储模型,同属性的列值被组织在一起,成为列的集合,数据是从上向下、从左到右的排列,形成列集合与列集合连接的布局。

行/列存储模型都是建立在数据块的基础上。CACHE 状态时,数据的读/写处理都在内存中进行,虽然两种存储模型的组织结构不尽相同,但是因为内存处理效率颇高,这个问题在速度面前就显示得微不足道。放到实际环境中检验,通过追踪两个存储模型的数据处理流程,发现它们的处理效率的确没有差别,所以两种存储模型虽然结构不同,但是在 CACHE 状态可以完全忽略。

差异主要体现在数据块的 CHUNK 状态。进行 CHUNK 状态后,数据处理将在磁盘上执行。行存储是以行为单位,若整行读取,那么行存储效率很高;如果读取多行,最好在数据写入前将被检索的数据排列在一起,这样只需要对磁盘做一次定位和读取。同样的,列存储是以列集合为单位,它适合对单列连续数据的读取,如果读取多列数据,就需要扫描不同的磁盘位置,这会降低磁盘检索效率。

数据块 CHUNK 状态的写处理,只会发生删除和更新操作。因为更新被分解为删除和追加,所以实质仍然是删除操作。删除操作不会将数据从磁盘中清除,只在数据的某个位置做一个无效标记。如果是批量删除,就需要分别做多个无效标记,这种操作对磁盘性能影响很大。

但是在实际应用时不是这样。根据磁盘(温彻斯特硬盘)工作特性,一个完整的读/写处理,分为磁头定位、等待、数据传输三个阶段。从目前磁盘性能的发展趋势来看,带宽速率的提升优于磁头定位,况且现在计算机的内存容量已经足够大,缓存一些数据也绰绰有余。根据这种情况,实际的读/写处理,是将需要的数据一次性调入内存,在内存中完成处理后再输出。这种处理方式,非常有助于提高磁盘读写效率。

在其它方面,列存储模型的数据是可以压缩的,压缩的好处是能够节省磁盘和内存的空间。比如当某一列有10个999的整数时,就不必把10个999依次排列,而是在999前面加一个10,就表达了10个999的含义。如果有增加或者删除999的操作时,只需要对10这个位置的参数进行修改,而不用修改999本身。行存储模型则没有这方面的能力。另外我们在列存储模型中采用了索引合并技术,这项技术除了节省磁盘和内存空间,还省略了关联操作,简化了存储层面的数据计算。行存储模型如果使用索引,则需要用户说明具体的列,并且在行数据集合之外开辟一块索引数据空间,处理前进行关联才能生效。根据我们对许多应用数据的统计,两组数据完全相同的存储模型,它们的空间占比,列存储模型是行存储模型的28% – 53%之间。

综上所述,行/列存储模型在CACHE状态的处理性能持平。在 CHUNK 状态,行存储模型适合整行读取,列存储模型适合单列读取。CHUNK 状态的写处理,因为数据在内存进行,它们处理性能仍然基本一致。

《从0开始,设计研发一个全功能通用大数据系统》

图11 行存储模型和列存储模型

行级锁

从数据的逻辑角度来看,“行”是能够表达一组完整信息的最小单元。为了保证数据处理的一致性,防止多个操作者竞用数据可能引起的数据混乱,我们在“行”这个层级给数据规置了锁定处理。行级锁是一个互斥锁,一个单位时间内只能执行一个单写或者多读操作。因为它的粒度足够细,只在一行记录上进行操作,不会触及其它行,所有实际上速度极快,对数据块的读写几乎没有影响。目前行级锁已经在行、列两个存储模型上实现。

元数据

为了快速的数据定位和数据计算,元数据做为数据操作者和被操作对象之间的中间媒质,来配合完成数据处理工作。元数据本质上是实体资源的抽象表示,用于描述节点在某一个时间的形态。在 Laxcus 大数据管理系统里,元数据又分为节点元数据和数据元数据。前者由网络地址和运行参数组成,后者将数据块的内容格式化成定长的数值,并且按照要求的规则排列和组合。

所有元数据都在节点运行过程中产生,随着节点运行发生变化和进行更新。元数据产生的数据量非常小,通常只有几百到几千个字节之间。这个特点使它非常适合在网络间快速传递和在内存中驻留。不同类型的节点对元数据各有不同,它们会根据的自己需要,通过管理节点或者直接通信的方式,去收集汇总这些信息,然后在本地进行筛选、分组、排列,存储在内存中,为数据处理提供必需的计算依据。运行环境中的元数据都是实时的,误差被控制在秒级,由一个资源管理模块去负责收集、管理、分配这些信息。这个模块在 Laxcus 集群架构里起着承上启下的作用,它有一个专门的名称:Laxcus 实时映像系统(Laxcus Realtime Map System)。

以大规模的读操作为主,兼顾少量的写操作

根据我们的调查,在很多商业应用场景中,由于固态硬盘(SSD)使用成本居高不下,承担数据存储工作的仍然是传统的机械硬盘(温彻斯特硬盘)。调查中同时也发现,很多大数据处理过程,由于硬盘的 IO 效率远滞后于 CPU 和内存,75%-90%的时间被消耗在硬盘存取上,即使是固态硬盘,虽然 IO 效率比机械硬盘提高一个量级,但是仍然远低于 CPU 和内存的处理能力。这种硬件之间的不匹配,导致硬盘成为大数据处理过程中的最主要瓶颈。所以,改善硬盘的处理效率,对提高大数据处理效率有立竿见影的效果,但是机械硬盘工作的特点,又使它与 CPU、内存这些电子部件在运行效率上存在着巨大的差异。在这种条件下,尽可能多地根据硬盘自身的特点,发挥出它的最大效能,成为解决问题的重要办法。

同时,我们对用户的数据应用追踪中也发现,大数据处理过程中,96%发生在检索操作上,3%是添加数据,删除和更新合计只占不到1%的比例。这个现象促使我们对数据存储产生了不同以往的定位和思路,将数据存储设计的重点围绕着检索展开,并据此制定了以下的执行策略:首先,为保证大数量高频度的检索操作,结合到计算机内的 CPU、内存、硬盘各主要工作部件的性能,在保证数据的持续吞吐性能上,流式处理效率最高。并行的数据写入在进入存储层面时,汇流为串行模式。检索操作的最终目标是硬盘,硬盘检索受制于硬盘物理特性的影响,在数据计算过程中,严重拖滞了整体性能的发挥,为提高数据处理性能,需要在检索前对数据进行优化,如关联和聚凑,同时提供一批优化算法给用户,使用户可以按照自己的意愿去组织和检索数据。删除不改变数据本身,只对数据做无效记录。数据更新分解为删除和添加两步操作,目的在于简化和内聚数据处理流程,同时避免发生多次硬盘读写现象。

上述处理虽然改善了存取性能,但是不可能从根本改变硬盘慢的特点。若要使性能获得根本性的提升,必须跳过硬盘这个瓶颈,所以在2.x版本中增加了一套新的数据处理方案:让内存代替硬盘,数据在网络、内存、CPU 之间流动,以接近 CPU 的速度运行。这种内存处理方案解决了硬盘存取慢的问题,使数据处理性能获得巨大的提升。根据我们的测试评估结果,这个提升幅度在2个量级左右。在实际应用中,用户如果有实时性的数据处理需求,且有足够的内存做保证时,内存处理方案无疑是最佳的选择。

内存计算

数据存储在磁盘上。数据受到磁盘本身的物理特性限制,其读写速率要远远低于内存和 CPU,拖慢了整个计算过程。尤其当面对热点数据块的读写,或者需要读取大量数据做数据计算时,这个影响尤其明显。为了提高计算效率,一个简单的办法就是把数据调入内存,跨过硬盘这道瓶颈,让数据在内存和CPU之间来运行,从而减少磁盘对数据的影响。

我们提供了两个加载数据块的方案:(1)当内存空间比较充裕时,由系统判断,把热点数据块调入内存。(2)由用户从 Front 节点发出命令,指定某些数据,把它们加载到内存里。加载数据的过程中,运行系统会检查计算机的可用内存容量,在接近规定限制值前停止,不会发生内存溢出的现象。

如果这个加载过程是由系统引发的,这是一个临时性加载,热点数据块会受到持续监视。当低于调用阀值,或者内存开始紧张时,或者使用频率更高的热点数据块出现时,会把它从内存中移除。

用户也可以卸载数据块,同样是通过命令从 Front 节点发出。

数据在内存的时候,不影响它的写操作。如果是添加、删除、更新这样的情况发生了,会同步修改它在内存和磁盘上的记录,这个过程仍然是串行的。

实际上,内存数据更适合执行大规模数据检索。尤其在今天很多的 CPU 都已经是64位,寻址范围突破 4G 限制的情况下。只要有足够数量的内存,使集群成为一个临时的数据仓库,让数据跨过磁盘,完全在网络、内存、CPU 之间运行,这是目前提高数据计算效率最有效的办法。

快照和备份

每一个 Cache 状态的主数据块,在 Data 主节点上生成后,会通过网络定向通知其它几个关联节点,产生一个相同编号的 Cache 数据块。此后这个主数据块每一次的写操作,都会通过网络向它们传递它最新的记录。这种以复本形式存在的 Cache 状态数据块,被称为“快照”。

每一个主数据块,从 Cache 状态转入 Chunk 状态后,主节点将立即启动,通过网络分发这个数据块的数据复本。这些被传播到不同节点的数据块,被称为“备份”。

备份数据块传递完成后,主 Data 节点会通知关联的 Data 节点,将 Cache 状态的“快照”删除。此后的运行过程中,如果发生写操作,Chunk 状态的主数据块仍会执行与快照一样的处理。

快照和备份的分配,将根据集群的网段原则进行选择。这是一个类似 LINUX TRACEROUTE 命令的处理过程,通过向不同 Data 节点发送 ICMP 包,探测当前节点与目标节点的跳点数,判断网段之间的距离,按照由远及近的顺序进行分配。

系统默认规定同质数据块的存量是3,即有1个主块,2个属于快照或者备份的从块。主块允许执行读/写处理,从块只能执行读处理,和接受主块的覆写操作。这个存量参数也可以由用户定义,但如果实际运行环境的节点数量不足时,将根据实际情况自行调整。

快照和备份使同质数据块之间保持了原始级的数据一致性,同时还实现了分解读处理压力、负载平衡、冗灾恢复的目的。如果当某个数据块读操作压力过大时,Data 节点会做出判断,把这个数据块进行扩散,以缓解当前节点的压力。

完整性检查

Data 节点启动时,会对磁盘上的每个数据块进行扫描,检查它的数据完整性。完整性检查将具体到数据块的每一列。如果在扫描过程中发现错误,将转入暂停状态,通过网络找到一段正确的数据复本,来覆盖错误的数据。扫描数据块的工作在内存中进行,完成后释放。扫描采用 CRC32 校验和算法,这个计算过程非常快,在32位 Pentium4 2G 计算机上,一个 64M 数据块的扫描时间不超过1秒钟。通过完整性检查,可以即时判断出每个数据块可能存在的错误,为此后正确的数据处理提供了保证。

提高数据处理效率的一些措施

分布计算业务普遍具有数据量大、耗时长、计算复杂的特点,在运行过程中会涉及到大批计算机节点和不同的处理环节。如果在执行这些工作前,有针对性地为它们产生某些数据,使它们能够减少磁盘读写频率,或者省略掉运行过程中的一些处理环节,这会对改善数据处理效率有很大帮助。

在磁盘存取层面,这样的预处理工作包括:把可能被重复使用的中间数据提前生成。针对删除、更新操作造成的磁盘数据碎片现象,做定期碎片整理工作。为了改善集群数据分布不均、单点数据量过大的问题,按需求调整集群数据分布等。

这些预处理工作被投入运行环境之后,数据处理效率有了明显提高。为了加快数据的生成速度,它们都被放到内存中执行。例如优化一个标准的 64M 数据块,在 Pentium4 2.0 G 芯片上,生成时间大约在1.2秒左右。另外,这些数据处理工作都是数据、计算双密集的,对内存、CPU 有很高的占用比率。考虑到这个原因,它们应该避免开业务繁忙的时段,放在系统空闲的时间执行,比如夜间的某个时段。这个时间的业务处理量会明显减少,有助于平衡系统资源使用效率,减少预处理工作对系统正常业务造成的不利影响。

主块冲突

任何一个编号的主数据块在任何时间只能有一个,当前两个相同编号的主数据块在集群上出现时,主块冲突就产生了。主块冲突通常发生在故障 Data 主节点重新启动之后,在进行完整性检查的过程中。

解决主块冲突由 Data 主节点自行协调处理,解决冲突的办法是判断文件的最后修改时间,以时间最新的那个主块为准。旧的主块会从磁盘上删除,新块被保留,从而达到防止主块冲突的目的。

数据负载检测

Data 节点在运行过程中,同一个时间可能有多个命令在执行,并且这些命令从磁盘上提取的数据量往往也是未知的,极有可能发生超载现象。面对这种情况,完全杜绝超载现象已不可能,能够做到的就是及时发现超载现象并且加以限制。

在一台计算机的硬件层面,发生超载的源头有两个:CPU、磁盘。CPU 超载原因是持续进行着大量的数据计算工作,磁盘超载是读写频率过高所致。CPU 超载是持续进行着大量的数据计算工作,而久久得不到缓解。磁盘超载是读写频率过高所致。减少它们超载的办法是限制数据计算量和磁盘 IO 量。Invoke/Produce 通过自适应机制实时追踪检查超载现象。一旦确认后,它将启动“锁”操作,限制计算任务的工作,降低对硬件设备的调用频率。必要时也会通知任务发起方,减少对本节点的调用频率。

对数据超载的检查还会追踪到每个数据块。如果 Invoke/Produce 发现某个数据块在一个时段的调用频率超过阀值,会检查本机的内存,在容量许可的情况下,将它加载到内存里运行。或者去网络上检查数据块的分布状况,把它分发给空闲的 Data 节点,用分散数据块调用的办法,来达到降低负载的目的。

数据组织

在数据的组织结构设计上, Laxcus 严格遵循数据和数据描述分离的原则,这个理念与关系数据库完全一致。在此基础上,为了保证大规模数据存取和计算的需要,大量采用新的数据处理技术。同时出于兼容用户使用习惯和简化数据处理的需要,继续沿用了一些关系数据库的设计和定义,其中不乏对 SQL 做适量的修订。在这些变化中,核心仍然是以关系代数的理念去处理数据,以及类自然语言风格的数据描述。所以用户在使用体验上,和关系数据库相比,不会感觉到有太多的差异。

本章将介绍 Laxcus 数据结构的组成,并对其中的一些修订和修订原因做出说明。

基础

Laxcus 沿袭了关系数据库的用户模型、逻辑模型、存储模型的三层结构。对于逻辑模型,遵循用户账号、数据库、表的结构序列,即用户账号下可以建立多个数据库,数据库下可以建立多个表,在表之下是数据文件。因为 Laxcus 的多集群架构,支持表跨节点跨集群存在。在逻辑描述上,表是行的集合,行由多列构成,每一列对应一个数据值。实体的行,最多容纳32767列(0x7FFF),这个尺寸足以满足各种数据应用需要。在列的基础上,可以建立索引,通过索引实现对表的快速检索。用户的配置数据经过加密后,会保存到 Top 节点的数据字典里。

在兼容 SQL 方面,SQL 的管理控制语句、数据定义语句、数据操作语句,以及运算符、关键字、大部分 SQL 函数,被完整继承下来。用户依然可以按照 SQL 标准进行操作。被支持的还有“空值”,包括 NULL 和 EMPTY。二者的区别是,NULL 表示数据值未定义或者不知道,适用于所有数据类型;EMPTY 只用在字符或者字节数组上,表示数据值确定且是0长度。作为 SQL 核心的4个操作语句也得到支持,并在此基础上扩展了 SELECT 嵌套语句、ORDER BY、GROUP BY 子句,另外也可以使用 LIKE 关键字进行模糊检索。

管理语句说明
CREATE USER建立一个用户账号和密码
ALTER USER修改用户账号的密码
DROP USER删除一个用户账号及其下的所有数据资料
GRANT对用户账号下的某个操作授权
REVOKE收回用户账号下的某个操作权利

表2 管理语句

数据定义说明
CREATE DATABASE建立一个数据库
DROP DATABASE删除一个数据库及其下的所有表
CREATE TABLE建立一个表
DROP TABLE删除一个表和其下的所有数据

表3 数据定义语句

数据操作说明
INSERT写入记录
DELETE删除记录
UPDATE更新记录
SELECT查询记录

表4 数据操作语句

运算符类型运算符说明
比较运算符=等于
>大于
<小于
>=大于等于
<=小于等于
<> !=不等于
逻辑运算符not
and
or
between … and在某些数据范围内
in满足多个条件之一
like模糊查询,匹配特定符串
赋符运算符=对变量赋值

表5 运算符

数据类型

目前各种关系数据库上的数据类型,因为产品和版本原因,数量也不尽相同。在实际应用中,最常用到的大约10余个。根据这种现状,我们在设计数据类型时做了简化处理,取消了其中大部分比较少用的数据类型,保留了一批基础数据类型,另外考虑到网络应用需求,新增加了一批数据类型,同时对某些数据类型进行了合并,最后把它们分为两大类:固定长的数值类型、可变长的数组类型。见表6所示。数值类型在不同操作系统平台上都是统一的,数组类型的长度范围在0 – 2G字节之间,可以随输入数据自动调整,这个尺寸足以容纳当前各种文本、图片、视频、音频等多媒体内容。因为这个尺寸对用户来说已经足够大,用户在输入数据时,可以忽略列长度问题。在字符选择上,为了适用于多语言的混合环境,字符类型内码统一采用 Unicode 编码,因此就避免了乱码现象。Laxcus 字符定义是,单字节的 Char 对应 UTF8 编码,双字节的 WChar 对应 UTF16 Big Endian 编码,四字节的 HChar 对应 UTF32 编码。用户在设计表的时候可以根据需要选择。例如英文环境应该使用 Char,东亚语系内码和西里尔文字都是双字节,采用 WChar 更合适。

全局数据库

在 Laxcus 大数据管理系统里,数据库被定义成“全局”的。这个“全局”意味着每一个数据库的名称,在整个主域集群里都是唯一的,不允许出现重叠现象,即使分属两个用户也不可以。比如,当 A 用户建立一个名为“Product”的数据库后,B用户再建立“Product”数据库将被系统拒绝。

采用全局数据库是出于简化系统设计和减少操作环节的考量。这样节点在运行过程中,因为数据库不存在同名歧义的可能性,系统可以很容易判断每一个数据库和用户的对应关系,可以减少许多不必要的作业流程。

跨数据库操作

我们在进行数据结构规划设计时,经常需要定义一个或者几个数据库,再这些数据库之下,又定义不同需求的表,然后录入不同性质的数据。同时,我们还需要设置一些公共参数,把它们放在一个或者几个表里,为了便于管理和使用,又常常希望放在一个数据库里,在数据处理时,可以给分散在不同数据库下的数据表共同使用。

出于这样的考虑, Laxcus 大数据管理系统支持跨数据库的数据表操作。这样就形成了在一个用户账号下,在数据操作时,所有表与表之间,不用事先声明,就可以实现完全的互通互调用。在精简了系统设计和集中数据资源的同时,也减少了数据处理过程中很多不必要的麻烦,方便了用户快速处理数据,提高了数据处理的灵活性和效率。

在实际应用中,这项功能对数据检索非常有利,诸如连接查询 (Join)和嵌套查询(Sub Select)这样的操作。跨数据库操作不会出现数据混乱,因为它们都要接受 Aid 节点的管理,被 Aid 节点有序地按照所属条件分别执行。

固定表

在关系数据库里,表结构是可以随时修改变化的,但是在 Laxcus ,这项功能被停止使用,表结构一旦定义禁止修改。禁止的原因在于大数据所处的现实环境。试想一下,在一个由上千台计算机组成的集群环境里,如果允许修改表结构,会有什么反应?所有正在运行和关联的任务将被迫停止,新的任务将转入队列中堆积和等待;全部数据内容将按照新的表结构重新组织和排列。这种变化和等待的过程,是任何一个大数据集群所不能承受的。囿于这种现实情况,Laxcus 规定,表的结构一旦正式确定不允许修改。

由于表的不可修改,同时被改变的还有对索引的定义。按照 SQL 规范,“CREATE INDEX”是在“CREATE TABLE”之后进行的操作。现在将它们合并到一起,在定义列的时候,指定这个列是否成为索引。

对索引的解释,Laxcus 也做了调整。新的规定是,一个表中只能有一个列成为主索引(Prime Index)和任意多个列的副索引(Slave Index)。副索引概念与 SQL 没有差别,主索引除了具有副索引的功能,主要用于指示数据排列位置,即将有相同值的列组织到一起。例外的是,对于列存储模型,所有列成员,即使用户不定义索引,其列值也能够自动做为索引使用,同时不增加磁盘和内容开销。但是两种存储模型都需要定义一个主索引,因为涉及到数据内容在磁盘和内存上的排列。

另外,为适应大数据处理需要,在建表命令中增加了一批新的内容,这些参数主要在“Create Table”和“数据库名.表名”之间声明,列声明中也有新的定义。这些参数都是可选的,不声明的时候,系统将使用默认值。请参见图12和表7。

《从0开始,设计研发一个全功能通用大数据系统》

图12 数据库建表命令语句

关键字说明
SM存储模型。NSM:行存储模型;DSM:列存储模型
CLUSTERS子域集群,一个或多个Home地址,或者指定数字
CHUNKSIZE数据块尺寸,以兆为单位
CHUNKCOPY同质数据块数据,包括一个主块和任意个从块
HOSTMODE表对节点所有权。SHARE:共享主机;EXCLUSIVE:独亨主机
HOSTCACHE数据块缓存,根据热度由节点选择是否自动加载
PRIMEHOSTS表初始拥有的Data主节点数量,以后随数据诸量自动增加
NULLNOT NULL
EMPTYNOT EMPTY
CASENOT CASE
LIKENOT LIKE
DEFAULT列的默认值,根据类型支持数值、数组、字符串、SQL函数
PRIME KEYSLAVE KEY
PACKING数组列内容的加密、压缩,若加密提供密码

表7 数据库建表关键字

取消视图

在 SQL 的定义中,视图是一个虚拟表,是对实体表和其它视图的关联和映射,作为一个数据描述存在于系统中,被视为用户和实体表之间的过渡而存在。视图具有向用户屏蔽实体表数据结构的作用,也具有在改变表数据结构时,不用改变上层描述的能力。只是在数据处理时,视图才将数据操作重新定位到实体表上,然后向用户返回经过它处理重组后的新的数据集合。

如果遵守 SQL 这套定义,把视图转移到大数据环境,它在处理海量数据时,就要进行视图和表之间的关联和转换,这无疑将增加运行开销,降低处理效率,同时也加大了系统设计难度,与我们追求简单、快捷的设计初衷相悖。另外 Laxcus 为取代视图提供了一套新的技术方案:数据构建。这项技术提供了对一个表或者多个表的分析、组合能力,并且具有比视图更大的灵活性和高效率。另外一个更重要的原因是:在 Laxcus 体系里,用户、数据之间的概念和关系已经与关系数据库大不一样,关系数据库提供视图的初衷是向部分用户屏蔽表数据结构,或者改变表数据结构而不用改变上层表述,而 Laxcus 的用户拥有对自己数据的全部管理权和使用权,表的数据结构也是固定的,这样的设计如果移植到 Laxcus 显然有悖常理。鉴于这些原因,综合比较之后,Laxcus 取消了视图。

带 Where 子句的 Select 检索

在关系数据库上,Select 检索不带 Where 语句将返回表下的全部记录。按此推理,计算机集群上的操作也应该返回一样的结果,但是这样的操作转移大数据环境下,面对巨大的数据压力将导致灾难性的后果:计算机会因为瞬间暴发的庞大数据量,在还来不及处理时,就造成内存溢出和软件系统崩溃;网络也会因为这些瞬间涌现的巨大流量,出现数据风暴,造成网络阻塞。接下来的可能是大面积故障和连带的波及影响扩大化,造成整个集群的故障,从而被迫中断数据处理业务,造成不可挽回的损失。这种情况显然是不可接受的。另外,在现实的应用环境里,全网络全数据的检索操作其实并没有太多实际意义。

因为上述原因,Laxcus 对数据检索提出这样的规定,基本的数据检索操作必须是“SELECT-FROM-WHERE”语句块,否则将视为非法,拒绝执行。这项检查工作将在 Front 节点上分析执行,然后在集群里还有进一步的判断。

数组列的压缩和加密

我们在使用很多网络应用的时候,经常会在其中保存一些敏感和关键的内容,比如银行卡密码、电子邮件账号、手机电话、家庭地址等私密性很强的信息。这些信息,通常是不希望被别人知道的,包括网络管理人员。还有一些内容,例如像网页或者文档这样的文本数据,通常会很长,如果采用明文的方式保存会占用大量磁盘空间,将其压缩再保存就能有效减少空间占用量,况且文本数据的压缩比率都是非常高的。

Laxcus 提供了这样一个选项,能够对这类信息进行加密和压缩。见图12和表7,这里对格式进行说明。“Packing”是对数组列内容进行压缩和加密的关键字。压缩和加密可以同时声明,也可以任选其一声明,如果只声明其中一种,要去掉连接它们的“AND”关键字。做加密声明时,同时需要提供密码。密码可以是任何语种的和不定长的字符串,在建表时会转换为 UTF8 码保存。压缩和加密的算法名称是固定的,已经支持的压缩算法有:GZIP、ZIP,以及加密算法:AES、DES、3DES、BLOWFISH。

数组列的压缩和加密由用户定义,在建表时输入。在此后的处理过程中,算法和密码也只对用户可见。

特别声明:无论数组列是否被压缩和加密,都不影响其做为索引的使用。

分布锁和事务

当前的大数据应用已经不局限于互联网,随着物联网、人工智能、区块链、智能生产等新兴业态的加入,数据处理需求日益多样化。尤其是商业数据业务,为了避免资源竞用造成的数据处理错误,需要软件系统提供这样一种机制,能够在多用户多任务并发环境里,保证每一项数据处理工作都能够正确读写。这就是分布锁产生的初衷。

目前分布锁被集成到分布资源协同框架下。它能够保证用户所有并行数据处理任务都在 Laxcus 大数据管理系统里正确运行,而不会发生读写冲突。同时,分布锁对用户是透明的,用户执行数据操作时,不会感到分布锁的存在,避免增加用户使用负担。事实上,分布数据处理任务在运行过程中,会被分布资源协同接管,根据任务操作要求,对它自动加入分布锁,和执行分布管理支持。

以分布锁为基础,我们进一步细化出事务处理。Laxcus 事务保持了关系数据库事务的基本状态,即所有数据处理只能有两种结果:成功或者失败。如果失败,数据将回滚到它的初始状态。在这种情况下,结合分布运行环境,避免因为事务造成数据处理效率下降, Laxcus 事务具有以下特点:

  1. 事务基于用户账号,非关联的数据处理之间不发生事务联系。
  2. 数据处理都默认执行事务流程。
  3. 事务从高到低,分成:用户、数据库、表三种级别,上一级覆盖下一级的全部操作。
  4. 事务操作支持排它和共享两种模式。

事务以管理器的形式运行在 Aid 节点上。所有数据处理工作都被默认要求执行事务处理流程。就是它们在执行数据操作前,需要通过事务管理器的审核才能实施。事务申请是一个同步串行操作过程,采用队列的“先到先得”原则,总是由排在最前面的申请获得优先使用权。申请成功后的事务会被记录到管理器队列,作为后续事务申请时的判断比较依据,直到它的数据处理工作完成后,才从管理器队列中撤销。没有申请成功的事务将被挂起,直到前面的事务从队列中撤销后才被唤醒。

在运行系统内部,事务操作的排它和共享模式会被解释成“写”和“读”两个操作。它们的规则处理如下:

  1. 所有”读”事务都可以共享存在。
  2. 如果队列中都是“读”事务,后续一个“写”事务可以获得批准。
  3. 如果队列中有“写”事务,后续一个“写”事务只要不与它们存在资源冲突,就可以获得批准,否则被拒绝挂起。
  4. 为了进一步提高数据库事务和表事务的并发效率,在它们之间有一个“数据库名称”比较。当这样的两个”写“事务发生”数据库名称“冲突时,后续“写”事务被挂起,即同名互斥。
  5. 如果一个事务同时存在“读写”两种状态时,将按照“写”事务规则处理。

《从0开始,设计研发一个全功能通用大数据系统》

图13 Laxcus 事务处理

可调 CAP 策略

可调 CAP 是 Laxcus 2.0版本新增的一项功能,它源自一个叫做“CAP”的分布理论。这套理论包含对分布数据处理的三个基本要求:一致性(Consistency)、可用性(Availability)、分区容错(Partition Tolerance)。它的要旨是:在分布环境下,CAP 的三项要求,最多只能满足其中两项,另一项要被舍弃。目前这个理论已经被很多分布式应用所证实。

在现在的普遍应用场景中,“P”是基本需求,必须得到保证。所以实际上,用户在规划自己的应用架构时,只能在 CP 和 AP 之间进行选择。如 Web 业务强调高并发能力,主要要求高可用性,允许一定额度的错误,这样就可以放宽了一致性的限制。而在线支付系统则必须保证最终数据的正确性,所以对数据一致性有很高要求。

Laxcus 充分考虑到这些不同应用需求的特点,在原 CAP 理论基础上,进行了适当的调整和改进,提供了允许由用户定制和分配的 CAP 管理策略。这样,用户能够按照自己的业务需求,在 AP 和 CP 之间进行选择切换。这项功能实施后,极大提高了系统的灵活性,同时简化了用户在应用层面的设计。特别说明的是,可调 CAP 策略是一个多维度多粒度的管理策略,即使在一个账号下,用户也能够针对不同业务需求,实现任意数量的可调 CAP 策略。

可调 CA P策略是 Laxcus 大数据管理系统分布资源协同框架的主要组成部分。

去中心化的数据处理

在分布计算环境里,由于并行运行着大量的软硬件设备,而这些运行中的软硬件设备几乎都是不稳定的。在很多运行环境,很多时候,实际上往往就是一个小小的问题,就能引发了大面积的数据故障和网络瘫痪。这样就使得分散在多个节点中的数据处理,时刻处于一种不确定的状态。这种不确认性,是造成分布数据处理结果不一致、影响数据可靠性的主要原因。成为一直以来,分布计算领域的一个顽疾。

为了解决这个问题,在2.0版本中,我们创新性地设计和实现了“去中心化的数据处理”,使得这个影响分布计算领域发展多年的问题迎刃而解。

“去中心化的数据处理”的技术特点是:当没有主控节点参与,或者当其中任何一个设备、软件失效的情况下,其它节点依然能够通过自主调节的方式,来保证分布数据处理的正确性,从而避免数据不一致现象发生。在 Laxcus 体系里,“去中心化的数据处理”是对可调CAP策略和分布锁的补充,是分布资源协同框架的一部分。对用户而言,这项技术是透明的,可以完全忽略它的存在。

跨用户的数据操作

通常情况下,Laxcus 用户的数据处理工作是在自己的逻辑空间里进行。但是随着各领域开始普遍使用 Laxcus ,大数据处理工作日益丰富多样和复杂化,包括数据融合和交叉处理等现象的增加,使得单个用户内进行的数据处理已经不能满足业务需求,越来越多的数据业务需要在多个用户数据之间,执行能够相互关联和交换的数据操作。

基于这种需求的考量,Laxcus 大数据管理系统增加了一项新的功能:“跨用户的数据操作”。

跨用户的数据处理是一项数据授权管理方案,必须在系统的安全监管之下,在可信用户之间进行的工作。它首先由宿主用户发起,向授信用户发出邀请,通过可信授权的方式,向授信用户公开自己的数据资源,来实现数据资源共享。授信用户在确认获得宿主用户的授权后,必须按照宿主用户规定的授信规则,对共享资源进行权限范围内的数据操作。另外,共享资源公开后,宿主用户也可以随时关闭他的授信,恢复到双方授信之前的状态。

除了要求授信和撤销授信的工作是由宿主用户完成外,跨用户数据操作的其它工作都是由系统负责执行,对授信用户完全透明。这样在兼容授信用户即有数据处理方案,不必修改业务代码的同时,也扩大了授信用户的数据处理范围,简化和减少了授信用户在应用层面的开发工作量。在数据资源方面,由于跨用户的数据处理实现了多个用户之间的数据共享,天生具有节省数据存储空间和提高数据处理效率的作用。

数据计算算法

Laxcus 所有数据计算工作都是通过网络实施。相较于集中计算,在网络间进行的数据计算更适合处理那些数据量大、复杂的、耗时长的计算任务。能够实施网络计算的前提是数据可以被分割。其要旨就是把一组大的数据分成若干组小的元组。分割数据的办法有很多种,目前最常使用的办法是按照数值范围和散列规则进行分割。需要强调的是,在被分割后的数据里,不应该存在内容重叠的现象。

在这一章里,我们通过介绍数据分布计算算法,来说明 Laxcus 大数据管理系统的分布计算工作是如何实现的。

Diffuse/Converge

Diffuse/Converge 是我们设计的一套分布计算模型,与 Laxcus 大数据管理系统紧密结合,负责组织实施大规模数据计算工作。Diffuse/Converge 算法依据我们对数据处理的理解产生,在我们的数据处理概念中,传统的集中计算模型,数据处理可以分解为两个阶段:产生、计算,如果把它扩大到网络环境,可以进一步分解为:分散、聚合。它们的区别在于:前者是直接产生数据,然后对数据进行计算,输出计算结果;后者是通过网络收集数据,经过组织整理后,再分配给多台计算机去执行计算,最后输出计算结果。实际上,分布计算与集中计算相比,只是多出数据组织整理环节,其它部分基本是一样的,但是在数据处理能力上,Diffuse/Converge 算法可以驱动和计算的数据量远远超越集中计算所能提供的规模,足以满足当前各种大数据计算业务需要。

在 Laxcus 大数据管理系统里,Diffuse/Converge 算法已经被抽象为一个分布范式,用户需要调用系统提供的SDK,通过编程来实现实际的数据计算业务。

以下结合图14,阐述 Diffuse/Converge 算法的处理流程。

《从0开始,设计研发一个全功能通用大数据系统》

图14 Diffuse/Converge 处理流程

如图所示,Call 节点是 Diffuse/Converge 算法的起点,实际也是计算结果的输出点,它负责进行协调和分配数据资源,而不会产生数据和计算数据。每个分布任务都从 Diffuse 开始,它被指向 Data 节点。在这个阶段,Call 节点会同时发出多个 Diffuse 请求,分别作用到多个 Data 节点上。每个 Data 节点根据 Diffuse 请求中的参数,执行产生数据的工作,数据来源可以是磁盘,也可以按照某种规则生成。这些数据产生后,被抽象处理成元数据,返回给 Call 节点,成为后续计算的依据。

Converge 是分布计算第二阶段,它的作用点是 Work 节点。同 Diffuse 阶段一样,Call 节点也会向多个 Work 节点发出多个 Converge 请求,每个 Work 节点根据 Converge 请求中的参数,执行数据计算工作。与 Diffuse 不同的是,Converge 是一个迭代的过程,在一次数据计算中,允许有任意多次的 Converge 发生,直到最后一次 Converge 计算生成计算结果。在此之前,Converge 产生的都是元数据。

通过以上说明可以看到,Diffuse 只执行一次,Converge 会执行多次。这正是本处要特别说明的:Diffuse/Converge 算法的本质是阶段间串行、阶段内并行的工作方式,每个阶段完成后才能进入下一个阶段,当前阶段的数据输出是下一阶段的数据输入。阶段内的并行处理由线程执行,线程之间是无联系的独立计算。

数据计算过程中的数据平均分配问题

在 Diffuse/Converge 分布计算过程中,每个 Data/Work 节点产生和计算的数据量常常是不一致的。这个现象如果放在这样的环境下就很容易看出来:(1)集群的硬件配置完全一致;(2)集群里只有一个计算任务。当这样的条件成立且数据量分配不均时,将导致 Work 节点在计算数据时,发生计算时间长短不一的现象,大批先期完成的子计算任务被迫等待最后一个计算结果,徒然增加了总计算时间,出现木桶短板效应。这样的数据处理显然不符合我们追求的最大计算量、同时最小计算时间的要求,如果能够使每个节点的数据量趋于相同,大家在相同或者接近的时间内返回计算结果,那么短板效应就会消失,就可以获得最大的计算效费比。显然这样的分布计算才是最合理和有效率的。

平均分配数据量的工作由 Call 节点来负责。如上所述,在数据计算过程中,Data/Work 节点会向 Call 节点返回元数据,我们在设计这些元数据时,已经考虑到平均分配数据量问题,并因此设置了一些参数。显式的如被分割的数据尺寸,隐式的参数由用户来定义和解释。通过这些参数,Call 节点在计算时,可以给每个 Work 节点分配相同或者基本一致的数据量。这样,在理想的环境下,每个 Work 节点能够在相同或者接近的时间内返回计算结果,保证数据计算获得一个最佳的计算时间。

数据构建和算法

在大数据处理过程中,我们经常会遇到这样的情况:大多数时候,用户最初输入的数据会含有大量无意义的、杂乱的信息,需要经过提炼、收集、汇总等一系列手段,才能产生有意义和用户可识别的数据内容;当数据长时间使用后,因为删除、更新操作的缘故,会在磁盘上产生大量数据碎片,这些数据碎片影响到正常的数据读写,为此需要做定时的数据清理工作,来保证一个高效的数据存取环境;还有一些时候,出于使用便利和效率的考虑,我们需要把多个表的不同字段组合到一起,形成一个宽表,来方便我们分析调用,和清晰、直观地展示给客户;另外,我们还需要按照某些特定的规则生成一些临时的、或者公共的数据,保存到磁盘上,来减少数据计算环节,加快数据计算速度。

如果仔细分析这些数据处理业务,可以发现它们都有一个共同的特点:重复执行概率强,不应该在数据计算时发生,最好提前提供数据准备。

基于这样的业务需求,我们提出了“数据构建”的概念,由它来统一完成这些工作。

在 Laxcus 2.x版本,数据构建已经发展成一个独立的子系统,有一套完整的实现方法和处理流程。因为它在 Laxcus 大数据体系中的重要性,所以单独分出一章做介绍。

简单说明一下数据构建的特点:

  1. 系统提供一套 API 接口,用户需要结合自己的业务,编程实现。
  2. 必须遵守这样一个准则:在既有数据基础上才能产生新的数据。
  3. 与数据计算工作不一样的是,数据构建不直接向用户提供计算结果,只为提高数据计算效率而产生。
  4. 在分类方面,数据构建属于 ETL(Extract/Transform/Load)范畴,是数据计算的预处理措施和加速器,为数据计算提供快速处理通道。
  5. 按照我们对数据构建的细化,它被分成两种操作:数据优化和数据重组。数据优化只执行数据清理工作;数据重组是对旧数据的再组织和再计算,并且衍生进化出新的数据。

数据优化

数据优化被设计成 Laxcus 系统的一个命令,用于整理磁盘上的数据碎片,删除其中的垃圾数据。命令可以是用户通过终端输入,也可以把命令保存到到 Top 节点上,由Top节点定期执行。由于 Laxcus 2.0版本的事务加入,数据优化被定义为事务“写”操作,在执行过程中,全部数据块将处于“锁定”状态,不允许其它操作加入进来,直到全部完成被解锁。通常经过数据优化整理过的数据,它尺寸会更小,内聚更紧凑(这一点在列存储模型上尤其明显),有利于大批量的磁盘读写。数据优化只发生于 Data 主节点上,如前所述,每个数据块的执行时间大约是1.2秒左右。工作完成后,新的数据块会同步更新到备份节点上,替换旧的数据块。数据优化命令可以指定一个或者几个 Data 主节点,如果不指定,默认是集群上的全部 Data 主节点。鉴于数据优化过程中的“锁定”情况,建议把数据优化工作放在业务空闲时段,以减少因为数据锁定带来的负面影响。

数据重组

数据优化是由系统定义和执行的,只在一类节点上发生和并行执行,整理一个表的数据碎片。它的工作简单,执行速度快,存在时间短,是一种小规模的数据处理业务,对其它数据操作不构成太长时间的影响。数据重组则大不一样,根据我们的使用经验和跟踪调查,数据重组普遍会涉及到多个表、多种格式的数据计算和分析,数据量大,执行时间长,产生的数据量也大,而且结果也是多种多样,属于大规模的、复杂型数据处理工作。

鉴于这样的情况,系统无法做到对数据重组进行统一的处理,还有开发者任意编写数据重组代码可能导致的错误,以及希望减少用户工作量,规范处理流程等原因的考虑,我们针对数据重组设计了一套 Scan/Sift 算法,让用户按照规定流程和规定要求去参与数据重组工作,并以此起到简化编程工作、减少运行错误的作用,也希望能够达到提高处理效率和保证系统稳定性的目的。

另外,在我们内部,数据重组被称为“洗牌”,这也许可以更好地表达我们对“数据重组”的本来意思。

Scan/Sift 算法

Scan/Sift 是为大规模数据重组设计的算法,与 Laxcus 大数据管理系统紧密结合,能够在多个子域集群中工作,具有操作多个表数据、产生任意组数据的能力。

同 Diffuse/Converge 算法一样,Scan/Sift 算法的工作起点和输出点也是 Call 节点,Call 节点在 Scan/Sift 算法中起协调和分配数据资源的作用,但是不去产生数据和重组数据。Scan 被设计用来收集数据信息工作,它的作用点是 Data 主节点。主要是扫描磁盘上的数据索引,然后生成元数据,反馈给 Call 节点。Call 节点汇总 Scan 收集来的元数据,在本地进行分析和调整后,分配给 Build 节点。Build 节点执行 Sift 工作,它根据 Call 节点提供的信息,向 Data 主节点索取数据,然后放到本地磁盘上,通过各种手段重新组织后,产生新的数据,最后按照 Call 节点的要求,返回到指定的 Data 节点上。按照这样的流程走下来,就完成了一次 Scan/Sift 数据重组工作。

与 Diffuse/Converge 算法不一样的是,Sift 不是迭代的,它在 Call 节点指挥下只是执行一次。实际上,Scan/Sift 算法的大量工作都集中在 Sift 阶段。这个阶段的工作压力非常大,如果放在 Data 节点处理,会影响到 Data 节点的正常数据业务,所以需要把数据转移出来处理。这也是我们设计 Scan/Sift 算法和 Build 节点的主要原因之一。

与 Diffuse/Converge 算法一样,Scan/Sift 也被抽象为一个分布范式,用户需要调用系统提供的 SDK,通过编程来实现实际的数据构建业务。

Marshal/Educe 接口

所有数据重组的开始阶段(ETL Extract),都需要把数据从磁盘文件中提取出来,然后才能执行后续操作。根据我们的追踪调查,提取操作主要这样两种方式:

  1. 按照某种规则有选择地抓取;
  2. 把全部数据输出再逐一排查或者分析。

对于这样的两种情况,前者可以通过 SQL SELECT 语句做到,后一种我们实现了 Marshal/Educe 接口,来方便用户调用。

Marshal/Educe 是把磁盘下一个表的数据全部排序和输出的过程,由三个函数组成。Marshal 负责把全部数据按照指定列进行排序,排序结果是生成一组镜像表,这是一种元数据,被保存在内存里。Educe 是在 Marshal 之后的操作,它在镜像表的指引下,把数据从磁盘上抓取出来并输出。其中 Marshal 只操作一次,Educe 可以任意多个。如果需要中途停止操作,就调用 unmarshal 函数,内存中的镜像表也将同步释放。

Marshal/Educe 以“只读”方式进行,执行过程中不会修改磁盘上的数据内容,生成的镜像表数据量也很小,每个数据块只产生几十到几百字节的信息,所以它对系统性能影响不大,可以放心使用。

人机交互接口

为了简化用户与大数据集群之间的数据处理和管理过程,满足用户的简单、易用、高效等指标,我们定义了一套规范的人机交互模型。这套人机交互模型的构成是:以命令为中心,加上控制点和分布描述语言组成。当运行的时候,它们在松耦合架构内,做为一个离散的整体,来执行 Laxcus 大数据管理系统所有的数据处理和管理工作。

控制点

控制点是提供人机交互能力的节点。在 Laxcus 大数据管理系统里,提供人机交互的控制点共有四种,它们是:WATCH 节点,FRONT 驱动程序节点、FRONT 字符控制台节点、FRONT 图形终端节点。其中 WATCH 节点被管理员使用,提供监视集群运行和管理、调度集群业务的工作。其他三类被注册的普通用户使用,执行所属的数据处理和管理工作。

控制点在启动命令的同时,兼具检查和判断语法正确性的作用,并提供命令处理结果的显示。这种形态,使它们实际上成为所有业务处理工作的输入点和输出点。

分布描述语言

分布描述语言(Distributed Description Language)是一种专门针对 Laxcus 注册用户和集群管理者设计的类自然语句高阶交互语言。它采用英文语句的语法风格,由用户者通过入口设备输入,被语法解释器解释,转换成命令后,分发到集群上执行。分布描述语言始于 Laxcus 0.4版本,经过持续的完善,现在已经与 Laxcus 大数据管理系统高度集成,提供了全方位的管理、操纵集群能力,贯穿到集群的每一个环节。我们设计分布描述语言的目的在于简化用户的工作,希望达到“只需要操作人员通知集群做什么,而不需要去知道集群怎么做”目的,为 Laxcus 大数据管理系统简单、高效的处理提供基本保证。

以下我们对分布描述语言的基本面貌做些简单的介绍。

三层结构模型

分布描述语言是一个三层结构模型。命令从 Front 或者 Watch 节点发出,来自 Front 节点的命令属于用户命令,来自 Watch 节点的命令属于集群管理命令。无论是 Front 还是 Watch,它们的命令都需要经过语法解释器翻译成计算机命令,才能发往集群。用户命令在进入集群执行操作前,首先要接受网关节点(Aid、Call)的检查,在合法性,再结合语义解释,转发给后续相关节点,去执行数据处理和数据管理工作。Watch 节点因为位于集群内部,命令被翻译成计算机命令后,会直接发给与命令关联的节点去处理。

命令分类

如上所述,分布描述语言中的命令分为两大类:集群管理命令、用户命令。集群管理命令由管理员从 Watch 节点发出,用来控制、检查集群和节点的工作状态、分布资源。用户命令由用户从 Front 节点发出,主要是执行数据操纵和数据管理。因为分布描述语言兼容 SQL,SQL 中的所有命令被划入用户命令队列里。集群管理命令和用户命令在系统中是完全平行的,没有交集,也不允许互相使用。在权限等级上,所有集群管理命令都拥有比用户命令更高的操作权限。这体现在命令的被调用过程中,比如当两类命令同时出现在一个节点时,集群管理命令总是比用户命令优先获得执行的权力。不过在系统实际运行时,在集群中工作的基本都是用户命令,集群管理命令偶尔出现,而且也不会产生太多计算压力,所以这种优先权并不容易体现出来。

自定义参数

在过去几个版本的演进过程中,有越来越多的用户要求系统提供一种在命令中存在、不需要系统理解、由用户自行处理的数据。这些数据的表现上,有时候可能是一个数字,有时候是一个字符串,也可能是一张图片,或者其它经过格式化处理的信息。它们成为命令的一部分,参与到用户的数据处理工作中。

顺应这一项发展需求,同时也为了规范化数据样式,提高数据处理效率,在2.0版本中,分布描述语言正式支持自定义参数,并且对自定义参数做出这样的规定:参数格式由 Laxcus 提供,内容由用户自己解释。如图7.2.3所示,自定义参数被分解成三部分:名称、类型、数值。其中名称由用户自由定义,类型是系统规定,类型在名称之后,被括号包围。类型分为数字型和数组型两组。数字类型包括bool、short、int、long、ushort、uint、ulong、float、double,数组类型包括string(char)、byte、image、object。为保证传输过程时的内码一致,用户输入的 string 数值会被转为UTF8编码。如果自定义参数是一个数组类型,那么数值需要被单括号包围,如果自定义是数字类型则不需要。这种样式的自定义参数被语法解释器解释后,将存入到命令的自定义参数队列,随命令一起分发到集群上,在需要它发挥作用的位置参与数据处理工作。

命令驱动的分布执行模式

命令由分布描述语言转义而来,做为 Laxcus 大数据管理系统的中介媒质存在。命令执行的时候,根据各自的语义,结合所属环境状态进行解释。并以异步的方式,分散到集群的不同节点上,执行各种数据处理和管理工作。在表现形式上,命令通过网络在各节点之间传递,形成一条前后关联的命令链。执行过程中,每个命令链都是独立的,严格按照预定的工作轨迹运行。当它们存在于计算机内部的时候,实质是一个个对内存占用很小的“程序片段”,而命令链之间处于完全隔离的状态。这种“被隔离”和内存占用小的特点使它们之间没有干扰,同时又允许大量存在,即使某一条命令链在运行过程中发生故障,产生的影响也只限于这个命令链本身,不会出现波及效应。并且这种方式对排查故障原因和故障源头十分方便。尤其重要的是,因为命令链的独立性,在编写代码的时候,每条命令链可以按照其自身的需求,被设计得非常细致和有针对性。这些特点,使它在保证系统稳定运行的过程中,起到重要的作用。

系统层应用开发

在 Laxcus 2.2版本之前,所有集群管理命令,都是由系统定义,被系统或者管理员来实施使用的。随着 Laxcus 大数据管理系统的普及和发展,有越来越多的管理业务不在系统核心需求之内,但是对于集群管理员又迫切需要,且必须在系统核心内部运行和使用的。这样就促使我们设计一套公共管理方案,来支持这些私有业务在集群里运行。于是,框架任务组件编程方案便应运而生。

从系统角度来看,框架任务组件编程接口仍然建立在松耦合架构基础上,以中间件的形态存在,遵循 Invoke/Produce 规范。用户需要在此基础上,通过编程定义自己的私有命令,和编写配置脚本,确定它们在 Laxcus 大数据管理系统中的分布关联。在运行前,系统管理员需要把程序包部署到系统指定的目录下,让节点能够找到它们并加载到运行环境里。运行过程中,节点将根据配置脚本,检查这些私有命令和业务模块,建立动态匹配关系,与系统的内置命令一起,统一交给系统管理和运行。

框架任务组件是可以在系统运行中热发布的,任何节点上的更新变换,都同步触发运行节点重新加载它们。框架任务组件本身开发难度不大,但是因为是从系统底层派生而来,需要开发者理解和熟悉 Invoke/Produce 运行机理和各个节点的工作范围,才能保证有效开发工作。以下将接合框架任务组件API接口,做一些相关的基础介绍。

框架任务组件编程接口

“CustomCommand”是自定义命令,这是一个 Java 类,继承系统的 Command 命令。它本身不提供任何实际的函数方法,完全由用户来设计提供。

“CustomInvoker”是自定义调用器,这是一个 Java 类,它继承自 EchoInvoker 类,是框架任务组件基础入口。用户需要在构造方法中指定一个自定义命令,和它形成关联。运行过程中,自定义调用器将使用关联的自定义命令,来处理系统层业务。通过自定义资源代理,辅助获得系统层的各种资源,为业务处理工作提供数据判断和辅助支持。

“CustomTrustor”自定义资源代理,这是一个 Java 接口声明,定义了两个基本方法,包括本地节点地址和注册服务器地址。如果用户有更多,可以派生声明。并在自己的业务中实现它们。

编写配置脚本

配置脚本的工作是把自定义命令、自定义调用器、命令/调用器生成器、命令语法配置文件,用 XML 标注的方法连接起来,其中命令语法配置文件是非必要选项,如果用户提供,在图形窗口中输入命令时,命令关键字将被高亮显示。自定义命令和自定义调用器成对出现,每一个自定义调用器,在不同的节点对应不同的调用器。调用器将结合所在节点的工作特点,执行不同的处理工作。

初始化加载工作则由另一个配置完成。这个配置块在每个节点的“conf/local.xml”文件中固定指定。“auto-update”标签决定节点发现 JAR 包更新后,是否自动加载(重新热发布)。“directory”指定存放自定义 JAR 包的所在磁盘目录。“statement”是自定义配置声明文件。

用户层应用开发

Laxcus 大数据管理系统的所有用户级数据业务都是通过“分布任务组件”实现。分布任务组件是我们借鉴中间件设计理念,融合网络通信、分布计算技术发展而来,以接口的形式提供给开发者。是连接用户业务和大数据集群之间的桥梁。

与 Laxcus 大数据管理系统其他子系统一样,分布任务组件也经历了数次升级发展过程,目前最新版本的特点是:

  1. 从原来的框架下剥离出来,发展成为一个完整的子系统,拥有独立的运行框架和操作规范,实现了全方位的数据处理和管理服务。
  2. 随集群节点规模同步扩充,可以提供近乎无限的数据处理能力。这足以满足我们当前以及未来相当长一段时间内,执行各种大规模数据处理业务的需要。
  3. 新版本中,集群管理员负责的工作省略掉,被交给系统来检测和处理,自动化管理能力大幅提高。
  4. 细化为数据计算组件和数据构建组件两种。部署位置分为内部和外部。内部组件在集群内部运行,执行主要的分布处理工作;外部组件属于客户端组件,只在 Front 节点运行,负责反馈和显示内部处理结果。

从开发者角度看,新版本的分布任务组件是简单的,他们可以不必再去考虑与分布环境有关的诸多操作,只需要将工作精力集中到业务模块开发上,调用几个有限的API接口,就可以开发出符合要求的分布任务组件。其类似于一个数据库应用开发过程,这使得任何具有Java语言开发能力的人都可以掌握它。

为管理分布任务组件,我们还设计了一套容器,兼具沙箱功能,来实施分布任务组件的自动部署和运行,并提供冷/热两种发布能力。在 Laxcus 大数据管理系统里,容器主要执行以下工作:

  1. 在发布前,检查分布任务组件的安全许可。
  2. 分配和回收分布任务组件使用的系统资源。
  3. 在分布任务组件运行中,对分布任务组件进行安全追踪和监测,防止来自分布任务组件的恶意操作。在这一章里,我们将着力介绍与分布任务组件有关的基本知识,以及如何通过调用分布任务组件的API接口来实现分布式编程,和执行分布式计算的。

阶段命名

我们在第一节提到过“命名”的概念,它是对实体资源的抽象化表述。阶段命名是命名中的一种。它是在命名的基础上,结合进分布处理的“步骤”,加上用户签名引申而来,用于描述运行中的分布任务组件,当时所处的位置和状态。“step”用来说明当前分布组件的操作步骤,“root”是根命名,每个根命名需要保证全局唯一。判断根命名唯一性的工作可以联系系统管理员,或者直接让管理员提供。“sub”是子命名,用于判断迭代化的数据处理,需要在所属命名队列中唯一。“issuer”是 SHA1 算法格式的用户签名,是每个用户登录时的数字指纹,具有唯一性。它用于分布环境下的安全判断和校验。

阶段命名是分布任务组件在 Laxcus 集群里部署、运行的唯一身份标识,数据计算和数据构建都要用到它。

数据计算组件

数据计算组件建立在 Diffuse/Converge 算法上,它的对应命令是 Conduct。一个完整的数据计算组件由5个阶段组成,每个阶段对应一个独立的子组件。数据计算各阶段的工作内容和处理范围,系统都做了明确的规定。Call 节点处于中心位置,负责调配分布资源,和控制数据处理流程。

Init 阶段

Init 阶段执行数据计算的初始化工作,按照 Conduct 命令中提供的参数和要求,为后续工作检查分布数据资源,调配运行参数。产生的计算结果,将成为后续数据计算的参考依据,被保存在 Conduct 命令中。Init 阶段组件属于内部组件,指定部署到 Call 节点。

From 阶段

From 阶段对应 Diffuse/Converge 算法中的 Diffuse。在这个阶段,将产生数据计算的初始数据,提供给后续To阶段使用。对整个数据计算流程而言,From 阶段产生的数据属于中间数据。这些数据来源有三种:1. 使用 SQL Select 语句产生;2.根据用户自定义参数,加上本地数据资源,由用户自解释规则生成;3. SQL Select 语句和用户自定义参数结合产生。无论哪一种情况,这些原始数据都会保存在硬盘或者内存上(默认保存到硬盘,保存到内存需要开发者指定,同是视运行环境许可而定),然后产生数据位图返回给 Call 节点。数据位图是 Laxcus 大数据管理系统针对分布计算设计的一种元数据,根据不同需求有不同的样式,目前已经实现接口化处理。用户在分布计算过程中,可以在此基础加入新的元素,实现数据位图的用户自定义自解释。From 阶段组件属于内部组件,指定部署到 Data 节点。

To 阶段

To 阶段对应 Diffuse/Converge 算法中的 Converge。在这个阶段,将执行实际的数据计算工作。根据上述对 Converge 介绍,To 阶段是迭代的,要求发生最少一次,最多不限。To 阶段迭代次数由开发者指定,被写入 Conduct 命令,由 Init 阶段做初始化校验,由 Balance 阶段解释和分配。如果是多次迭代,在使用 Conduct 语句描述子级 To 阶段时,要使用“SubTo”语句。To 阶段最初所需计算数据,来源于 From 阶段,此后的计算结果,将供下一级 SubTo 阶段使用,直到全部完成。在完成最后的计算工作前,To/SubTo 将向 Balance 阶段返回数据位图,供 Balance 阶段分析判断,为下一次 SubTo 阶段提供分布计算依据。To 阶段组件属于内部组件,指定部署到 Work 节点。

Balance 阶段

Balance 阶段介于 From/To/SubTo 阶段之间。它将根据这些阶段返回的数据位图,进行分析整理后,为后续的 To/SubTo 阶段调配分散在 Data/Work 节点上的数据资源,使每一个 To/SubTo 任务尽可能获得相同的计算量,以尽可能相同的计算时间返回计算结果,达到节省总计算时间、提高计算效率的目的。对于数据位图,如果它是系统生成,那么在 Balance 阶段,解释工作也是由系统处理;如果用户使用自定义规则生成,那么 Balance 阶段也是由用户自己解释和分配。Balance 阶段组件属于内部组件,指定部署在 Call 节点。

Put 阶段

Put 阶段承接最后一次的 To/SubTo 阶段计算工作,是对上述数据处理结果的最终输出。这些输出通常是以计算机屏幕和磁盘为目标,把数据存入磁盘,或者以文字、图形的方式显示在计算机屏幕上。Put 阶段组件功能要求简单,属于外部组件,由用户部署在自己的 Front 节点上。

数据构建组件

数据构建组件建立在 Scan/Sift 算法上,它的对应命令是 Establish。一个完整的数据构建组件由6个阶段组成,和数据计算一样,每个阶段只执行一项规定工作,6个阶段衔接,形成一个完整的数据构建流程。数据构建的每次处理输出,都是下一个阶段的处理输入。Call 节点仍然处于中心位置,负责调配数据构建产生的分布资源和控制数据处理流程。

Issue 阶段

Issue 阶段与 Conduct.Init 阶段有极大相似性,也是提供数据处理前的准备工作。这包括对 Establish 命令中的全部参数进行检查,为后续阶段检查和调配数据资源。如果指定的参数中存在错误,或者数据资源不满足要求,它将拒绝执行,并向用户返回错误报告。Issue 阶段组件属于内部组件,指定部署在 Call 节点。

Scan 阶段

Scan 阶段执行数据扫描工作,它只发生在 Data 主节点,检查数据块的索引信息。因为只扫描数据块的索引,所以这个速度是非常快的。在 Laxcus 大数据管理系统里,现在已经有一个标准化的 Scan 阶段组件接口,如果没有特殊需要,开发者只需要调用这个接口就可以了。如果有个性化需求时,也可以在这个接口基础上进行再实现。Scan 阶段工作完成后,会向 Call 节点返回一个数据位图,里面包含了下个阶段需要的各种信息。Scan 阶段组件属于内部组件,指定部署在 Data 节点。

Sift 阶段

Sift 阶段是数据构建最重要的部分,所有数据构建的实质性工作都在 Sift 阶段执行和完成,是数据构建的核心阶段。在实际应用中,因为数据构建有太多的差异,所以系统提供的 Sift 阶段接口也是宽范的。系统负责完成的只有从 Data 主节点下载数据块一项工作,剩下的工作,开发者可以在安全许可范围内,在 Sift 接口里执行各种数据操作。当 Sift 阶段工作完成后,它将产生新的数据块,这些数据块将生成一个固定格式的数据位图,并返回给Call节点的Assign阶段处理。与 Conduct.To 阶段类似,Sift 阶段也允许迭代,迭代操作在Assign阶段控制下执行。 Sift 阶段组件属于内部组件,指定部署在Build节点。

Rise 阶段

Rise阶段工作承接最后一次 Sift 阶段,并经过Assign阶段的重组,按照 Sift 提供的数据位图,找到指定的 Build 节点和数据块,执行下载。当下载完成后,这些数据块将被分发给关联的 Data 从节点。因为Rise阶段的工作内容是相对固定的,所以象Scan阶段一样,系统也提供了一个标准化接口,开发者只需要调用这个接口,把工作提交给系统处理就可以。Rise阶段完成后,也将返回一个数据位图,数据位图可以是系统默认生成或者用户自定义组织。Rise阶段组件属于内部组件,指定部署在 Data 主节点。

Assign 阶段

Assign阶段介于 Scan/Sift/Rise 三个阶段之间,调配 Scan/Sift 阶段产生的数据位图后,推送给下个阶段。它首先承接 Scan 阶段,重组分配给 Sift 阶段。由于 Sift 阶段是迭代的,Assign阶段也将做对应处理,直到Rise阶段。在这些过程中,Assign将根据 Data/Build节点的资源状况,以平均分配原则为基础,通过综合比较,对数据位图进行有选择的调整。Assign阶段工作和Conduct.Balance有部分相似之处,都要考虑下一阶段的数据平衡问题。Assign阶段组件属于内部组件,指定部署在Call节点。

End 阶段

End 阶段承接 Rise 阶段,是数据构建的最后一个环节。它的工作内容与 Conduct.Put 阶段类似,显示数据构建的最终处理结果。由于数据构建工作远比数据计算简单得多,输出内容也有章可循,通常只是提示重构信息,所以 End 阶段不需要开发者做太多处理,交给系统的标准化接口输出即可。End 阶段组件属于外部组件,指定部署在 Front 节点上。

数据计算编程接口

数据计算编程接口是数据计算组件的技术实现。接口设计遵循数据计算流程,命名格式与数据计算规范对应。API 由三个模块组成,分别是:

  1. 开发者接口。这是一组定义了数据计算规则和可操作范围的分布任务组件抽象类,对应数据计算的每个阶段,包含需要开发者实现的抽象方法。类名以“阶段名称”+“Task”格式出现,包括“InitTask、FromTask、ToTask、BalanceTask、PutTask”五种。开发者在编写分布应用时,需要从这五个抽象类派生,将私有业务逻辑和这些抽象方法结合,来实现它们。当数据计算组件运行时,这些抽象方法将被系统调用。对于这些抽象方法的操作范围和执行内容,系统有明确的规定,开发者必须遵守这些准则。这也是整个数据计算规则体系中,唯一需要开发者参与的工作。
  2. 本地资源接口。以 Java 语法的“interface”存在,由系统实现,供开发者使用。本地资源接口向数据计算组件提供计算工作所需的各种数据,是数据计算组件分析、判断、组织本地计算的依据。这些接口以“工作性质或者阶段名称”+“Trustor”格式出现,包括:“MetaTrustor、FromTrustor、ToTrustor、PutTrustor”四种,分别提供给“InitTask/BalanceTask”、“FromTask”,“ToTask”,“PutTask”使用。
  3. 远程资源接口。以Java语法的“interface”存在,由系统实现,供开发者使用。远程资源接口向数据计算组件提供其他节点的数据资源,是数据计算组件协调、整合集群数据的依据。它们以“阶段名称”+“Seeker”格式出现,包括“FromSeeker、ToSeeker”两种,提供给“InitTask/BalanceTask”使用。因为开发者接口是用户唯一需要实现的类,以下将对它们的抽象方法做概要介绍。
Init 抽象方法

Init 阶段只有一个抽象方法,方法名是“init”。这个方法是数据计算流程第一步,它需要用户解释和判断 Conduct 命令中的参数,包括对 From/To 阶段工作做一个大致的范围判断,和根据 From/To 分布资源,生成供 From 阶段计算的分布资源,并将这些结果写入到 Conduct 命令,输出给系统。系统将根据这些参数,去分配和建立 From 阶段连接,执行 From 阶段的数据计算工作。

From 抽象方法

From 阶段有三个抽象方法,起主要作用的是“divide”方法,这是一个数据分割操作。分割工作由用户自己定义和执行。分割后的数据将暂存在本地,这个位置可以是磁盘或者内存,由用户决定,返回参数是数据位图的字节数组长度。“effuse”把被分割数据的数据位图输出,“flushTo”则是把数据位图写入到磁盘文件。如果数据位图是输出到磁盘,在沙箱配置里,要打开这个文件写入权限。

To 抽象方法

由于 To 阶段工作相对复杂,出于简化开发者工作和精确处理目标的考量,我们把To阶段的任务分布两个部分:“生成(GENERATE)”和“计算(EVALUATE)”。“生成”完成类似 From 的操作,它以远程通信的方式,从其他节点获得数据和进行数据分割。“计算”处理分割后的数据。直到完成最后一次迭代前,它们每次输出的数据结果都是数据位图。

相应的,To 抽象方法为三组:基类 ToTask 提供两个方法:”effuse“和”flushTo“。“effuse”输出数据位图或者实体数据,”flushTo“是把数据位图或者实体数据写入到磁盘。ToGenerateTask 继承 ToTask,提供一个“divide”,这个方法从其他节点获得数据和分割数据。ToEvaluateTask 继承 ToTask,有两个“evaluate”方法,系统将根据数据位图,从其他节点获得分割数据后,交给 evaluate 方法执行数据计算工作。

Balance 抽象方法

Balance 阶段有两个同名抽象方法:“dispense”。系统要求两个方法能够根据上次 From/To 阶段反馈的数据位图,加上本次 To 阶段需求,重组数据位图,产生系统需要的分布资源。在这些分布资源里,有 Work 节点的具体地址,并将重组后的数据位图发给 Work 节点,以指示 To 阶段需要执行的工作。

Put 抽象方法

Put 阶段的抽象方法是:“display”。这个方法的工作非常明确:保存、解释、显示数据计算结果。因为 Put 阶段组件部署在 Front 节点,系统默认取消沙箱控制,用户拥有绝对的管理权限,可以执行任意操作。所以这个抽象方法是开放的,没有任何限制设施。

数据构建编程接口

数据构建编程接口是数据构建组件的技术实现。虽然数据构建和数据计算的业务性质不同,但是出于简化开发者工作的需要,在接口设计上,数据构建编程与数据计算保持高度一致。所以开发者在熟悉数据计算后,很容易理解和接受数据构建接口规范。这包括:

  1. 开发者接口。是定义数据构建规则和操作范围的分布任务组件抽象类,对应数据构建每个阶段,有需要开发者实现的抽象方法。类名仍然是以“阶段名称”+“Task”格式出现,包括“IssueTask、ScanTask、SiftTask、RiseTask、AssignTask、EndTask”六种。开发者的分布应用从这六个类派生,并和私有业务连接起来,实现这些抽象方法。数据构建组件运行时,系统将调用这些抽象方法。与数据计算一样,这些抽象方法也有它们的操作范围和工作内容,需要开发者遵守。
  2. 本地资源接口。以Java语法的“interface”存在,由系统实现,供开发者使用。本地资源接口向数据构建组件提供数据构建工作所需参数,以此来组织数据构建工作。这些接口继续以“工作性质或者阶段名称”+“Trustor”格式出现,包括“MetaTrustor、ScanTrustor、SiftTrustor、RiseTrustor、EndTrustor”,分别供“IssueTask/AssignTask、ScanTask、SiftTask、RiseTask、EndTask”使用。
  3. 远程代理接口。以Java语法的“interface”存在,由系统实现,供开发者使用。远程资源接口向数据构建组件提供数据块的分布状况,以此来组织数据构建工作,重新调整数据块的分布状态。它们以“阶段名称”+“Seeker”格式出现,包括“ScanSeeker、SiftSeeker”,被“IssueTask、AssignTask”使用。以下将继续通过介绍开发者接口的抽象方法,来阐述数据构建的实现过程。
Issue 抽象方法

Issue阶段抽象方法是:“create”。这个方法检查和建立起数据构建后续阶段的基本参数,以及为 Scan 阶段建立运行资源,并将这些参数结果写入Establish命令,输出给系统。系统根据这些参数,建立与 Scan 阶段的连接,执行 Scan 阶段的数据构建工作。

Scan 抽象方法

Scan 阶段有两个同名方法:“analyse”。它的工作是分析和提取出指定数据表下面的数据块元信息,并生成数据位图输出。 Scan 是一个可以标准化处理的阶段,如果开发者没有特殊需求,可以调用ScanTask中的“defaultScan”方法,由系统分析和输出数据位图。

Sift 抽象方法

Sift 阶段的两个同名方法是:“implement”。这个阶段执行数据重组工作。系统将根据数据位图提供的元信息,分别从不同的Data主节点下载数据,然后交给“implement”方法处理。重组规则由开发者实现,重组后的数据块暂存在本地,然后将输出重组后的数据位图反馈给系统。

Rise 抽象方法

Rise 阶段的同名方法是:“convert”。这个阶段执行数据转换工作,包括从 Build 节点下载数据块,追加新块,覆盖和删除本地旧的数据块。转换工作完成后,将返回包含转换结果的数据位图给系统。

Assign 抽象方法

Assign 阶段有三组抽象方法,分别针对“Scan、Sift、Rise”三个阶段,执行数据位图的重组和分配工作。其中“scan”方法针对 Scan 阶段,它收集 Scan 阶段返回的数据位图,提供给 Sift 阶段。“sift”针对Sift阶段迭代过程,重组本次产生的数据位图,提供给下一次 Sift 阶段。“rise”针对 Rise 阶段,它收集 Sift 最后一次数据位图结果,重组推送给Rise阶段。

End 抽象方法

End 阶段的抽象方法是:”display“,这个方法显示数据构建的处理结果。实际上,由于数据构建工作比数据计算简单很多,输出结果也趋于一致,系统提供一个“defaultDisplay”方法,来显示标准的数据构建结果。和Put阶段一样,End 阶段也部署在 Front 节点,系统屏蔽了沙箱限制,开发者可以在这个方法里执行任何数据操作。

打包

一个项目的编程开发工作完成后,接下来的工作就是打包。打包是把已经编译好的 Java 类文件放在一个文件里,方便系统管理和执行。打包操作可以使用 Java 运行环境提供的 jar 命令,或者 Eclipse 集成的 ant 工具来完成,这个过程和一般的 Java 打包操作完全一样。不一样的是, Laxcus 要求打包后的分布任务组件文件名后缀是“.dtc”,Archive 节点需要根据这个后缀名来判断是分布任务组件。另外,在每个分布任务组件包里,必须提供一个”tasks.xml”文件。这是一个 XML 格式的配置文件,放在文件包根目录的”TASK-INF”目录下面。它指定一个分布任务组件包中,所有需要提供给系统识别和处理的数据。Archive 节点将根据这个文件中提供的参数,把每个分布任务组件推送到关联节点下面。这是一个很重要的文件,所有参数的格式,系统都有明确规定,不允许出现任何错误。

分布计算过程中的数据分区

无论是数据计算还是数据构建,它们本质都是分布处理。都存在着在计算中间数据过程中,如何把一大块数据分割成多个小块数据的问题。按照数据的不同特性建立对应的分割规则,就是“数据分区”要做的工作。

数据分区一般首先按照后续的节点数目划分。这样当把一块数据分割后,后续每一个节点都能得到其中一小块数据。更多时候要考虑到数据属性,按照数据属性进行分割。比如执行带 order by、group by 子句的 select 检索时,就要根据排列、分组的数据类型,把数据划到不同的类别中。还有一些个性化的数据分割需求,因为系统无法实现统一处理,就设计了一套自定义分区规则的API接口,让程序去自主实现。

目前 From/To、Scan 阶段的分布任务组件都提供了默认的分割数据处理。

自定义分区规则和码位计算器

在很多的数据处理过程中,即使同样的数据类型,在不同应用场景下,也会具有不一样的数据含义。相应的,它们的数据分区也需要区别对待和另外处理。这就是我们设计和制定自定义分区规则的原因。

自定义分区以中间件的形式提供给开发者,在 Laxcus 语义定义中,它被称为“码位计算器”。如图9.8.1所示,码位计算器的核心是“CodeScaler”接口,由开发者去编码实现。其中的“seek”方法,将根据传入的对象,计算出一个数值。通过这个数值,系统将确定一个数据对象在分区集合中的下标位置,并且依此完成后续数据对象的分组、派发等一系列工作。

与分布任务组件一样,码位计算器也需要一个配置文件,这个配置文件标明码位计算器在运行时需要的全部参数,在经过编译、打包和发布后,将部署到集群的相关节点上运行。与分布任务组件不同的是,每个码位计算器的命名只需要保证在本次配置中唯一即可。这个特点使它比分布任务组件简单很多。

分布计算的数据平衡问题

在分区基础上,如果让数据计算实现时间最短、计算效率最大化,还需要考虑平衡分布数据问题。

事实上,为了实现数据平衡处理,在分区时就已经准备了平衡处理参数。在分布执行过程中,数据计算的数据平衡工作由 Balance 阶段负责,数据构建的数据平衡工作由 Assign 阶段负责。理想条件下,当不考虑计算机性能的时候,简单的数据平衡可以按照数据长度来处理,这个参数目前已经在数据位图中提供。理论上,两组内容、长度相同的数据,在两台硬件配置相同的计算机上,它们的执行时间是一样的。在比较复杂的时候,就需要考虑数据类型和处理内容等因素。比如加减计算肯定比乘除要快,整数计算肯定比浮点数计算要快,多媒体的音频、视频数据肯定比文本数据计算密度大等影响。和分区一样,更多复杂的、个性化的数据平衡计算工作需要开发者来处理,系统也已经提供了API接口。

分布计算的内存模式

分布任务组件运行过程中,会产生大量的中间数据。在默认条件下,这些中间数据会被系统保存到硬盘上,并在工作结束后被系统释放。我们此前已经多次提过,由于磁盘的读写效率很低,虽然系统对此做了很多优化处理,但是仍然无法满足用户快速处理需求。所以,为了加快分布处理速度,必须把数据缓存到内存里。与之配套的,我们在系统命令提供这样一个方法,由用户决定把中间数据保存到内存还是硬盘。这项功能要求用户在生成命令时显式指定,当分布任务组件运行时,系统将在内存资源许可的情况下,把中间数据缓存到内存。理想状态下,如果一个分布处理流程都能够以内存作为存取目标,那么数据处理将完全跳过硬盘这道瓶颈,使这次分布计算成为纯粹的流式处理,处理效率将获得数十倍的提升。这种的数据快速处理方案,是很多时间敏感型的数据业务迫切需要的。

特别说明的是,用户只需要在运行分布任务时,显示指定驱动命令为内存模式,后续分布任务组件的所有数据存取工作,都将由系统按照用户的要求完成,开发者不需要为此编写任何代码或者做任何设置。

发布

打包工作完成后,接下来就要执行分布任务组件的发布工作。为了不影响集群正常运行,在将分布任务组件正式提交到集群之前,我们提供了一个测试工具,供开发者检查自己的分布任务组件。由于只是测试工具,不具备运营环境所拥有的各种资源,所以这个测试工具,只对分布任务组件的格式、配置、运行参数进行检查。当这些都确认正确后,就可以提交给集群了。另外,用户也可以自己搭建一个模拟环境,通过正常的发布流程来检查分布任务组件。

Laxcus 大数据管理系统支持“热发布”,分布任务组件在进入集群的几分钟内,经过一系列的识别和校验,就可以生效。它首先会被投递到Archive节点,Archive 节点将根据“tasks.xml”文件中提供的配置参数,对分布任务组件进行一系列的检查,在确认无误后,分发给关联节点。如果在检查过程中发现错误,Archive 节点将拒绝分发,并把分布任务组件和发布过程中出现的错误反馈给 Watch 节点,再由管理员去联系用户。为避免热发布过程中发生分布任务组件版本冲突,用户在发布前和发布过程中,应该停止一切分布计算工作,直到发布过程完全结束。

分布任务组件投递到 Archive 节点的工作,有两种操作方式:一种是用户将分布任务组件交给集群管理员,让他通过 Watch 节点代为发布;另一种是用户通过 Web 发布接口,跳过集群管理员,让 Web 程序直接投递到 Archive 节点下面。Web 发布接口管理权由集群管理员掌握,用户跳过集群管理员发布分布任务组件对系统具有一定风险性。至于集群管理员是否愿意开放Web接口,并承担因此带来的安全风险,就是集群管理员自己决定了。

系统冗余容错

由于 Laxcus 大数据管理系统建立在低成本硬件基础之上,以及硬件品质的参差不齐,和计算机集群庞大的组织体系和复杂结构的特点,使得集群在运行过程中发生的错误概率,远高于单一且性能稳定的小型机服务器,并且集群在运行过程中几乎是不允许停止的,这就更需要提供比单机环境复杂得多的错误管理方案。实际上,我们在产品设计、开发、运营的各个阶段,有相当大一部分精力,都是用来获取各种故障,和解决各种故障发生后的错误处理问题。对于这些错误处理,我们依据系统的松耦合架构和自适应感知机制,遵循这样一个整体思路来解决:首先由软件感知来发现和定位故障点,然后进行判断,如果属于软件可以解决的故障,且有足够的冗余备份,那么启动软件自修复机制来完成,否则,这个错误就提交给集群管理员人工处理。按照这样的两条错误处理基线,我们把各种错误处理分别融入到它们的模块中,并与这些模块嵌合,形成一个完整的冗余容错管理机制。下面我们将从硬件和软件两个角度,来阐述 Laxcus 会面对的一些主要故障以及处理这些故障的办法。

硬件的容错

在 Laxcus 集群错误管理中,我们把运行环境或者硬件本身问题所造成、且不能通过软件自行修复来解决的错误,统一称为硬件错误。硬件错误的处理工作由集群管理员来完成,软件在这里起发现和报警的作用。根据我们过往的一些经验,本节就介绍一些经常发生的硬件故障和软件感知它们的办法。

网络故障

目前的网络故障由以下硬件部件造成:交换机、路由器、集线器、网线、接线头、网卡。在这些故障中,其中一部分是可以人工方式修复的,比如接线头松动、网卡接触不良等。另一部分属于硬件损坏,需要关闭设备更换。软件发现这些故障的办法也很简单,主要是通过网络握手来侦测发现,比如在软件里集成 ICMP 这样的功能,在运行时去追踪节点,发现可疑现象后,通过在本网段和外网段之间对比排查,可以很快判断和定位故障点。这类故障检查工作一般由管理节点来执行,其它类型的节点如果在运行过程中发现问题或者故障,也会主动提交给管理节点,供管理节点做进一步检查核对。

计算机故障

计算机故障是由计算机内部部件失效引发的错误,这部件包括了主板、芯片、内存、网卡、硬盘、电源。根据我们过往的使用经验,大部分计算机故障是由主板和硬盘导致,其中主板又占了相当大部分。计算机故障通过内、外两种手段来检查发现。在内部,由节点自检机制来探测部件,在外部,由管理节点来追踪节点。无论谁先检测得到,软件感知之后,都会马上提交给管理员处理。

硬盘故障

硬盘故障有三种情况:硬盘完全损坏(通常是引导区损坏导致)、扇区损坏、磁盘空间已满。第一种情况通常在计算机启动时发生,对于这种故障,最好的解决办法是管理员在开机时跟踪一下计算机的运行情况。第二种故障通常是节点读写数据过程中产生,这种情况软件通过故障实时感知能够马上发现,会立即报告给管理员。第三种情况由写入数据太多溢出导致,不是硬盘本身问题,这种情况也会被节点马上捕捉到,然后去通知管理员。

节点的冗余容错

本节点所说的“节点”,包含了软件的”进程“和硬件的”计算机“两个概念。这和之前所提略有不同,请诸位注意一下。在早期版本中,节点故障更多是软件故障造成的,比如节点的运行管理机制处理不善,模块间的API接口协同、衔接的错误。这些问题都与详细设计和编程有很大关系,随着版本演进,现在越来越多的情况是硬件问题导致。在 Laxcus 集群里,由于Front节点归用户使用,而且功能简单,实质只是一个用于输入输出的显示终端,所以本节忽略它,将主要介绍集群管理员管理下的节点冗余容错。

管理节点的冗余容错

前面已经提到过,无论是主域集群还是子域集群,都只能有一个Master管理节点来负责所属集群的管理工作,它在自己集群里的地位是独一无二的,是保证整个集群正常运行的关键。同时,为保证集群不会因为 Master 节点故障造成集群的管理混乱,通常还有一至数个 Monitor 管理节点做为备份存在着,它们将监视 Master 节点运行。

在我们的测试环境,有1个 Master 节点和2个 Monitor 节点。为检查管理节点容错能力,我们进行了这样的试验。我们使用 Linux kill命令杀掉一个 Master 节点进程,在第5秒钟的时候,其中一个 Monitor 节点感知到Master节点发生了故障,并且立即启动故障协商机制,询问另一个 Monitor 节点,它对Master节点的判断,双方很快共同确认了Master节点发生了故障。然后,它们按照自己的网络地址排序,选择数字最大的那个 Monitor 节点,成为新的Master节点。新Master节点立即将自己从 Monitor 状态转入Master状态,并且通知原来所有下属节点(包括另一个 Monitor 节点),让它们重新注册到新Master节点下面,同时将故障的Master节点和切换过程通知给Watch节点。整个容错处理在20秒内完成。

Data 节点的冗余容错

Data 节点保存着集群的全部数据,它的重要性仅次于管理节点,所以 Data 节点的冗余容错管理也与其它节点大不相同。上面已经介绍过,每个节点宕机都会被管理节点及时捕捉到。在 Data 节点宕机后,管理节点会在报警的同时,对 Data 节点的数据做出如下处理:取出这个 Data 节点的数据块编号,按照数据块编号,找到同源备份,产生一个新的备份到其它节点上,如果是 Data 主节点,其它从节点备份会恢复到一个新的主节点上,并且这些从块也升级成主块。如果是 Data 从节点,这些备份会从主节点产生备份,分发到其它从节点上。由于 Data 主节点的数据量一般都比较大(最多时候有几个TB),又要保证不能太过于占用网络带宽,实际上这个恢复备份过程是缓慢的。在这段时间里,管理员有足够的时间来检查和恢复故障计算机。当重新启动计算机后,它会在网络上进行主块冲突检查,避免同质数据块出现。尤其是主节点故障,在恢复完成前,存在着数据不全的可能性,这个时间内发生的更新/删除操作,Call节点将拒绝它们执行,直到全部数据完成恢复。

10.2.3 集群内其它节点冗余容错

相较于以上两种,集群内的其它节点由于只保存着少量实时的元数据,不负责集群管理工作,只是为了满足分布处理流程而存在,且运行过程中通常也不止一个同类节点,这使得每类节点之间,可以互相替代。这些单个节点的退出和加入,对于整个集群的运行来说,只会产生微小的影响。所以在 Laxcus 大数据管理系统的冗余容错设计里,对这些节点的容错管理要宽泛很多。它们的故障,大都以报警方式通知给Watch节点,由管理员来判断和选择处理。它们缺失的工作,会在管理节点的干涉下,把业务切换到其它同类正常节点上。这些故障感知和切换过程都是实时的,被控制在数秒以内,保证将对集群的影响降到最低。

数据的冗余容错

根据我们统计的多组 Laxcus 集群故障,因为节点导致的故障概率并不高,大量发生的是数据错误。造成数据错误的主要原因是磁盘出现了坏区,这种故障通常在计算机读写磁盘数据被捕获。处理数据错误的办法是冗余复制,由出现错误块的 Data 节点使用自修复机制来实现。其过程是错误块所属 Data 节点通过网络去查找其它 Data 节点上同编号的数据块,然后把正确的数据块下载下来,取代已经出现错误的数据块。在数据块复制过程中,这个表下面的全部数据块将被锁定,直到完成更新后才被解锁。错误的数据块将被 Data 节点标记起来,并且停止使用它。最后 Data 节点将数据块编号和自己的网络地址发送给 Watch 节点上,提供管理员注意已经发生了数据错误。

分布任务组件容错

现在的分布任务组件故障基本都来源于用户,是开发者在编程时处理不善导致。这样的错误在开发者编程过程中,以及集群测试环境里都难以发现,只有在正式的运营环境才有可能发生。负责监管分布任务组件错误的是沙箱,这是它在安全管理之外的另一个主要责任。为了防止故障扩散,沙箱将分布任务组件错误限制在它自己的空间里,不会波及节点和其它分布任务组件。故障发生后,沙箱会立即卸载这个分布任务组件,并且向源头发送一个错误码和它的错误堆栈,同时也把这些信息提交给管理员,由管理员去负责和用户交涉。

管理员责任

虽然集群提供了故障感知能力,也实现了一些错误自恢复处理,但是仍然有各种后期管理工作,需要管理员来执行才能解决。要完成这些工作,管理员应该具备一定的专业知识和职业责任。

对于很多因为软件问题产生的故障,现在已经基本可以通过追踪日志和断点分析得到;对于硬件故障,则更需要维护经验和专业知识,这些都需要一定时间的工作积累,付出很多时间和学习为代价。实际上,根据我们的运营和管理集群的经验,随着未来大数据市场需要的存储量和计算量的增加,网络和集群规模会越来越大。要做好集群管理工作,不是一件轻松的事,集群管理员要能够了解集群和各种节点的性能参数、执行处理范围、故障特点和原因,并且能够在发现问题后能够很快解决问题,在线上和线下与各种人进行沟通和联络。这些要求,做为集群管理员,需要有充分准备。

系统安全

由于安全问题对大数据系统乃至当前社会的重要性,我们在 Laxcus 2.x版本实现了全体系的安全管理策略。同样我们也考虑到不同用户对安全管理需求是不一样的,所以在设计安全管理时,针对不同环境、不同环节做了一些选择性处理。

Laxcus 安全管理模型是一个“网络->节点->用户->业务”的四层管理架构。RSA+SHA 的安全策略,是系统所有业务的安全基础。在 FIXP 网络里,要求所有业务都使用RSA加密,所有数据都经过 SHA 验证。此后,分别是对称加密、资源安全策略、签名管理、用户安全策略、业务安全策略一系列安全管理措施。在这些措施里,RSA 是目前安全等级最高的加密手段,SHA 是数字签名算法,可以保证网络传输内容的正确性。针对不同的安全需求,系统提供了 SHA1、SHA256、SHA512 三种签名验证。之后,对大量传输的数据,FIXP 网络将启用对称加密。目前对称加密算法除了 AES、DES 等常用算法外,管理员还可以通过系统提供的 API 接口,将自己的私有对称加密算法加入其中。资源安全策略则包含了为不同节点和服务设计的安全验证。签名管理判断每个注册用户的合法性。用户安全策略通过规范化的 API 接口,赋与用户自定义安全规则的能力,方便用户自由定义、调整自己的私有数据业务,这有助于强化数据处理过程中的用户数据安全。业务安全策略配合用户安全策略,保证每一项数据业务全程处于系统监管状态下。

上述安全管理措施非常繁多,但都是围绕着两个目标进行:防窃取和防篡改。考虑到安全管理对数据处理业务的影响(频繁的 RSA 计算对 CPU 的占比非常高),在系统的某些层面,安全管理被设置为可选项,决定权交给集群管理者和用户自己处理。例如在内网通信中,由于内网的安全保障度比较高,并且内网的数据传输量又非常巨大,主要的网络计算工作都在内网中进行。所以在这种情况下,为了给数据处理是腾出基础资源,提高处理效率,可以酌情选择省略掉部分安全管理。

本章将依循 Laxcus 大数据管理系统架构,阐述每个层面的安全管理。

环境安全

在系统架构设计上,Laxcus 集群被分为内外彼此隔绝的两个网络环境。内部网络的拓扑结构对外部保密,且不可访问。网络地址一般是采用 TCP/IP 协议中的内网地址(10.0.0.0 – 10.255.255.255、172.16.0.0 – 172.31.255.255、192.168.0.0 – 192.168.255.255),它们由专业的计算机集群管理人员来管理和维护,可以被认为是“安全”的。外网由普通的注册用户来使用和管理,不在集群管理人员的可控制范围内,来源可以是互联网或者VPN的连接,他们属于低可信度用户,被认为是“不安全”的。网关节点位于它们之间,除了起到沟通双方的连接和分解任务压力的作用外,更主要是在接受外部网络请求的同时,屏蔽内部网络拓扑结构,使内部网络有一个相对安全的运行环境,防范可能遭到的网络攻击。

虽然运行环境提供了这样的安全设计,但是在部署集群时,仍然需要集群的组织管理人员遵守设计规定。集群运行过程中,管理人员也应该具备安全管理常识,这是需要相互配合的工作。在这个的架构安全基础上,还有后续一系列的安全管理措施,进一步降低集群被攻击的可能性。

通信安全

在 Laxcus 设计定义里,节点同时具有客户机/服务器的双重身份。在每一次网络通信开始时,为了确保客户机是可以信任的,服务器会要求客户机出示通信安全凭证。这个凭证将保证双方在安全的状态下通信。

通信安全凭证在 FIXP 服务器上配置,这里面保存着客户机在连接时必须出示的信息。一台FIXP服务器可以按照不同来源的用户,为他们配置个性化的通信安全令牌,这种措施保证了每个用户都能够拥有一套属于自己的网络管理策略。这样即使某个用户的账号因为个人原因遭到外泄,也不会影响同一节点上的其他用户的安全通信。FIXP 安全通信分为三种类型:地址验证、账号验证、地址/账号复合验证。当服务器要求客户机出示安全凭证时,客户机必须遵守这个协定,向服务器出示自己的安全凭证,否则通信将被服务器中止。客户机也可以主动向服务器要求安全校验,服务器每次都是会接受的。

通过安全凭证验证后,可以确定网络两端之间传输的数据是正确和可信任的,这样就为后续的数据处理工作提供了一个基本的安全保障。

使用中也有例外,例如上面提到的内网通信。因为内部网络相对公共网络,它的安全度和信任度颇高,而通信安全项除了地址验证外,其他两种都需要执行消耗 CPU 的计算,这会造成数据处理的延迟,对大规模、高频度、高密度的网络计算来说显得得不偿失。所以,一般的建议是,在使用互联网通信的双方,应该启用安全通信;在信任度较高的内部网络,这项工作可以选择地址验证,或者忽略它。

节点准入制度

在 Laxcus 集群里,一个节点若要向另一个节点发起命令请求,必须首先以客户机的身份登录它的服务器节点,客户机发出的每一条命令,都要接受服务器的验证和检查,这就是节点准入制度。

节点准入制度是在安全通信之后,为各节点间的连接和操作定义的一套安全措施。在这个层面上,能够保证各节点之间的连接都是正确的,被传输的命令也在监管范围内。

比如,Aid 节点只能连接 Top 节点,连接 Home 节点就是非法的。Front 节点必须先向 Call 节点注册,才能得到命令操作许可。Call 节点只能向 Data 节点发出 SQL SELECT 命令,向任何其它节点发出这道命令都会遭到拒绝。

我们对不同节点的节点准入制度有一套详细的规定,在此就不赘述。由于这个规定准确定义了它们之间的请求、受理范围、命令许可,使得每个节点和每一道命令在运行过程中都接受检查,杜绝了一切可能的非法连接和操作。

用户账号安全

用户登录使用 Front 节点。无论用户是以终端的交互方式还是驱动程序的嵌入方式接入 Laxcus 集群,系统都要求用户提供一个登录账号,确认用户是可信的。 Laxcus 账号由用户名称和密码组成,每一个账号必须由系统管理员建立,账号的用户名和密码会被计算机计算为 SHA1 算法的散列码,再通过网络上传到 Top 节点,保存到数据字典里,供后续使用。

账号的用户名是系统唯一的,一经建立不能修改。当系统管理员建立账号后,会通过其它渠道将账号的明文转交给账号持有人。账号持有人拥有修改账号密码的权利,通常账号持人会修改系统管理员设置的密码。

特别注意,在建立、修改和使用账号登录的过程中,账号的明文只出现在用户的计算机屏幕上或者用户的驱动程序里,不会出现在网络通信的任何环节。Top 节点保存的只是账号明文的 SHA1 算法散列码,由于 SHA1 算法逆向破解的难度,使得获取账号明文的可能性极小。这样就使得账号在产生和使用过程中拥有极大的安全性。

另外,用户登录除了需要提供登录账号外,还必须持有一个系统管理员颁发的安全许可证书。这是一个经过RSA算法签名的文件,由系统管理员建立和保管。用户登录时首先出示这个证书,服务器会检查证书的有效性,确定证书有效和登录者可信后,再执行账号检查,进一步判断账号的正确性和操作范围,决定是接受还是拒绝。

这样,实际上每一个用户的登录过程都是 RSA 和 SHA1 的组合,首先用SHA1对账号进行数字签名,然后用RSA进行传输和校验。究其原因,因为这是进入集群的第一步,必须保证有足够的安全强度。这种双保险措施保证了每一个登录用户的可信性。

登录成功后,双方进入正式的通信状态。我们通常要求数据经过加密或者数字签名处理。目前提供的加密和数字签名算法有:AES、DES、3DES、MD5、SHA1等。这些算法和密钥会随着通信过程自动变换,使得窥密者短时间内难以获得明文,这又进一步提高了交互双方的数据安全度。

综上所述,用户进入 Laxcus 集群依次有三道安全门槛:RSA、用户账号、对称加密或者数字签名,前两种保证用户登录时的安全,后一种保证登录后数据内容的安全。

用户权限管理

用户使用 FRONT 节点登录,只是拥有了进入集群的权利。若要获得数据处理能力,还需要获得进一步的数据操作权限。

数据操作权限也是由管理员来授权。数据操作权限从高到低分为三级:用户级、数据库级、表级。每一个级别有多个操作选项,部分选项会在多个级别存在,对于这类同质选项,上一级操作权限默认高于下一级操作权限。例如SQL“SELECT”操作权限,用户级“SELECT”高于数据库级”SELECT“,数据库级”SELECT“又高于表级“SELECT”。

由管理员分配的数据操作权限也可以被管理员回收。权限回收后将立即生效,超过权限的数据请求在此之后将被拒绝。

通过用户权限管理,管理员可以把用户的数据处理操作控制在规定的范围内,杜绝用户可能的越权操作。

私有业务安全

私有业务属于用户业务范围,这一块的安全管理交给用户处理。在这个层面,用户可以自由组织自己的数据内容和数据格式。组织方式分成两种:

  1. 使用系统提供的可类化接口,在发送前,把数据按照自己理解的数据格式,用各种方式编排在一起,在接收后,再重新拆解。可类化接口中的“ClassWriter、ClassReader”同时提供加密/解密功能,可以进一步提高安全能力,这些加密/解密算法也是可以由用户自己定义的。这样在数据传输过程中,由于格式和内容都经过了处理,破解就变得很困难。至于密码,可以放在外界难以窥测到的地方,比如命令自定义参数的某个位置,或者集群的数据字典里。
  2. 数据表中的数组数据,在生成时通过系统提供的“Packing“接口加密。这样内容在生成就已经处理过,只是在显示的时候被解开,重新以明文格式出现,中间过程都是以密文的形式存在。在不掌握密码的情况下,外界也是无从窥视。

分布任务组件安全

分布任务组件的安全由沙箱(sandbox)来保证。目前沙箱属于容器管理服务的一部分,提供监视和限制程序操作范围的能力,已经被集成到 Laxcus 大数据管理系统里。所有处于运行状态的分布任务组件,都被置于沙箱里运行。

将分布任务组件置于沙箱里运行的根本原因在于:分布任务组件来源于用户,从保守的安全角度考虑,我们无法预判每个分布任务组件都是善意和可以信任的,不会在他们的程序里含有恶意代码,那么从统一处理的原则出发,我们就假定这些分布任务组件都是不安全的,需要在它们运行过程中,监视和约束它们的操作行为,以防止各种可能危害系统或者其它分布任务组件的事情发生。

在沙箱里运行的分布任务组件,它们的操作权限受到沙箱严格监管,只能“读、写、删除”规定目录下面的文件,或者获取规定的系统属性,其它操作都被排除在外。运行过程中,分布任务组件发出的每个操作请求都会首先传到沙箱进行安全检查,当发现操作超出许可范围时,沙箱将拒绝执行,以保证运行环境安全。

沙箱的安全检查项目被放在安全策略文件中,在系统启动时加载。修改安全策略文件是很容易的,不过这属于集群管理员的职责,普通用户没有这个能力。

数据块安全

数据块的安全依赖于对数据的签名。当数据块从 Cache 状态转向 Chunk 状态过程中,系统会计算这个数据块的数据内容,生成一个256位的数字签名,做为校验码保存到数据块里。产生数据块的签名过程很快,一个64M的数据块签名生成时间,在 Pentium4 2.0G 的计算机上,通常在10毫秒左右。

当 Data 节点重新启动,或者数据块被加载到内存,或者通过网络传输到另一个 Data 节点,系统会重新根据数据内容再次生成一个校验码,与已经存在的校验码进行比较,确认数据的完整性,以保证后续数据处理的数据本身是正确的。

行/列存储安全

数据块从 Cache状 态转入到 Chunk 状态过程中,除了生成数据块签名,还会根据数据块的存储模型,针对行集合或者列集合,生成它们的 CRC32 校验码,并且保存在记录的开始位置。

设置行/列集合校验码的原因是,因为整块的数据不会被经常调用,而行/列集合的数据却总是在网络上大量、频繁传递,这就使得行/列集合的数据校验更有实际意义。

然而相较于少量的数据块签名计算,被传输的行/列集合因为粒度细、数据量大、校验次数频繁,计算持续时间也会更长,这将消耗大量计算资源,影响网络计算的处理效率。所以,通常任务请求方在收到计算结果后,会根据数据的来源来选择是否检测。如果是内网数据,由于网络安全度高,这个校验可以被忽略。

运行测试

本章将介绍一些 Laxcus 集群基本运行、使用情况,结合图片和表格表示。地点是我们的数据实验室,使用我们的实验集群。数据来自于我们的合作伙伴,软件平台混合了 Windows 和 Fedora Linux 两个操作系统,硬件因为一直以来的测试需要,显得参差不齐,从10年前的旧机器到今天最新的设备都有。这样的环境虽然不足以反映目前商业运营的集群现实状况,但是在反映 Laxcus 集群和集群基础硬件性能参数时,仍然具有一定的代表性。为了更好反映测试结果,我们将多用户多集群的 Laxcus 部署成单用户单集群环境(即一个主域集群加一个子域集群和一个注册用户)。网络传输都按照默认规定,采取了流量控制措施。

配置

首先介绍这个实验集群的基本情况,我们把配置分成两部分:硬件的计算机、软件的节点,用两张表说明,可以从中一窥集群的端倪。因为 Data/Work节点要执行数据存储和计算工作,所以大量计算机分配给它们。本次测试没有数据构造业务,Build节点就只保留一台做为冗余。在这个集群里,因为每台计算机的硬件配置很不相同,数据也不是平均分布的,这直接导致 Data 节点产生的数据量不一致,和Work节点的计算时间长短不一,Call节点做为它们的协调者,会尽量去平衡这种不平均现象。其它不怎么产生计算压力的节点就用一台,或者合用一台计算机。

部件类型数据
CPUPentium III、Pentium IV、CORE、ATOM、ARM32
内存512M – 4G
硬盘20G – 2TB,IDE/STTA/SSD,Data、Work、Build、Call节点会部署多个硬盘
网卡100M/1G
带宽1G

表:硬件情况

节点说明
Top1个,与HOME/ARCHIVE/AID合用1台物理计算机
Home1个,与Top共享使用
Archive1个,与Top共享使用
Aid1个,与Top共享使用
Log1个,独立使用1台物理计算机
Call3个,部署在3台物理计算机上
Data24个,部署在24台物理计算机上
Work20个,部署在20台物理计算机上
Build3个,部署在3台物理计算机上
Watch2个,共享1台物理计算机,分别监视TOP/HOME两个集群
Front8个,部署在2台物理计算机上。

表:节点情况

管理

管理是 Laxcus 集群一项基础服务。它包含两个部分:管理员对集群的管理,用户对所拥有数据的管理。集群的管理,由管理员通过Watch节点实施。用户对自己数据的管理,由用户通过Front节点实施。所有管理工作都是通过命令实施,其中有些命令可以被管理员和用户共用。另外为减少管理员的工作负担,部分由管理员实施的工作也可以指定某个用户代为处理,如对用户账号授权这样的管理工作。但是大部分命令都有它们明确的操作归属,不允许随意使用,即使被错误发出,也不会被集群接受。

元数据

在 Laxcus 集群运行过程中,元数据是一项很重要的参考指标,它大体反映了每一个节点的当前的负载和运行情况。如果把这些元数据综合起来,可以进一步获得一个集群的运行信息。或者按照不同要求,对不同的元数据进行分类、对照、聚合、比较,又可以反映出集群某一局部的运行状态。

Laxcus 集群的元数据只对集群管理员开放,用户不具备这项权利。在实际的集群管理维护中,管理员通过Watch节点向集群发出命令来获得元数据,使管理员可以快速了解集群运行情况,是管理员工作的重要辅助手段。通过元数据管理员可以很快检查、发现集群可能存在的运行问题,或者在实施一项工作前,通过元数据获得必要的预判,再决定接下来的工作是否处理和处理方向。

目前元数据都是以文字和表格的形式显示出来,下一步将提供图表化和图像化的显示方案,这样管理员将获得更丰富和直接的显示效果。这项改进工作已经在项目日程中。

节点类型节点数量元数据尺寸关联数据尺寸
Top10.372M
Home10.692M
Archive11.731M
Aid10.053M
Watch11.528M
Log10.339M
Data245.712M – 28.729M623.182GB – 4.851TB
Work200.131M – 0.257M
Build10.180M
Call31.361M – 6.749M8.302TB – 47.276TB

表:测试集群元数据列表

数据操作

在 Laxcus 大数据管理系统中,数据操作被归为用户使用部分。现在主要通过Conduct 、Establish两个命令来实现大规模数据处理。另外考虑到用户的使用习惯,我们还完整兼容了SQL四个主要命令:Insert、Select、Delete、Update。在实际应用中,由于直接操作Select会产生巨量数据,给Front节点带来雪崩现象,造成Front节点瘫痪,所以极少被直接使用,而是把它嵌入到Conduct、Establish命令中组合使用。

Front节点是用户操作数据的入口。在很多运营环境中,大多数时候,它被用户做为驱动程序,嵌入到其它软件中使用,其中使用最多的SQL命令是Insert。图形界面和字符界面的Front节点起着辅助作用,主要是用在用户的数据管理上。

Sort Benchmark 测试

我们设计了一个Sort Benchmark测试,通过一个分布环境下的数据排序工作,追踪数据的产生、写入、读取、传输、计算一系列流程。在考察一个集群的数据处理能力的同时,也对集群中的CPU、硬盘、内存、网络设备等主要硬件部件进行性能考核。测试以一套分布任务组件展开,组件名称是“SortBenchmark”。按照 Laxcus 大数据管理系统要求,这个命名在整个主域集群是唯一的,并且已经通过检查发布到集群上。SortBenchmark基于Diffuse/Converge算法,对应操作命令是Conduct。为防止多用户多任务并发竞用集群资源影响观察效果,所以在测试过程中,集群里只运行一个用户的一个任务。这个工作首先从一个Front节点向Aid节点发出命令,再由Aid节点转发给Call节点。Call节节点根据命令的参数,检查和分配后续数据处理工作,并监管整个工作直到完成。在这个期间,Front节点将等待Call节点的反馈结果,然后撤销Aid节点上的记录,并把测试数据打印了计算机屏幕上。

排序测试

测试从Front节点开始,图形窗口上,Conduct命令中的关键字被高亮显示。其中”sites”表示要求的节点数,”writeto”表示测试报告被写入的本机磁盘文件。”from、to、put”都是Conduct命令的阶段类型关键字,其它是自定义参数关键字,此次排序操作被要求按照升序排序,中间数据写入硬盘,SortBenchmark默认产生的随机数是64位长整型long。

整个命令的表述是:SortBenchmark组件要求产生2000M的随机数排序,分给20个 Data.From 阶段任务去执行。每个 Data.From阶段任务负责产生100M的随机数,随机数将按照Work.To阶段任务的20个节点数要求,把100M数据切割成20个5M数据,每个5M数据会有一个对应的“模”值。之后把数据写入硬盘,并把20个5M的数据映像成一组元数据,返回给Call节点。Call节点将对20个 Data 节点的元数据进行平衡计算,通过拆分重组后,对应Work.To的20个节点数,产生20组新的元数据(这些元数据中指明了 Data 节点地址和数据位置),分配给Work节点。如果所有 Data .From阶段任务产生的随机数是完全平均的(这是理想状态,现实中不会有绝对的平均),那么每个Work.To阶段任务,将启动20个连接,去20个 Data.From阶段任务中,拿走其中一个5M数据,并把20个5M数据在本地内存重新合并成100M的数据。这时,按照Call节点给每个Work.To的编号排列,每个Work.To阶段任务中保存的随机数,它们之间已经形成链接关系(当前Work.To阶段任务保存的最后一个排序数字,总比下个任务第一个排序数字大)。此时再对100M数据进行升序排序,就产生了最后的计算结果。出于对Front节点计算机性能考虑,2000M的数据量实在太大,接收下来要花很长一段时间,这将影响到统计总计算时间,况且也没有必要接收这些数据,所以在Work.To排序后,数据将丢弃,只返回一个排序测试报告(实际是SortBenchmark自定义自解释的元数据)给Front节点。

基于硬盘的排序,即Data.From将随机数据生成后,写入到硬盘,然后在Work.To请求下,又从硬盘读出。我们前面多次提到过,硬盘是数据处理过程中的最大瓶颈,会消耗很多输入输出时间,所以在图12.5.1.2中,我们调用7.10节所提的中数据数据写入接口(MidWriter),每个Data.From存储100M数据的位置,由默认的硬盘改为内存,省略了写/读硬盘过程,这样SortBenchmark整个处理流程不再接触硬盘,成为一次流式排序操作,排序结果明显比基于硬盘的排序方式快了很多。

排序分析

从上述两组对比测试数据可以看出,数据的产生、传输、排序阶段,它们的平均处理时间是接近的。但是同一阶段的并行任务之间,它们的处理时间差距则很大,这是由于硬件配置不一致所造成。这种最快和最慢之间的差距,是导致数据排序木桶短板现象的直接原因。造成下一阶段的等待时间,由上一阶段的最慢那个线程决定,如此迭代下去,将严重影响整体排序处理效果。这是目前很多大数据处理普遍存在的现象。所以在运营的集群环境中,负责数据处理工作同一类型的节点,如果能够使用相同的硬件配置,将有效减少这种拖滞问题。

为了达到快速的数据处理效果,把存储中间数据的位置,从硬盘改为内存,这是流式处理的基本原理。这种方案带的好处就是数据处理速度确实加快了,但是缺点也很明显:提供云计算或者集群服务的运营商要采购更多内存,这样就增加了设备投入成本,对运营商来说是一件“奢侈”的服务方案。另外根据我们的市场调查,目前需要快速数据处理业务方案的用户比例并不高。

排序优化

上述排序仍然存在一个问题:100M的数据量,对于一台计算机来说,计算量实在不小,这从Work.To阶段任务的排序时间就可以看出。如果能让Work.To把每次的数据量变得更小一些,分成多个批次排序,这样总数据量没有变,但是总计算时间会相应缩短。再采用衔接的办法,把数据按照“模”方式串联起,会得到和上述一样的排序结果。

这个测试很容易,有兴趣的读者可以在自己的计算机上尝试一下,看看1个10M的数据排序时间,和10个1M数据排序的时间,它们有多少差别。

下面看一个改进,在Conduct命令的From阶段增加一个“next_split(int)=5”自定义参数。这样就把在原来每个5M基础上的数据,再分成5份,实际上形成了100个1M的数据单元。Data.From每次产生的随机数,被分到100个1M单元中的一个,返回的模值,也由原来100/20的关系,变成100/100的关系。在Work.To阶段,相应需要启动100个连接,每个连接拿加加属于自己的一块数据,再按照20*1M,分成5个20M的数据,每个20M的数据为一个单位进行排序,5次排序后,再按照它们的模值串联起来,形成最后的排序结果。

如果希望将总处理时间进一步提高,“next_split(int)=5”这个参数还可以再增加,使得Work.To单次排序数据量更小,然后再结合“模”衔接,得到更快的排序效果。另外现在的计算机已经普遍使用多核CPU,这样在排序时,同一时间可以并发多个线程,将使得总排序时间获得进一步改善。

需要说明一点,这里忽略了socket问题。因为本次排序,集群中只有一个任务,单机并发100个连接和产生的流量尚在可接受范围内,但是在实际的运营环境中,这种并发连接可能会产生很大的数据流量,按照 Laxcus 流量控制机制的规定,超过环境条件许可的连接和流量将受到限制,所以实际效果可能并不如意,这一点用户应该注意。

总结

以上从多个角度阐述了 Laxcus 主要组成部分和应用情况。所有设计都是基于现实环境下的评估、对比、测试和考量。设计的基本思路很明确,就是将大数据需要的各项功能分解、细化、归类,形成一个个可以独立、小的模块,每个模块承担一项职能,再把这些模块组织起来,在松耦合框架管理下,协同工作,来完成大规模的数据存储和计算工作。

设计中的主要问题源自有限的基础设施和变化中的应用需求之间的矛盾。如何在不损失处理性能的前提下,将有限的基础设施资源利用率做到最大化,是设计考虑的重点。这也是一个和硬件密切相关的问题。

在核定系统设计目标时,我们面临多种选择。大多数情况下,没有鱼和熊掌兼得的可能,只能二选一做出取舍。考虑到系统虽然经过很多简化处理,但是为了满足需求,仍然存在太多环节,加之这些环节之间各种关联导致的复杂性,我们将稳定、可靠、“大”这三项指标放在首位,其它指标则做为次要需求放在后面。所以,从这一点来说, Laxcus 虽然能够管理百万级的计算机节点,实现了EB级的数据存储计算能力,也提供了基于内存的快速数据处理解决方案,但并不是一个为追求“快”而设计的大数据系统。

现在再回过头,根据我们的经历,来看一个我们组织实施并投入运营的集群基本配置情况:拥有从数百台到千台左右规模的计算机,采用X86架构的32/64位芯片,每台计算机配置2 – 8G的内存,2 – 4TB储量的温彻斯特硬盘。计算机被部署在多个机架上,采用千兆的光纤网络,通过多台交换机实现连接。不同的时段内,会有数百到数万个用户,每个用户并发多个任务使用着这个集群。

可以看到,在这样的网络环境中,每台计算机能够分到的带宽并不多,考虑到 Laxcus 是多集群多用户系统,每个用户又并行执行着多个任务,每个任务以并发方式分派出多个子任务。在这种情况下,实际能够分配到每个子任务身上的带宽就更低。集群在执行正常的数据处理业务之外,还有大量的集群管理业务也要通过网络传输数据,如果把全部数据用量统计起来,这样的带宽很容易发生超载现象,而集群管理又严重依赖网络通信,这一部分的带宽资源是不能够被挤占的。所以,如何节约数据处理过程中的各种存储和计算开销就变得非常关键。节约的一个办法是杜绝冗余数据。

冗余数据主要产生在数据生成阶段,预防手段也很简单:对数据进行精确的筛选和抓取。这就涉及到存储方案的设计。

为了适应不同业务需要,我们设计了行/列两个存储模型。存储模型的最小存储单位是列。在列这个层面上,数据可以随意地组织、置换和计算,在保证灵活性的同时不失其精准性。与之相关的,把SQL融入分布描述语言,与分布环境结合具有一举多得之效。比如借助Where子句的多条件组合查询能力,通过SELECT语句将其分散作用到数据存取层面后,以列为单位的检索结果可以直接在计算机生成,从而避免了冗余数据在网络上传输。这种数据处理方案,非常符合分布环境下在数据源位置进行计算的原则。即以移动计算代替移动数据计算的原则。节约原则还体现在对数据格式的原始定义上。

Laxcus 设计规定,数值统一采用二进制格式表述。比如一个整型值,二进制格式固定为4个字节,如果换作字符串表述再加上符号位,最大将达到11个字节。这就使得二进制数值无论是在磁盘和内存里存储,还是在网络上传输,数据量都比其它格式要少。而且因为数值的长度固定,当进入CPU层面进行处理时,不需要转换数据类型,就能够被CPU识别和计算,比如C语言就可以通过指针可以直接引用。这在执行数据密集的计算任务时,能够显著提高计算效率。

FIXP协议也是体现二进制优势的又一个例证。在网络通信中,基于UDP传输的监控包占了很大比例,因为二进制使得FIXP包的数据长度相对较小,通常都小于一个IP包的长度,也低于链路层对数据包的尺寸限制。这样的结果使得FIXP包能够被直接传输,避免了在网络两端对数据包进行的分组和重组操作。这个小小的改进使得FIXP协议的丢包率大为减少,不可靠的UDP通信成功率大为增加,获得了更高的通信稳定性。

Laxcus 针对的是目前普遍存在的各种大规模数据处理,并着眼于未来的超大规模数据处理环境。为了实现易用性,设计中很重要的一项要求就是简约化的数据处理需求。这包括了更低成本的硬件、快速的布署、容易的维护、简单的开发和操作,使用户能够以轻松的心情完成大数据处理。所以在用户体现设计上,用户的感觉会更接近于数据库,而不是什么新的数据产品,并以此来达到减少用户学习压力,提高使用效率的目的。另外还有一项隐含但是非常重要的要素是:在我们的现实世界中,各种事物之间是存在“关系”的,数据的本质就是这种“事物”和“关系”的关联反映,从“关系”的角度去理解、组织、处理数据,更符合人们的思维习惯和定势。

与当前很多大数据产品不一样的是, Laxcus 大数据管理系统一开始就着力于实现下一代的大规模数据处理,要求在一套产品里做到大数据业务的全功能全体系的高度集成,在满足用户超大规模的数据存储和计算需求的同时,还要提供接口化的编程模型,并保持轻量级的管理维护模式和易操作性,这些基本需求最终促使 Laxcus 大数据管理系统必须拥有自己的产品特点。

所以,我们在系统设计中采用了松耦合架构和架构/功能一体化结合的设计方案,来提高内部结构集成度,减少开发和维护冗余成本,并保证在系统总体结构不变的情况下,为以后的产品迭代和版本升级,提供足够的扩展空间。

在这个基础之上, Laxcus 大数据管理系统又设计了实时映像来管理元数据信息,通过元信息在集群内的实时分发和映射,来实现各节点间的信息交互和联系。这些元信息在系统运行过程中产生,在网络之间传递,在内存里驻留,不进入磁盘,被不定时地被刷新,总是保证处于最新状态。且它的数据尺寸极小,不会对运行环境构成压力,能够保证分布状态下实时的数据追踪和数据处理。

设计中另外着力考虑的是网络环境下数据计算面临的诸多问题。

数据块成为解决这些问题的关键。

如第3章所述,数据块的基本特点是长度固定。只此一点,就避免了磁盘碎片和减轻了数据维护的难度。也是因为这个原因,使得数据在网络间的传播极为简单,为网络环境下的数据备份和负载平衡奠定了基础。同时,把对磁盘影响最大的写操作转移到内存执行,以空间换时间的手法,将磁盘的写操作延迟降到最低,使磁盘更专注于读操作。更进一步,通过引入数据优化和数据构建,使得用户更能够按照自己的意愿组织和检索数据。表现在磁盘上,直接的反映就是减少了读操作次数。这些都对改善磁盘处理性能、提高数据计算效率甚为重要。

在数据块之外,最需要提及的当属Diffuse/Converge算法,这是整个网络计算的核心。算法将网络计算过程分为两个步骤:Diffuse向网络上查找数据后进行分配,Converge在已经分配的数据的基础上,对数据进行再组织和再分配,数据的每一次的输出做为下一次的输入,通过数次迭代得出计算结果。围绕着Diffuse/Converge算法,又进行了一系列的配套设计。通过将系统和用户功能的分离,用户实现网络计算接口可派生编程,系统实现热发布、任务调度,模平均分配数据,任务命名,Conduct语句,使得这些模块在其中各司其职,运行时组织起来,形成从终端到数据存储层面,一个完整的网络计算体系。在保持了简单和易用性的同时,也实现了大规模数据并行计算的目的。

分布计算过程中的数据量平均分配的问题也得到妥善解决。分布环境里的数据被均匀分配后,得到的结果就是处理时间的基本一致,可以让每一个用户快速脱离计算环境,将计算机资源留给后续业务,这对保证集群高效处理来说十分关键。另外,在分布体系里,各节点上的数据分配采用“拉(pull)”,而不是“推(push)”的处理方式,也是简化数据处理流程,保证分布计算平衡性非常重要的一条准则。

分布任务组件技术是在总结目前各种中间件技术之上,进行的改进和提升。通过在分布任务组件中引入中间件、网络通信、集群概念,结合Diffuse/Converge算法的接口化,规范好不同阶段的功能和处理要求,再加上打包、发布等手段,我们很好地解决了用户二次开发中的学习成本、开发成本、部署成本的问题。在保证系统稳定、可靠、安全运行的同时,为用户提供了简单的开发环境,实现了快速开发目的,把用户的编程和运行中可能产生的错误降到很低的水平。

目前,以分布任务组件为基础,我们已经和合作伙伴一起,设计和开发了大量的大数据应用,正服务在各行业的大数据应用场景中。

冗灾处理也纳入了网络计算体系中。因为具有弱中心化管理和故障主动判断的能力,系统能够在很短时间内感知到故障的存在,并主动回避故障源。对于故障节点,系统一旦确定就会将其隔离,不会再出现在集群里,同时采用数据冗余和再恢复的办法,保护正常的数据处理业务。

在许多技术细节上,我们也做了优化处理。比如在执行底层计算时,针对数据密集的这个特点,通过合理运用X86芯片体系的SSE指令,能够使计算效率取得成倍的增长。另外,在计算中使用更多的加、减、移位指令,取代乘、除指令,也能够达到减少指令计算周期、提高计算效率的目的。还有一个更直接的手段是采用64位的CPU,根据测试统计,经过LINUX GCC64位编译器编译的C/C++语言代码,在执行关键数据计算时,效率比32位代码普遍提高15%-20%。

对于未来,应该根据集群和数据应用场景的具体特点,选择合适的软硬件组合。如本文开篇所言,集群计算不在意个体计算单元性能的强弱,它是把众多且分散的计算单元通过网络组织起来,以协同工作的方式,取代那些单一但性能强大的集中计算。这种以多胜强特点,为实现低成本的计算业务带来福音。这个情况,在数据中心表现尤其明显。在现在的数据中心内部,计算机和维持计算机运行的制冷设备,它们消耗的电量非常庞大。如果采用移动架构的硬件设备,不单计算机能耗会显著下降,计算机体积缩小,单位空间内的计算机布署数量增加,制冷需求也会大幅降低。还有,在数据应用领域,数据分析和多媒体业务正在快速增长,GPU天然适合处理这种大规模同质数据的简单重复计算,如果硬件系统能够采用CPU 加GPU的混合架构,且由于 Laxcus 已经支持混合架构,这样的组合将极大提升这些数据业务的计算效率。当这些改进后的基础设施被部署到数据中心后,它们会直接降低用户数据运营成本。其所产生的影响,正如当年的PC架构取代了小型机一样,当前的移动架构、混合架构取代PC架构已经露出峥嵘之势。今天 , Laxcus 大数据管理系统已经全面整合云管理、大数据、关系数据库、中间件和容器五大领域的技术和功能。以此为基础,在各行业普遍强调总体拥有成本(TCO)的今天,加上着力解决好硬件算力和软件算法的结合问题,配合海量存储计算和人工智能时代的到来,这将掀起一场新的数据计算革命。

这可能不是一个太漫长的过程,这里面还有许多工作要做。

现在只是刚刚开始。

参考文献

  • [1] D.M.Ritchie and K.Thompson, The Unix Time-sharing System, ACM (1974)
  • [2] E.F.Codd, A Relational Model of Data for Large Shared Data Banks, ACM(1970)
  • [3] 聚一网络科技有限公司,分散数据的聚合计算方法,2003
  • [4] 聚一网络科技有限公司,自由信息交换协议(FIXP),2005
  • [5] Laxcus 大数据实验室,行列混合存储性能分析,2011
  • [6] Laxcus 大数据实验室,分布计算的参数化函数模块和实现,2011
  • [7] Laxcus 大数据实验室,分布任务组件开发方案,2011
  • [8] Laxcus 大数据实验室,分布数据的精准定位和纠错,2012
  • [9] Laxcus 大数据实验室,集群松耦合架构设计,2013
  • [10] Laxcus 大数据实验室,采用标记化方法追踪和记录运行参数,2013
  • [11] Laxcus 大数据实验室,数据的乱序传输和处理,2014
  • [12] Laxcus 大数据实验室,去中心状态的分布一致性保证,2015
  • [13] Laxcus 大数据实验室,在分布系统中兼顾高可靠性和高可用性的方法,2015
  • [14] Laxcus 大数据实验室,跨账号的有限授权操作,2016

本文首发于GitChat,未经授权不得转载,转载需与GitChat联系。

阅读全文: http://gitbook.cn/gitchat/activity/5a900cc86ea84019c594bafd

您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

《从0开始,设计研发一个全功能通用大数据系统》

    原文作者:蔚1
    原文地址: https://blog.csdn.net/valada/article/details/79910016
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞