Kappa Architecture将数据库提升到新阶段

饮马天涯 2016-07-19

亚马逊Aurora让数据库可扩展,但Kappa Architecture让数据库的发展无极限,管理员可以跨服务器集群创建数据的物化视图。

传统的数据库有许多先进的功能,其中对开发者最重要的就是物化视图功能。这种存储查询会自动缓存创建耗时的查询,并将数据写入磁盘。但传统的数据库在数据的存储量和接受请求的吞吐方面的扩展性不佳。虽然亚马逊Aurora可以提高数据库的扩展能力,还单个数据库的处理能力仍然有限。Kappa Architecture可以在这点上有所助益。

Kappa Architecture将数据库提升到新阶段

Kappa Architecture是一种软件架构模式加上一个只允许追加不允许修改的日志。Kappa Architecture同Lambda架构系统类似,只是不支持批量处理。在数据库中,有个细节叫做事务日志,每一次对数据库的变更都会对日志进行写入。事务日志是用来重建部分数据库的内容,如果出现问题的话可以恢复到特定的时间点。该日志包含底层数据的每一个原始动作。例如,如果一个客户要购买一件物品,事务日志可能会这样显示:

at 1463086280008 row 123456 old value = [ "cust-123", 50 ] new value = [ "cust-123", 25]

该值显示在unix时间戳1463086280008的时候,123456行记录从“cust-123”,50变更为“cust-123”,25。

这就是被称为fact,表明在某个特定的时间,一个值被从某个值改为另一个值。这个事实是真的,不管之后会发生什么。举例来说,即便客户在此之后又增加了25个积分,他们在这个特定的时间点仍然是减少了25积分。

数据库常年都处理这种小细节,但大多作为一个小的实现细节。Kappa Architecture建议将此作为记录的主来源,其他的一切都作为数据的物化视图。传统的数据库可以在一台服务器上执行这种类型的活动,而这种方法允许管理员可以无限扩展和创建横跨不同服务器集群数据的物化视图。

管理员可以使用日志流来查看跨服务器集群的数据

此日志流成为一个只能追加的系统,只接受写入操作,在写入的时候加上基本的时间戳,然后将信息写入到磁盘中。这种交互的构想是,每一个写操作都是按顺序发生,所以该系统必须从头开始按顺序运行日志中的每一个事件,才能重建数据库当前完整的视图。

这使得开发人员可以在保持后台系统完全运作的同时增加额外的视图。每个数据视图可以在一个完全独立的系统或多个完全独立的系统里,只要这些系统有访问整个日志流的完整权限。日志流会通知每个视图任何一切操作以及操作发生的精确时间戳,这样所有的操作就可以顺序执行。然后每个视图可以获取其需要的所有信息以确保单个视图的正确建立。

Kappa如何在AWS上工作

创建Kappa这样的架构最显而易见的工具是Amazon Kinesis,这是一个专门用来处理数据流的工具。当一个进程附加到一个Kinesis流,它可以自动按顺序读取每一个事件,以建立自己的数据库视图。这可以用来将数据库的更改复制到其它数据存储,如亚马逊DynamoDB,甚至跨区域到其他的数据库,因为区域邻近优化的关系。

Kinesis的另一种替代选择是DynamoDB流,这对于使用DynamoDB数据库的开发者来说使用方便。将这个想成是专门针对DynamoDB的自动Kinesis流。不幸的是,无论来自Kinesis还是DynamoDB的流都只存储最近7天的记录。因此,要创建一个新的视图,开发人员必须首先从一个主数据库里读出包含所有变更的最终结果的全部数据。

想更深入的了解如何创建一个Kappa风格的视图,现在假设我们有两个DynamoDB表,Customer和Orders。公司的市场部门可能通常会问,“客户X这个月花了多少钱?”在传统的数据库方式下,查询该数据需要连接Customer表和Orders表,然后汇总出客户所花费的金额。

现在采用Kappa的方法,因为数据是存储在DynamoDB,而不是关系型数据库,这种类型的查询要么预先知晓,要么是我们为此建立的一个新的并会不断更新的视图。大量的数据被存在Orders数据库中,但营销部门可能并不想知道一个Customer ID,而是会查找一个客户的姓名或电子邮件地址。在这种情况下,开发人员可以创建一个包含Customer ID,Customer Name,Customer Email,Month和Total Spend的视图。你可以根据姓名和电子邮件来对这个视图建立索引。DynamoDB可以自动处理这个问题,但如果不使用DynamoDB,开发人员还可以创建两个独立的视图,一个根据名字建立索引和一个根据邮件索引。

Kappa Architecture结合AWS Lambda

首先,视图的创建脚本需要先连接到流,并开始存储DynamoDB流中的所有变更。该脚本可以从OldValue/NewValue的变化中识别出新的值。一旦脚本开始缓冲数据,会将当前数据表中所有的数据转存出来,写入到新表中。在所有的数据复制完毕后再开始处理事件。这种两阶段的方法有助于防止任何并发问题,以确保在数据被复制和脚本开始处理变更事件之间不会有数据丢失。

AWS Lambda是最有效的处理变更事件的方法。创建完用于创建该视图的Lambda函数后,进入Event Sources页,然后选择Add event source。

从Event Sources页选择‘Add event source’。

在弹出框中,选择DynamoDB。

选择DynamoDB作为事件源类型

接下来,填写细节,确保选择正确的DynamoDB表(Orders),在Starting Position处填写Trim Horizon。Batch size列出在某个时间最多有多少条记录被发送给AWS Lambda函数的单个实例。这意味着Lambda函数需要在单次执行中处理多个事件。

为Lambda函数配置DynamoDB表,batch size和starting position

接下来,Add Amazon DynamoDB Permissions to your role,以便Lambda函数可以访问DynamoDB流。开发者还应确保为角色添加AWS身份和访问管理权限,使其能够写入到新的DynamoDB表,这将是新创建的视图。开发人员应该首先测试Lambda函数;钩上Enable event source,直到函数的功能验证成功。在确保函数工作之后,使用同样的Event Sources控制台暂时禁用流,直到新的视图初始化完成。确保视图初始化完成后再重新启用源。

在重新启动流之前,最后一步是将所有现有的记录复制到新的视图。这涉及到用一个外部脚本来读取Orders数据库中的每条记录,并将其提交给Lambda函数。开发人员可能会想临时增加读取吞吐量直到新的视图产生,这样可以快速创建新视图。请记住,DynamoDB Kinesis流将在日志中最多保留七天的事件。

最后,写一个额外的句柄来处理Customer的DynamoDB表的变更,将任何变化,如电子邮件地址或姓名,更新到与该客户相关的新视图是一个不错的主意。