流处理时代(stream processing age)-part 1

流处理时代(stream processing age)

有的人称之为流处理。其他人称之为事件源或者CQRS(命令查询职责分离)。也有的人称之为复杂事件处理。总之,他们都包含了一个核心,帮助我们更好的设计系统。接下来我们将探讨给核心是什么!

我们将讨论event streams 如何使得你的应用更有扩展性(scalable)、更可靠(reliable)和更容易维护(maintainlable)。event streams 是LinkedIn 大规模系统的基础,而kafka正是有LinkedIn开源的。

Idea:将数据组织成事件流。许多的想法,当你接触核心时,实际上是很简单的。


处理事件的概念出现在许多不同的领域,一开始确实有点使人困惑。不同领域的人使用不同的术语,实际上说的是同一件事情。stream processing 来自于网络公司,例如,LinkedIn,主要源自于数据库的研究。而CEP源自于事件模拟研究,现在用于企业运营目的。Event sourcing 源自于领域驱动设计(domain-driven design),用于解决企业软件的开发。


一个关于stream processing的例子是Google Analytics Google Analytics 是一些JavaScript代码,你能够将这些代码放到你的网站中,它将跟踪哪个页面被哪个访问者所访问。管理员能够使用这些数据,并且按照时间段、URL等等进行化分。


首先,看看系统的输入。每次一个用户查看view一个页面,我们需要将记录(log)一个关于该事实的event。一个pageview event 可能像如下所示(使用伪JSON表示)。


一个page view有一个事件类型(PageViewEvent),一个Unix时间戳表示该事件发生的时间,一个客户端的IP地址,一个session ID(这个可能是来自cookie的唯一标示,使你能够得出来自同一个人的一系列page views)。被查看页的URL,和该用户得到该页面的方式(例如,来自搜索引擎或者来自点击另有网站的链接),用户的浏览器和语言设置等等。注意:每个pageview 时间是一个简单的、不变的事实。记录了到底发生了什么。现在,你如何从这些pageview events 中得到一个漂亮的图形仪表盘,使你能够清晰地知道用户怎么使用你的网站的呢?


总体来说,你有两个选择:

选项(a):当一个event到来时,你将他存储下来,将其存储到数据仓库的一个大的数据库中。例如(Hive).现在,无论何时你想分析这些数据,你可以执行一个大的Select语句。例如,你可能groupby URL和时间段(time period)。你可能利用一些条件进行过滤,并且count(*)来得到每个URL某个时间段的pageview 数量。这将扫描整个events记录,或者一个很大的子集,然后进行聚合。

选项(b):如果存储每个事件对你来说太多了的话,你可以转而存储事件的聚合指标。例如,如果你是在计数,那么当每个event来的时候,你将计数器(counters)加一。然后不再存储真正的事件了。你将保存一些计数器,我们称其为OLAP cube(在线分析处理立方体):想象一下,一个多维的立方体,一维表示URL,一维表示该event的事件,一维表示浏览器等等。对于每个event,你将增加的是哪个特殊的URL、时间等等维度的计数器。


选项(a)可能听起来有点疯狂,但是事实上工作得非常好。现在的分析数据库在扫描大量数据时变得快。存储原始event 数据的一个最大好处就是你在分析时有充分的灵活性。例如,你可以跟踪一个用户在他的session过程中所访问的页面序列。使用选项b显然你是做不到的。一些线下处理任务的类别事实上是很重要的,例如训练一个推荐系统。对于这些用例,最好是保存所有的原始event。

然而,选项(b)也有用处,特别是在你需要对某件事做实时决策时。例如,如果你想防止某人爬取你的网站,你可以引入一个比例限制,你就可以应许100个请求每个特定的IP每小时。如果一个客户端超过了这个限制,你可以阻塞它。使用选项(a)实现这个功能将非常的低效,因为你不得不不停的扫描你的历史event来觉得一个用户是否超过了该限制。对于选项(b),你可以对每个IP保存一个page view计数,在一个事件窗口中,然后你能够对每个请求检查它是否超过了你的限制。

相似地,对于预警来说,你需要非常快地对event做出反应,例如,股票市场交易,必须快速。

最后的结论:原始event存储和聚合的概要指标都很有用,但是他们有不同的用例。


在这个简单的用例中,你有一个web server直接更新聚合指标。例如,你想计算每个IP每小时的page view 量。你可以将那些计数器放在memcache或者Redis中。每次这个web server处理一个请求时,它直接给存储(memcache或者Redis)发送一个增加计数命令。使用由客户端IP地址和当前时间构成的Key作为存储中的key。如果你想要更高级一点,你可能引入一个event stream或者message queue或者一个event log等等。这个stream中的message就是我们之前看到的PageViewEvent,每个message包括了一个特定page view的属性。

    这个体系结构的好处是你能够有多个consumer来消费同一个event数据。你能够有一个consumer来将所有的原始event归档到一个大的存储中;即使你没有处理原始event的能力,你却可以存储他们,因为存储相对廉价并且你后续可以利用这些数据。你也可以有另外一个consumer来做一些聚合工作(例如,增加计数器),同时其他的consumer来做其他的事情。他们都由这个event stream来提供数据。


Event sourcing 来自领域驱动设计领域,和event stream相似。Event sourcing 关心的是如何在数据库中结构化数据。例如,以来是来自一个电子商务网站的购物车表。


每个客户在某一时刻可能有个一些数量的不同产品,对于该购物车的每个元素(item)有一个量。现在,假设用户123更新了他的购物车:对于999产品,该用户想要购买3个产品,而不是1个产品。在数据库中,将会把该记录的quality字段从1update到3.

但是,就event sourcing来说,这并不是一个好的数据库设计方案,相反,我们将记录数据库的变化,而不是直接在原记录上进行更新。


例如,我们首先记录一个AddToCartevent当用户123第一次添加产品888到他的购物车,quantity为1.接下啦,我们分别记录了UpdateCartQuantity event当他更改quantity为3,接下来为2.最终是一个结账event.所有的这些动作都记录为独立的event,并且追加到database中。


当你按照这种方式结构化数据时,每次购物车的改变在数据库中都是不可变的event.即使事实上用户确实将quantity更改到了2,在上一时刻选择的quantity为3的事实也存在在数据库中。如果你复写了数据库,那么你将失去历史信息。


回到我们的streamprocessing 例子,Google Analytics.我们有两个选项(a) 原始 event ;(b)聚合概要指标。现在可以看到,event sourcing 同stream processing非常相似。你可以想象那些event sourced 命令(AddToCart、UpdateCartQuanity)为原始event:他们组成了随时间变化,都有那些事件发生了。但是,当你查看你的购物车类容时,你看到的是当前的状态。那就是,你得到的是将所有历史事件综合而成的最终状态。


深入思考下,你可以发现,原始事件将是一个理想的数据写入方式:你仅仅需要将event追加到一个日志的最后。这是最简单的也是最快写入数据到数据库的方式。

另一方面,聚合数据是从数据库读出数据最理想方式。如果一个用户查询他的购物车类容,她对导致当前状态的整个历史和修改信息并不关心。所以当我们读取数据是,最高效的方式是,这些历史数据已经聚合,用来表示当前的状态。

下接第二部分(part 2)










  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值